diff options
Diffstat (limited to 'crawl-ref/source')
148 files changed, 3880 insertions, 2380 deletions
diff --git a/crawl-ref/source/abl-show.cc b/crawl-ref/source/abl-show.cc index 73dc7b730c..ceb47a2064 100644 --- a/crawl-ref/source/abl-show.cc +++ b/crawl-ref/source/abl-show.cc @@ -37,7 +37,7 @@ #include "message.h" #include "menu.h" #include "misc.h" -#include "monplace.h" +#include "mon-place.h" #include "mutation.h" #include "notes.h" #include "ouch.h" @@ -1482,7 +1482,8 @@ static bool _do_ability(const ability_def& abil) break; case ABIL_RAISE_DEAD: - animate_dead(&you, you.experience_level * 5, BEH_FRIENDLY, MHITYOU); + animate_dead(&you, you.experience_level * 5, BEH_FRIENDLY, + MHITYOU, &you); break; case ABIL_CONTROL_DEMON: @@ -1609,7 +1610,7 @@ static bool _do_ability(const ability_def& abil) mpr("You attempt to give life to the dead..."); if (animate_remains(you.pos(), CORPSE_BODY, BEH_FRIENDLY, - MHITYOU, GOD_YREDELEMNUL) < 0) + MHITYOU, &you, "", GOD_YREDELEMNUL) < 0) { mpr("There are no remains here to animate!"); } @@ -1625,7 +1626,7 @@ static bool _do_ability(const ability_def& abil) mpr("You call on the dead to walk for you..."); animate_dead(&you, 1 + you.skills[SK_INVOCATIONS], BEH_FRIENDLY, - MHITYOU, GOD_YREDELEMNUL); + MHITYOU, &you, "", GOD_YREDELEMNUL); exercise(SK_INVOCATIONS, 2 + random2(4)); break; @@ -1928,12 +1929,15 @@ static bool _do_ability(const ability_def& abil) { int count = fungal_bloom(); - if (count) + if (!count) { - simple_god_message(" appreciates your contribution to the " - "ecosystem.", GOD_FEDHAS); + canned_msg(MSG_NOTHING_HAPPENS); + return (false); } + simple_god_message(" appreciates your contribution to the " + "ecosystem.", GOD_FEDHAS); + // We are following the blood god sacrifice piety gain model, given as: // if (random2(level + 10) > 5) // piety_change = 1; @@ -1993,9 +1997,11 @@ static bool _do_ability(const ability_def& abil) case ABIL_JIYVA_CALL_JELLY: { - mgen_data mg(MONS_JELLY, BEH_STRICT_NEUTRAL, 0, 0, you.pos(), + mgen_data mg(MONS_JELLY, BEH_STRICT_NEUTRAL, 0, 0, 0, you.pos(), MHITNOT, 0, GOD_JIYVA); + mg.non_actor_summoner = "Jiyva"; + if (create_monster(mg) == -1) return (false); diff --git a/crawl-ref/source/abyss.cc b/crawl-ref/source/abyss.cc index cf3f74267d..af78932c24 100644 --- a/crawl-ref/source/abyss.cc +++ b/crawl-ref/source/abyss.cc @@ -18,8 +18,9 @@ #include "mapmark.h" #include "message.h" #include "misc.h" +#include "mon-iter.h" #include "mon-util.h" -#include "monplace.h" +#include "mon-place.h" #include "mtransit.h" #include "player.h" #include "dungeon.h" @@ -181,6 +182,7 @@ static void _generate_area(const coord_def& topleft, // Nuke map. env.map_knowledge.init(map_cell()); + env.pgrid.init(0); // Generate level composition vector. for (int i = 0; i < 5; i++) @@ -319,6 +321,21 @@ static void _generate_area(const coord_def& topleft, mpr("Placing altar.", MSGCH_DIAGNOSTICS); #endif } + + if (one_chance_in(20000)) + { + // Not a vital thing, items shouldn't hurt. + grd(*ri) = DNGN_ENTER_PANDEMONIUM; +#ifdef DEBUG_ABYSS + mpr("Placing a Pan portal.", MSGCH_DIAGNOSTICS); +#endif + } + + if (one_chance_in(10000)) + { + // purely decorative + grd(*ri) = DNGN_STONE_ARCH; + } } } @@ -442,16 +459,11 @@ void area_shift(void) _xom_check_nearness_setup(); - for (unsigned int i = 0; i < MAX_MONSTERS; i++) + // Remove non-nearby monsters. + for (monster_iterator mi; mi; ++mi) { - monsters &m = menv[i]; - - if (!m.alive()) - continue; - - // Remove non-nearby monsters. - if (grid_distance(m.pos(), you.pos()) > 10) - _abyss_lose_monster(m); + if (grid_distance(mi->pos(), you.pos()) > 10) + _abyss_lose_monster(**mi); } for (rectangle_iterator ri(5); ri; ++ri) @@ -546,12 +558,9 @@ void area_shift(void) void save_abyss_uniques() { - for (int i = 0; i < MAX_MONSTERS; ++i) - { - monsters &m = menv[i]; - if (m.alive() && m.needs_transit()) - m.set_transit( level_id(LEVEL_ABYSS) ); - } + for (monster_iterator mi; mi; ++mi) + if (mi->needs_transit()) + mi->set_transit(level_id(LEVEL_ABYSS)); } void abyss_teleport( bool new_area ) @@ -602,9 +611,8 @@ void abyss_teleport( bool new_area ) tile_init_flavour(); #endif - for (int i = 0; i < MAX_MONSTERS; ++i) - if (menv[i].alive()) - _abyss_lose_monster(menv[i]); + for (monster_iterator mi; mi; ++mi) + _abyss_lose_monster(**mi); // Orbs and fixed artefacts are marked as "lost in the abyss". for (int i = 0; i < MAX_ITEMS; ++i) @@ -702,7 +710,10 @@ static bool _spawn_corrupted_servant_near(const coord_def &pos) const beh_type beh = one_chance_in(5 + you.skills[SK_INVOCATIONS] / 4) ? BEH_HOSTILE : BEH_NEUTRAL; - const int mid = create_monster(mgen_data(mons, beh, 5, 0, p)); + mgen_data mg(mons, beh, 0, 5, 0, p); + mg.non_actor_summoner = "Lugonu's corruption"; + + const int mid = create_monster(mg); return (mid != -1); } diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc index ff1a1ccd3b..fe11c6612f 100644 --- a/crawl-ref/source/acr.cc +++ b/crawl-ref/source/acr.cc @@ -89,8 +89,9 @@ #include "misc.h" #include "mon-act.h" #include "mon-cast.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-iter.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "mon-util.h" #include "mutation.h" #include "newgame.h" @@ -2503,7 +2504,7 @@ static void _decrement_durations() Options.tutorial_events[TUT_YOU_ENCHANTED] = tut_slow; } - if (you.duration[DUR_BACKLIGHT] && !--you.duration[DUR_BACKLIGHT] + if (you.duration[DUR_CORONA] && !--you.duration[DUR_CORONA] && !you.backlit()) { mpr("You are no longer glowing.", MSGCH_DURATION); @@ -3280,23 +3281,53 @@ static void _open_door(coord_def move, bool check_confused) const char *adj, *noun; get_door_description(all_door.size(), &adj, &noun); - int skill = you.dex - + (you.skills[SK_TRAPS_DOORS] + you.skills[SK_STEALTH]) / 2; - - if (is_exclude_root(doorpos) && !(check_confused && you.confused())) + if (!(check_confused && you.confused())) { - std::string prompt = - make_stringf("This %s%s is marked as excluded! Open it " - "anyway?", adj, noun); + std::string door_open_prompt = + env.markers.property_at(doorpos, MAT_ANY, "door_open_prompt"); + + bool ignore_exclude = false; - if (!yesno(prompt.c_str(), true, 'n', true, false)) + if (!door_open_prompt.empty()) { - canned_msg(MSG_OK); - interrupt_activity(AI_FORCE_INTERRUPT); - return; + door_open_prompt += " (y/N)"; + if (!yesno(door_open_prompt.c_str(), true, 'n', true, false)) + { + if (is_exclude_root(doorpos)) + canned_msg(MSG_OK); + else + { + if (yesno("Put travel exclusion on door? (Y/n)", + true, 'y')) + { + // Zero radius exclusion right on top of door. + set_exclude(doorpos, 0); + } + } + interrupt_activity(AI_FORCE_INTERRUPT); + return; + } + ignore_exclude = true; + } + + if (!ignore_exclude && is_exclude_root(doorpos)) + { + std::string prompt = + make_stringf("This %s%s is marked as excluded! Open it " + "anyway?", adj, noun); + + if (!yesno(prompt.c_str(), true, 'n', true, false)) + { + canned_msg(MSG_OK); + interrupt_activity(AI_FORCE_INTERRUPT); + return; + } } } + int skill = you.dex + + (you.skills[SK_TRAPS_DOORS] + you.skills[SK_STEALTH]) / 2; + if (you.berserk()) { // XXX: Better flavour for larger doors? @@ -3564,6 +3595,7 @@ static bool _initialise(void) igrd.init(NON_ITEM); mgrd.init(NON_MONSTER); env.map_knowledge.init(map_cell()); + env.pgrid.init(0); you.unique_creatures.init(false); you.unique_items.init(UNIQ_NOT_EXISTS); @@ -3734,8 +3766,9 @@ static bool _initialise(void) // Mark items in inventory as of unknown origin. origin_set_inventory(origin_set_unknown); - // For a new game, wipe out monsters in LOS. - zap_los_monsters(); + // For a new game, wipe out monsters in LOS, and + // for new tutorial games also the items. + zap_los_monsters(Options.tutorial_events[TUT_SEEN_FIRST_OBJECT]); // For a newly started tutorial, turn secret doors into normal ones. if (Options.tutorial_left) @@ -4025,9 +4058,8 @@ static void _move_player(coord_def move) mprf(MSGCH_DIAGNOSTICS, "Number of items present: %d", j); j = 0; - for (int i = 0; i < MAX_MONSTERS; ++i) - if (menv[i].type != -1) - ++j; + for (monster_iterator mi; mi; ++mi) + ++j; mprf(MSGCH_DIAGNOSTICS, "Number of monsters present: %d", j); mprf(MSGCH_DIAGNOSTICS, "Number of clouds present: %d", env.cloud_no); @@ -4380,7 +4412,7 @@ static void _compile_time_asserts() COMPILE_CHECK(SP_VAMPIRE == 30 , c3); COMPILE_CHECK(SPELL_DEBUGGING_RAY == 103 , c4); COMPILE_CHECK(SPELL_PETRIFY == 155 , c5); - COMPILE_CHECK(NUM_SPELLS == 206 , c6); + COMPILE_CHECK(NUM_SPELLS == 207 , c6); //jmf: NEW ASSERTS: we ought to do a *lot* of these COMPILE_CHECK(NUM_SPECIES < SP_UNKNOWN , c7); diff --git a/crawl-ref/source/actor-los.cc b/crawl-ref/source/actor-los.cc index 85e66fd8ab..06eb063a13 100644 --- a/crawl-ref/source/actor-los.cc +++ b/crawl-ref/source/actor-los.cc @@ -30,6 +30,11 @@ bool player::see_cell_no_trans(const coord_def &p) const return (los_no_trans.see_cell(p)); } +const los_def& actor::get_los() const +{ + return (los); +} + const los_def& actor::get_los_no_trans() { return (los_no_trans); diff --git a/crawl-ref/source/actor.h b/crawl-ref/source/actor.h index 97bae34914..10dd3f7bda 100644 --- a/crawl-ref/source/actor.h +++ b/crawl-ref/source/actor.h @@ -121,6 +121,7 @@ public: virtual void update_los(); + virtual const los_def& get_los() const; // Could be const for player, but monsters updates it on the fly. virtual const los_def& get_los_no_trans(); @@ -156,8 +157,8 @@ public: virtual void confuse(actor *attacker, int strength) = 0; virtual void expose_to_element(beam_type element, int strength = 0) = 0; virtual void drain_stat(int stat, int amount, actor* attacker) { } - virtual bool can_sleep(bool holi_only = false) const = 0; - virtual void put_to_sleep(int power = 0) = 0; + virtual bool can_hibernate(bool holi_only = false) const = 0; + virtual void hibernate(int power = 0) = 0; virtual void check_awaken(int disturbance) = 0; virtual bool wearing_light_armour(bool = false) const { return (true); } diff --git a/crawl-ref/source/arena.cc b/crawl-ref/source/arena.cc index dcae744e65..31512cd621 100644 --- a/crawl-ref/source/arena.cc +++ b/crawl-ref/source/arena.cc @@ -22,10 +22,11 @@ #include "maps.h" #include "message.h" #include "mon-behv.h" +#include "mon-iter.h" #include "mon-pick.h" #include "mon-util.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "spl-mis.h" #include "spl-util.h" #include "state.h" @@ -139,12 +140,8 @@ namespace arena void adjust_monsters() { - for (int i = 0; i < MAX_MONSTERS; i++) + for (monster_iterator mon; mon; ++mon) { - monsters *mon = &menv[i]; - if (!mon->alive()) - continue; - const bool friendly = mon->friendly(); // Set target to the opposite faction's home base. mon->target = friendly ? place_b : place_a; @@ -543,16 +540,12 @@ namespace arena faction_a.active_members = 0; faction_b.active_members = 0; - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mons; mons; ++mons) { - const monsters *mons(&menv[i]); - if (mons->alive()) - { - if (mons->attitude == ATT_FRIENDLY) - faction_a.active_members++; - else if (mons->attitude == ATT_HOSTILE) - faction_b.active_members++; - } + if (mons->attitude == ATT_FRIENDLY) + faction_a.active_members++; + else if (mons->attitude == ATT_HOSTILE) + faction_b.active_members++; } if (orig_a != faction_a.active_members @@ -601,35 +594,27 @@ namespace arena void report_foes() { - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mons; mons; ++mons) { - monsters *mons(&menv[i]); - if (mons->alive()) + if (mons->type == MONS_SIGMUND) { - if (mons->type == MONS_SIGMUND) - { - coord_def where; - if (mons->get_foe()) - where = mons->get_foe()->pos(); - mprf("%s (%d,%d) foe: %s (%d,%d)", - mons->name(DESC_PLAIN).c_str(), - mons->pos().x, mons->pos().y, - mons->get_foe()? mons->get_foe()->name(DESC_PLAIN).c_str() - : "(none)", - where.x, where.y); - } + coord_def where; + if (mons->get_foe()) + where = mons->get_foe()->pos(); + mprf("%s (%d,%d) foe: %s (%d,%d)", + mons->name(DESC_PLAIN).c_str(), + mons->pos().x, mons->pos().y, + mons->get_foe()? mons->get_foe()->name(DESC_PLAIN).c_str() + : "(none)", + where.x, where.y); } } } void fixup_foes() { - for (int i = 0; i < MAX_MONSTERS; ++i) - { - monsters *mons(&menv[i]); - if (mons->alive()) - behaviour_event(mons, ME_DISTURB, MHITNOT, mons->pos()); - } + for (monster_iterator mons; mons; ++mons) + behaviour_event(*mons, ME_DISTURB, MHITNOT, mons->pos()); } void dump_messages() @@ -718,15 +703,13 @@ namespace arena if (!miscasts) return; - for (int i = 0; i < MAX_MONSTERS; i++) + for (monster_iterator mon; mon; ++mon) { - monsters* mon = &menv[i]; - - if (!mon->alive() || mon->type == MONS_TEST_SPAWNER) + if (mon->type == MONS_TEST_SPAWNER) continue; - MiscastEffect(mon, i, SPTYP_RANDOM, random_range(1, 3), - "arena miscast", NH_NEVER); + MiscastEffect(*mon, mon->mindex(), SPTYP_RANDOM, + random_range(1, 3), "arena miscast", NH_NEVER); } } diff --git a/crawl-ref/source/art-data.h b/crawl-ref/source/art-data.h index abf00dfaee..0fa2709a17 100644 --- a/crawl-ref/source/art-data.h +++ b/crawl-ref/source/art-data.h @@ -23,7 +23,7 @@ #define ART_DATA_H -/* 1: UNRAND_DUMMY1 */ +/* UNRAND_DUMMY1 */ { "DUMMY UNRANDART 1", "DUMMY UNRANDART 1", OBJ_UNASSIGNED, 250, 250, 250, BLACK, 0, @@ -42,7 +42,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 2: UNRAND_SINGING_SWORD */ +/* UNRAND_SINGING_SWORD */ { "Singing Sword", "golden long sword", OBJ_WEAPONS, WPN_LONG_SWORD, +7, +7, ETC_GOLD, 1200, @@ -61,7 +61,7 @@ _SINGING_SWORD_equip, _SINGING_SWORD_unequip, NULL, { NULL }, NULL, }, -/* 3: UNRAND_TROG */ +/* UNRAND_TROG */ { "Wrath of Trog", "bloodstained battleaxe", OBJ_WEAPONS, WPN_BATTLEAXE, +3, +11, ETC_BLOOD, 1000, @@ -80,7 +80,7 @@ _TROG_equip, _TROG_unequip, NULL, { _TROG_melee_effect }, NULL, }, -/* 4: UNRAND_VARIABILITY */ +/* UNRAND_VARIABILITY */ { "Mace of Variability", "shimmering mace", OBJ_WEAPONS, WPN_MACE, 0, 0, ETC_RANDOM, 700, @@ -99,7 +99,7 @@ NULL, NULL, _VARIABILITY_world_reacts, { NULL }, NULL, }, -/* 5: UNRAND_PRUNE */ +/* UNRAND_PRUNE */ { "Glaive of Prune", "purple glaive", OBJ_WEAPONS, WPN_GLAIVE, 0, +12, MAGENTA, 1000, @@ -118,7 +118,7 @@ _PRUNE_equip, NULL, NULL, { NULL }, NULL, }, -/* 6: UNRAND_POWER */ +/* UNRAND_POWER */ { "Sword of Power", "chunky great sword", OBJ_WEAPONS, WPN_GREAT_SWORD, 0, 0, RED, 1000, @@ -137,7 +137,7 @@ _POWER_equip, NULL, _POWER_world_reacts, { NULL }, NULL, }, -/* 7: UNRAND_OLGREB */ +/* UNRAND_OLGREB */ { "Staff of Olgreb", "green glowing staff", OBJ_WEAPONS, WPN_QUARTERSTAFF, 0, 0, ETC_POISON, 1000, @@ -156,7 +156,7 @@ _OLGREB_equip, _OLGREB_unequip, _OLGREB_world_reacts, { NULL }, _OLGREB_evoke, }, -/* 8: UNRAND_WUCAD_MU */ +/* UNRAND_WUCAD_MU */ { "Staff of Wucad Mu", "ephemeral quarterstaff", OBJ_WEAPONS, WPN_QUARTERSTAFF, 0, 0, ETC_MAGIC, 1000, @@ -175,7 +175,7 @@ _WUCAD_MU_equip, _WUCAD_MU_unequip, _WUCAD_MU_world_reacts, { _WUCAD_MU_melee_effect }, _WUCAD_MU_evoke, }, -/* 9: UNRAND_VAMPIRES_TOOTH */ +/* UNRAND_VAMPIRES_TOOTH */ { "Vampire's Tooth", "ivory dagger", OBJ_WEAPONS, WPN_DAGGER, +3, +4, ETC_BONE, 1000, @@ -194,7 +194,7 @@ _VAMPIRES_TOOTH_equip, NULL, NULL, { NULL }, NULL, }, -/* 10: UNRAND_CURSES */ +/* UNRAND_CURSES */ { "Scythe of Curses", "warped scythe", OBJ_WEAPONS, WPN_SCYTHE, +13, +13, ETC_NECRO, 800, @@ -213,7 +213,7 @@ _CURSES_equip, NULL, _CURSES_world_reacts, { _CURSES_melee_effect }, NULL, }, -/* 11: UNRAND_TORMENT */ +/* UNRAND_TORMENT */ { "Sceptre of Torment", "jewelled golden mace", OBJ_WEAPONS, WPN_MACE, +7, +6, ETC_GOLD, 1200, @@ -232,7 +232,7 @@ _TORMENT_equip, NULL, _TORMENT_world_reacts, { _TORMENT_melee_effect }, NULL, }, -/* 12: UNRAND_ZONGULDROK */ +/* UNRAND_ZONGULDROK */ { "Sword of Zonguldrok", "bone long sword", OBJ_WEAPONS, WPN_LONG_SWORD, +9, +9, ETC_BONE, 1250, @@ -251,11 +251,11 @@ _ZONGULDROK_equip, NULL, _ZONGULDROK_world_reacts, { _ZONGULDROK_melee_effect }, NULL, }, -/* 13: UNRAND_CEREBOV */ +/* UNRAND_CEREBOV */ { "Sword of Cerebov", "great serpentine sword", OBJ_WEAPONS, WPN_GREAT_SWORD, +6, +6, ETC_FIRE, 2000, - UNRAND_FLAG_SPECIAL | UNRAND_FLAG_UNHOLY, + UNRAND_FLAG_SPECIAL | UNRAND_FLAG_EVIL, { SPWPN_FLAMING, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -270,11 +270,11 @@ NULL, NULL, NULL, { _CEREBOV_melee_effect }, NULL, }, -/* 14: UNRAND_DISPATER */ +/* UNRAND_DISPATER */ { "Staff of Dispater", "golden staff", OBJ_WEAPONS, WPN_QUARTERSTAFF, +4, +4, ETC_GOLD, 1200, - UNRAND_FLAG_SPECIAL | UNRAND_FLAG_UNHOLY, + UNRAND_FLAG_SPECIAL | UNRAND_FLAG_EVIL, { SPWPN_NORMAL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -289,7 +289,7 @@ NULL, NULL, NULL, { _DISPATER_melee_effect }, _DISPATER_evoke, }, -/* 15: UNRAND_ASMODEUS */ +/* UNRAND_ASMODEUS */ { "Sceptre of Asmodeus", "ruby sceptre", OBJ_WEAPONS, WPN_QUARTERSTAFF, +7, +7, ETC_BLOOD, 1500, @@ -308,7 +308,7 @@ NULL, NULL, NULL, { _ASMODEUS_melee_effect }, _ASMODEUS_evoke, }, -/* 16: UNRAND_BLOODBANE */ +/* UNRAND_BLOODBANE */ { "long sword \"Bloodbane\"", "blackened long sword", OBJ_WEAPONS, WPN_LONG_SWORD, +7, +8, ETC_DARK, 0, @@ -327,7 +327,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 17: UNRAND_FLAMING_DEATH */ +/* UNRAND_FLAMING_DEATH */ { "scimitar of Flaming Death", "smoking scimitar", OBJ_WEAPONS, WPN_SCIMITAR, +7, +5, ETC_FIRE, 0, @@ -346,7 +346,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 18: UNRAND_BRILLIANCE */ +/* UNRAND_BRILLIANCE */ { "mace of Brilliance", "brightly glowing mace", OBJ_WEAPONS, WPN_MACE, +5, +5, ETC_HOLY, 0, @@ -365,7 +365,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 19: UNRAND_LEECH */ +/* UNRAND_LEECH */ { "demon blade \"Leech\"", "runed demon blade", OBJ_WEAPONS, WPN_DEMON_BLADE, +13, +4, MAGENTA, 0, @@ -384,7 +384,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 20: UNRAND_CHILLY_DEATH */ +/* UNRAND_CHILLY_DEATH */ { "dagger of Chilly Death", "sapphire dagger", OBJ_WEAPONS, WPN_DAGGER, +5, +7, ETC_ICE, 0, @@ -403,7 +403,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 21: UNRAND_MORG */ +/* UNRAND_MORG */ { "dagger \"Morg\"", "rusty dagger", OBJ_WEAPONS, WPN_DAGGER, -1, +4, LIGHTRED, 0, @@ -422,7 +422,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 22: UNRAND_FINISHER */ +/* UNRAND_FINISHER */ { "scythe \"Finisher\"", "blackened scythe", OBJ_WEAPONS, WPN_SCYTHE, +3, +5, ETC_DARK, 0, @@ -441,7 +441,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 23: UNRAND_PUNK */ +/* UNRAND_PUNK */ { "sling \"Punk\"", "blue sling", OBJ_WEAPONS, WPN_SLING, +9, +12, ETC_ICE, 0, @@ -460,7 +460,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 24: UNRAND_KRISHNA */ +/* UNRAND_KRISHNA */ { "bow of Krishna \"Sharnga\"", "golden bow", OBJ_WEAPONS, WPN_BOW, +8, +8, ETC_GOLD, 0, @@ -479,7 +479,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 25: UNRAND_SKULLCRUSHER */ +/* UNRAND_SKULLCRUSHER */ { "giant club \"Skullcrusher\"", "brutal giant club", OBJ_WEAPONS, WPN_GIANT_CLUB, +0, +5, BROWN, 0, @@ -498,7 +498,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 26: UNRAND_GUARD */ +/* UNRAND_GUARD */ { "glaive of the Guard", "polished glaive", OBJ_WEAPONS, WPN_GLAIVE, +5, +8, ETC_ELECTRICITY, 0, @@ -517,7 +517,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 27: UNRAND_JIHAD */ +/* UNRAND_JIHAD */ { "sword of Jihad", "crystal sword", OBJ_WEAPONS, WPN_LONG_SWORD, +12, +10, ETC_HOLY, 0, @@ -536,7 +536,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 28: UNRAND_HELLFIRE */ +/* UNRAND_HELLFIRE */ { "crossbow \"Hellfire\"", "flaming crossbow", OBJ_WEAPONS, WPN_CROSSBOW, +6, +9, ETC_FIRE, 0, @@ -555,7 +555,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 29: UNRAND_DOOM_KNIGHT */ +/* UNRAND_DOOM_KNIGHT */ { "sword of the Doom Knight", "adamantine great sword", OBJ_WEAPONS, WPN_GREAT_SWORD, +13, +13, BLUE, 0, @@ -574,7 +574,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 30: UNRAND_EOS */ +/* UNRAND_EOS */ { "\"Eos\"", "encrusted morningstar", OBJ_WEAPONS, WPN_MORNINGSTAR, +5, +5, ETC_JEWEL, 0, @@ -593,7 +593,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 31: UNRAND_BOTONO */ +/* UNRAND_BOTONO */ { "spear of the Botono", "ebony spear", OBJ_WEAPONS, WPN_SPEAR, +2, +10, ETC_UNHOLY, 0, @@ -612,7 +612,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 32: UNRAND_OCTOPUS_KING */ +/* UNRAND_OCTOPUS_KING */ { "trident of the Octopus King", "mangy trident", OBJ_WEAPONS, WPN_TRIDENT, +10, +4, ETC_WATER, 0, @@ -631,7 +631,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 33: UNRAND_ARGA */ +/* UNRAND_ARGA */ { "mithril axe \"Arga\"", "mithril axe", OBJ_WEAPONS, WPN_WAR_AXE, +10, +6, WHITE, 0, @@ -650,7 +650,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 34: UNRAND_ELEMENTAL_STAFF */ +/* UNRAND_ELEMENTAL_STAFF */ { "Elemental Staff", "black staff", OBJ_WEAPONS, WPN_QUARTERSTAFF, +3, +1, DARKGREY, 0, @@ -669,7 +669,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 35: UNRAND_SNIPER */ +/* UNRAND_SNIPER */ { "hand crossbow \"Sniper\"", "black crossbow", OBJ_WEAPONS, WPN_HAND_CROSSBOW, +10, +0, ETC_DARK, 0, @@ -688,7 +688,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 36: UNRAND_PIERCER */ +/* UNRAND_PIERCER */ { "longbow \"Piercer\"", "very long metal bow", OBJ_WEAPONS, WPN_LONGBOW, +2, +10, CYAN, 0, @@ -707,7 +707,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 37: UNRAND_BLOWGUN_ASSASSIN */ +/* UNRAND_BLOWGUN_ASSASSIN */ { "blowgun of the Assassin", "tiny blowgun", OBJ_WEAPONS, WPN_BLOWGUN, +6, +6, WHITE, 0, @@ -726,7 +726,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 38: UNRAND_WYRMBANE */ +/* UNRAND_WYRMBANE */ { "Wyrmbane", "scale-covered lance", OBJ_WEAPONS, WPN_SPEAR, +9, +6, LIGHTGREEN, 0, @@ -745,7 +745,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 39: UNRAND_SPRIGGANS_KNIFE */ +/* UNRAND_SPRIGGANS_KNIFE */ { "Spriggan's Knife", "dainty little knife", OBJ_WEAPONS, WPN_KNIFE, +4, +10, LIGHTCYAN, 0, @@ -764,7 +764,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 40: UNRAND_PLUTONIUM_SWORD */ +/* UNRAND_PLUTONIUM_SWORD */ { "plutonium sword", "glowing long sword", OBJ_WEAPONS, WPN_LONG_SWORD, +12, +16, ETC_RANDOM, 0, @@ -783,7 +783,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 41: UNRAND_UNDEADHUNTER */ +/* UNRAND_UNDEADHUNTER */ { "great mace \"Undeadhunter\"", "great steel mace", OBJ_WEAPONS, WPN_GREAT_MACE, +7, +7, LIGHTGREY, 0, @@ -802,7 +802,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 42: UNRAND_SERPENT_SCOURGE */ +/* UNRAND_SERPENT_SCOURGE */ { "whip \"Serpent-Scourge\"", "forked whip", OBJ_WEAPONS, WPN_WHIP, +5, +10, DARKGREY, 0, @@ -821,7 +821,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 43: UNRAND_ACCURACY */ +/* UNRAND_ACCURACY */ { "knife of Accuracy", "thin dagger", OBJ_WEAPONS, WPN_DAGGER, +27, -1, LIGHTCYAN, 0, @@ -840,7 +840,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 44: UNRAND_CRYSTAL_SPEAR */ +/* UNRAND_CRYSTAL_SPEAR */ { "Lehudib's crystal spear", "crystal spear", OBJ_WEAPONS, WPN_SPEAR, +6, +6, GREEN, 0, @@ -859,7 +859,45 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 45: UNRAND_IGNORANCE */ +/* UNRAND_CAPTAINS_CUTLASS */ +{ + "captain's cutlass", "black cutlass", + OBJ_WEAPONS, WPN_SABRE, +6, +7, DARKGRAY, 0, + UNRAND_FLAG_NONE, + { + SPWPN_SPEED, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 0, + }, + "", + "", + "This infamous weapon was used by a vile pirate captain to slaughter countless innocents. Finally, he met his destiny when a kraken swallowed his ship with all the crew aboard. The cutlass was thought to be forever lost, but now you have a proof to the contrary in your very hands.", + NULL, NULL, NULL, { NULL }, NULL, +}, + +/* UNRAND_STORM_BOW */ +{ + "storm bow", "night blue bow", + OBJ_WEAPONS, WPN_LONGBOW, +8, +8, BLUE, 0, + UNRAND_FLAG_SPECIAL, + { + SPWPN_ELECTROCUTION, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, + }, + "This bow has the color of dark rain clouds, and the smell of wet ozone.", + "", + "", + NULL, NULL, _STORM_BOW_world_reacts, { NULL }, NULL, +}, + +/* UNRAND_IGNORANCE */ { "shield of Ignorance", "dull large shield", OBJ_ARMOUR, ARM_LARGE_SHIELD, +8, 0, BROWN, 0, @@ -878,7 +916,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 46: UNRAND_AUGMENTATION */ +/* UNRAND_AUGMENTATION */ { "robe of Augmentation", "silk robe", OBJ_ARMOUR, ARM_ROBE, +4, 0, LIGHTRED, 0, @@ -897,7 +935,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 47: UNRAND_THIEF */ +/* UNRAND_THIEF */ { "cloak of the Thief", "tattered cloak", OBJ_ARMOUR, ARM_CLOAK, +1, 0, ETC_DARK, 0, @@ -916,7 +954,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 48: UNRAND_BULLSEYE */ +/* UNRAND_BULLSEYE */ { "shield \"Bullseye\"", "round shield", OBJ_ARMOUR, ARM_SHIELD, +15, 0, RED, 0, @@ -935,7 +973,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 49: UNRAND_DYROVEPREVA */ +/* UNRAND_DYROVEPREVA */ { "crown of Dyrovepreva", "jewelled bronze crown", OBJ_ARMOUR, ARM_CAP, +3, 0, ETC_JEWEL, 0, @@ -954,7 +992,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 50: UNRAND_BEAR_SPIRIT */ +/* UNRAND_BEAR_SPIRIT */ { "hat of the Bear Spirit", "fur hat", OBJ_ARMOUR, ARM_CAP, +2, 0, DARKGREY, 0, @@ -973,7 +1011,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 51: UNRAND_MISFORTUNE */ +/* UNRAND_MISFORTUNE */ { "robe of Misfortune", "fabulously ornate robe", OBJ_ARMOUR, ARM_ROBE, -5, 0, MAGENTA, 0, @@ -992,7 +1030,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 52: UNRAND_FLASH */ +/* UNRAND_FLASH */ { "cloak of Flash", "vibrating cloak", OBJ_ARMOUR, ARM_CLOAK, +3, 0, ETC_GILA, 0, @@ -1011,7 +1049,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 53: UNRAND_BOOTS_ASSASSIN */ +/* UNRAND_BOOTS_ASSASSIN */ { "boots of the Assassin", "soft boots", OBJ_ARMOUR, ARM_BOOTS, +2, 0, BROWN, 0, @@ -1030,7 +1068,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 54: UNRAND_LEAR */ +/* UNRAND_LEAR */ { "Lear's chain mail", "golden chain mail", OBJ_ARMOUR, ARM_CHAIN_MAIL, -1, 0, ETC_GOLD, 0, @@ -1049,7 +1087,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 55: UNRAND_ZHOR */ +/* UNRAND_ZHOR */ { "skin of Zhor", "smelly skin", OBJ_ARMOUR, ARM_ANIMAL_SKIN, +4, 0, BROWN, 0, @@ -1068,7 +1106,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 56: UNRAND_SALAMANDER */ +/* UNRAND_SALAMANDER */ { "salamander hide armour", "red leather armour", OBJ_ARMOUR, ARM_LEATHER_ARMOUR, +3, 0, ETC_FIRE, 0, @@ -1087,7 +1125,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 57: UNRAND_WAR */ +/* UNRAND_WAR */ { "gauntlets of War", "thick gauntlets", OBJ_ARMOUR, ARM_GLOVES, +3, 0, BROWN, 0, @@ -1106,7 +1144,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 58: UNRAND_RESISTANCE */ +/* UNRAND_RESISTANCE */ { "shield of Resistance", "bronze shield", OBJ_ARMOUR, ARM_SHIELD, +5, 0, LIGHTRED, 0, @@ -1125,7 +1163,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 59: UNRAND_FOLLY */ +/* UNRAND_FOLLY */ { "robe of Folly", "dull robe", OBJ_ARMOUR, ARM_ROBE, -1, 0, LIGHTGREY, 0, @@ -1144,7 +1182,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 60: UNRAND_MAXWELL */ +/* UNRAND_MAXWELL */ { "Maxwell's patent armour", "weird-looking armour", OBJ_ARMOUR, ARM_PLATE_MAIL, +10, 0, LIGHTGREEN, 0, @@ -1163,7 +1201,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 61: UNRAND_DRAGONMASK */ +/* UNRAND_DRAGONMASK */ { "mask of the Dragon", "blue mask", OBJ_ARMOUR, ARM_CAP, 0, 0, ETC_SHIMMER_BLUE, 0, @@ -1182,7 +1220,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 62: UNRAND_NIGHT */ +/* UNRAND_NIGHT */ { "robe of Night", "black robe", OBJ_ARMOUR, ARM_ROBE, +4, 0, ETC_DARK, 0, @@ -1201,7 +1239,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 63: UNRAND_DRAGON_KING */ +/* UNRAND_DRAGON_KING */ { "armour of the Dragon King", "shiny dragon armour", OBJ_ARMOUR, ARM_GOLD_DRAGON_ARMOUR, +5, 0, ETC_GOLD, 0, @@ -1220,7 +1258,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 64: UNRAND_ALCHEMIST */ +/* UNRAND_ALCHEMIST */ { "hat of the Alchemist", "dirty hat", OBJ_ARMOUR, ARM_WIZARD_HAT, +2, 0, MAGENTA, 0, @@ -1239,7 +1277,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 65: UNRAND_FENCERS_GLOVES */ +/* UNRAND_FENCERS_GLOVES */ { "Fencer's gloves", "silk gloves", OBJ_ARMOUR, ARM_GLOVES, +2, 0, WHITE, 0, @@ -1258,7 +1296,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 66: UNRAND_STARLIGHT */ +/* UNRAND_STARLIGHT */ { "cloak of Starlight", "phosphorescent cloak", OBJ_ARMOUR, ARM_CLOAK, 0, 0, ETC_ICE, 0, @@ -1277,7 +1315,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 67: UNRAND_RATSKIN_CLOAK */ +/* UNRAND_RATSKIN_CLOAK */ { "ratskin cloak", "motley cloak", OBJ_ARMOUR, ARM_CLOAK, +1, 0, ETC_BEOGH, 0, @@ -1296,7 +1334,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 68: UNRAND_AIR */ +/* UNRAND_AIR */ { "amulet of the Air", "sky-blue amulet", OBJ_JEWELLERY, AMU_CONTROLLED_FLIGHT, 0, 0, ETC_ELECTRICITY, 0, @@ -1315,7 +1353,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 69: UNRAND_SHADOWS */ +/* UNRAND_SHADOWS */ { "ring of Shadows", "black ring", OBJ_JEWELLERY, RING_INVISIBILITY, 0, 0, ETC_DARK, 0, @@ -1334,7 +1372,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 70: UNRAND_CEKUGOB */ +/* UNRAND_CEKUGOB */ { "amulet of Cekugob", "crystal amulet", OBJ_JEWELLERY, AMU_WARDING, 0, 0, LIGHTGREY, 0, @@ -1353,7 +1391,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 71: UNRAND_FOUR_WINDS */ +/* UNRAND_FOUR_WINDS */ { "amulet of the Four Winds", "jade amulet", OBJ_JEWELLERY, AMU_CLARITY, 0, 0, ETC_POISON, 0, @@ -1372,7 +1410,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 72: UNRAND_BLOODLUST */ +/* UNRAND_BLOODLUST */ { "necklace of Bloodlust", "blood-stained necklace", OBJ_JEWELLERY, AMU_RAGE, 0, 0, ETC_BLOOD, 0, @@ -1391,7 +1429,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 73: UNRAND_SHAOLIN */ +/* UNRAND_SHAOLIN */ { "ring of Shaolin", "jade ring", OBJ_JEWELLERY, RING_EVASION, +8, 0, ETC_POISON, 0, @@ -1410,7 +1448,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 74: UNRAND_ROBUSTNESS */ +/* UNRAND_ROBUSTNESS */ { "ring of Robustness", "steel ring", OBJ_JEWELLERY, RING_PROTECTION, +8, 0, LIGHTGREY, 0, @@ -1429,7 +1467,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 75: UNRAND_MAGE */ +/* UNRAND_MAGE */ { "ring of the Mage", "sapphire ring", OBJ_JEWELLERY, RING_WIZARDRY, 0, 0, ETC_ENCHANT, 0, @@ -1448,7 +1486,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 76: UNRAND_SHIELDING */ +/* UNRAND_SHIELDING */ { "brooch of Shielding", "shield-shaped amulet", OBJ_JEWELLERY, AMU_WARDING, 0, 0, ETC_MAGIC, 0, @@ -1467,7 +1505,7 @@ NULL, NULL, NULL, { NULL }, NULL, }, -/* 77: UNRAND_DUMMY2 */ +/* UNRAND_DUMMY2 */ { "DUMMY UNRANDART 2", "DUMMY UNRANDART 2", OBJ_UNASSIGNED, 250, 250, 250, BLACK, 0, diff --git a/crawl-ref/source/art-data.txt b/crawl-ref/source/art-data.txt index 95b381db10..9b3b1a889a 100644 --- a/crawl-ref/source/art-data.txt +++ b/crawl-ref/source/art-data.txt @@ -705,6 +705,32 @@ TILE_EQ: crystal_spear INT: 3 DESC_END: Presumably this relic led to the invention of the famous spell, or maybe the other way around. +NAME: captain's cutlass +APPEAR: black cutlass +OBJ: OBJ_WEAPONS/WPN_SABRE +PLUS: +6/+7 +COLOUR: DARKGRAY +TILE: urand_cutlass +TILE_EQ: cutlass +BRAND: SPWPN_SPEED +DAM: 3 +DESC_END: This infamous weapon was used by a vile pirate captain to + slaughter countless innocents. Finally, he met his destiny + when a kraken swallowed his ship with all the crew aboard. + The cutlass was thought to be forever lost, but now you have + a proof to the contrary in your very hands. + +NAME: storm bow +APPEAR: night blue bow +OBJ: OBJ_WEAPONS/WPN_LONGBOW +PLUS: +8/+8 +COLOUR: BLUE +TILE: urand_storm_bow +TILE_EQ: bow_blue +BRAND: SPWPN_ELECTROCUTION +BOOL: special +DESC: This bow has the color of dark rain clouds, and the smell of wet ozone. + NAME: shield of Ignorance APPEAR: dull large shield OBJ: OBJ_ARMOUR/ARM_LARGE_SHIELD diff --git a/crawl-ref/source/art-func.h b/crawl-ref/source/art-func.h index f4c076e478..b460304502 100644 --- a/crawl-ref/source/art-func.h +++ b/crawl-ref/source/art-func.h @@ -21,10 +21,11 @@ #define ART_FUNC_H +#include "cloud.h" // For storm's bow rain #include "effects.h" // For Sceptre of Torment tormenting #include "food.h" // For evokes -#include "monplace.h" // For Sceptre of Asmodeus evoke -#include "monstuff.h" // For Scythe of Curses cursing items +#include "mon-place.h" // For Sceptre of Asmodeus evoke +#include "mon-stuff.h" // For Scythe of Curses cursing items #include "spells3.h" // For Zonguldrok animating dead #include "spl-cast.h" // For evokes #include "spl-mis.h" // For Staff of Wucad Mu miscasts @@ -73,6 +74,7 @@ static bool _evoke_sceptre_of_asmodeus() summon_any_demon(DEMON_COMMON)); const bool good_summon = create_monster( mgen_data::hostile_at(mon, + "the Sceptre of Asmodeus", true, 6, 0, you.pos())) != -1; if (good_summon) @@ -461,7 +463,8 @@ static void _ZONGULDROK_world_reacts(item_def *item) { if (one_chance_in(5)) { - animate_dead(&you, 1 + random2(3), BEH_HOSTILE, MHITYOU); + animate_dead(&you, 1 + random2(3), BEH_HOSTILE, MHITYOU, 0, + "the Sword of Zonguldrok"); did_god_conduct(DID_NECROMANCY, 1); } } @@ -477,3 +480,14 @@ static void _ZONGULDROK_melee_effect(item_def* weapon, actor* attacker, /////////////////////////////////////////////////// +static void _STORM_BOW_world_reacts(item_def *item) +{ + if (!one_chance_in(300)) + return; + + for (radius_iterator ri(you.pos(), 2); ri; ++ri) + if (!cell_is_solid(*ri) && env.cgrid(*ri) == EMPTY_CLOUD && one_chance_in(5)) + place_cloud( CLOUD_RAIN, *ri, random2(20), KC_OTHER, 3); +} + +/////////////////////////////////////////////////// diff --git a/crawl-ref/source/artefact.cc b/crawl-ref/source/artefact.cc index fb2687526a..0ac8f3ac0c 100644 --- a/crawl-ref/source/artefact.cc +++ b/crawl-ref/source/artefact.cc @@ -769,6 +769,12 @@ void static _get_randart_properties(const item_def &item, { proprt[ARTP_BRAND] = SPWPN_NORMAL; } + + if (atype == WPN_CROSSBOW && one_chance_in(5) + || atype == WPN_HAND_CROSSBOW && one_chance_in(10)) + { + proprt[ARTP_BRAND] = SPWPN_ELECTROCUTION; + } } } diff --git a/crawl-ref/source/artefact.h b/crawl-ref/source/artefact.h index 9b19c03a06..5375c2f03e 100644 --- a/crawl-ref/source/artefact.h +++ b/crawl-ref/source/artefact.h @@ -13,7 +13,7 @@ class bolt; // NOTE: NO_UNRANDARTS is automatically set by util/art-data.pl -#define NO_UNRANDARTS 77 +#define NO_UNRANDARTS 79 #define ART_PROPERTIES ARTP_NUM_PROPERTIES @@ -81,6 +81,8 @@ enum unrand_type UNRAND_SERPENT_SCOURGE, // whip "Serpent-Scourge" UNRAND_ACCURACY, // knife of Accuracy UNRAND_CRYSTAL_SPEAR, // Lehudib's crystal spear + UNRAND_CAPTAINS_CUTLASS, // captain's cutlass + UNRAND_STORM_BOW, // storm bow UNRAND_IGNORANCE, // shield of Ignorance UNRAND_AUGMENTATION, // robe of Augmentation UNRAND_THIEF, // cloak of the Thief diff --git a/crawl-ref/source/attitude-change.cc b/crawl-ref/source/attitude-change.cc index 509525fb65..0cb8d91949 100644 --- a/crawl-ref/source/attitude-change.cc +++ b/crawl-ref/source/attitude-change.cc @@ -16,9 +16,10 @@ #include "goditem.h" #include "message.h" #include "mon-behv.h" +#include "mon-iter.h" #include "mon-util.h" #include "monster.h" -#include "monstuff.h" +#include "mon-stuff.h" #include "player.h" #include "random.h" #include "religion.h" @@ -145,44 +146,42 @@ static bool _holy_beings_on_level_attitude_change() { bool success = false; - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi; mi; ++mi) { - monsters *monster = &menv[i]; - if (monster->alive() - && monster->is_holy()) - { + if (!mi->is_holy()) + continue; + #ifdef DEBUG_DIAGNOSTICS - mprf(MSGCH_DIAGNOSTICS, "Holy attitude changing: %s on level %d, branch %d", - monster->name(DESC_PLAIN).c_str(), - static_cast<int>(you.your_level), - static_cast<int>(you.where_are_you)); + mprf(MSGCH_DIAGNOSTICS, "Holy attitude changing: %s on level %d, branch %d", + mi->name(DESC_PLAIN).c_str(), + static_cast<int>(you.your_level), + static_cast<int>(you.where_are_you)); #endif - // If you worship a good god, you get another chance to make - // neutral and hostile holy beings good neutral. - if (is_good_god(you.religion) && !monster->wont_attack()) - { - if (testbits(monster->flags, MF_ATT_CHANGE_ATTEMPT)) - { - monster->flags &= ~MF_ATT_CHANGE_ATTEMPT; - - success = true; - } - } - // If you don't worship a good god, you make all friendly - // and good neutral holy beings that worship a good god - // hostile. - else if (!is_good_god(you.religion) && monster->wont_attack() - && is_good_god(monster->god)) + // If you worship a good god, you get another chance to make + // neutral and hostile holy beings good neutral. + if (is_good_god(you.religion) && !mi->wont_attack()) + { + if (testbits(mi->flags, MF_ATT_CHANGE_ATTEMPT)) { - monster->attitude = ATT_HOSTILE; - monster->del_ench(ENCH_CHARM, true); - behaviour_event(monster, ME_ALERT, MHITYOU); - // For now CREATED_FRIENDLY/WAS_NEUTRAL stays. + mi->flags &= ~MF_ATT_CHANGE_ATTEMPT; success = true; } } + // If you don't worship a good god, you make all friendly + // and good neutral holy beings that worship a good god + // hostile. + else if (!is_good_god(you.religion) && mi->wont_attack() + && is_good_god(mi->god)) + { + mi->attitude = ATT_HOSTILE; + mi->del_ench(ENCH_CHARM, true); + behaviour_event(*mi, ME_ALERT, MHITYOU); + // For now CREATED_FRIENDLY/WAS_NEUTRAL stays. + + success = true; + } } return (success); @@ -197,32 +196,29 @@ static bool _unholy_and_evil_beings_on_level_attitude_change() { bool success = false; - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi; mi; ++mi) { - monsters *monster = &menv[i]; - if (monster->alive() - && (monster->is_unholy() - || monster->is_evil())) - { + if (!mi->is_unholy() && !mi->is_evil()) + continue; + #ifdef DEBUG_DIAGNOSTICS - mprf(MSGCH_DIAGNOSTICS, "Unholy/evil attitude changing: %s " - "on level %d, branch %d", - monster->name(DESC_PLAIN, true).c_str(), - static_cast<int>(you.your_level), - static_cast<int>(you.where_are_you)); + mprf(MSGCH_DIAGNOSTICS, "Unholy/evil attitude changing: %s " + "on level %d, branch %d", + mi->name(DESC_PLAIN, true).c_str(), + static_cast<int>(you.your_level), + static_cast<int>(you.where_are_you)); #endif - // If you worship a good god, you make all friendly and good - // neutral unholy and evil beings hostile. - if (is_good_god(you.religion) && monster->wont_attack()) - { - monster->attitude = ATT_HOSTILE; - monster->del_ench(ENCH_CHARM, true); - behaviour_event(monster, ME_ALERT, MHITYOU); - // For now CREATED_FRIENDLY/WAS_NEUTRAL stays. + // If you worship a good god, you make all friendly and good + // neutral unholy and evil beings hostile. + if (is_good_god(you.religion) && mi->wont_attack()) + { + mi->attitude = ATT_HOSTILE; + mi->del_ench(ENCH_CHARM, true); + behaviour_event(*mi, ME_ALERT, MHITYOU); + // For now CREATED_FRIENDLY/WAS_NEUTRAL stays. - success = true; - } + success = true; } } @@ -238,33 +234,30 @@ static bool _chaotic_beings_on_level_attitude_change() { bool success = false; - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi; mi; ++mi) { - monsters *monster = &menv[i]; - if (monster->alive() - && monster->is_chaotic()) - { + if (!mi->is_chaotic()) + continue; + #ifdef DEBUG_DIAGNOSTICS - mprf(MSGCH_DIAGNOSTICS, "Chaotic attitude changing: %s on level %d, branch %d", - monster->name(DESC_PLAIN).c_str(), - static_cast<int>(you.your_level), - static_cast<int>(you.where_are_you)); + mprf(MSGCH_DIAGNOSTICS, "Chaotic attitude changing: %s on level %d, branch %d", + mi->name(DESC_PLAIN).c_str(), + static_cast<int>(you.your_level), + static_cast<int>(you.where_are_you)); #endif - // If you worship Zin, you make all friendly and good neutral - // chaotic beings hostile. - if (you.religion == GOD_ZIN && monster->wont_attack()) - { - monster->attitude = ATT_HOSTILE; - monster->del_ench(ENCH_CHARM, true); - behaviour_event(monster, ME_ALERT, MHITYOU); - // For now CREATED_FRIENDLY/WAS_NEUTRAL stays. + // If you worship Zin, you make all friendly and good neutral + // chaotic beings hostile. + if (you.religion == GOD_ZIN && mi->wont_attack()) + { + mi->attitude = ATT_HOSTILE; + mi->del_ench(ENCH_CHARM, true); + behaviour_event(*mi, ME_ALERT, MHITYOU); + // For now CREATED_FRIENDLY/WAS_NEUTRAL stays. - success = true; - } + success = true; } } - return (success); } @@ -277,30 +270,28 @@ static bool _spellcasters_on_level_attitude_change() { bool success = false; - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi; mi; ++mi) { - monsters *monster = &menv[i]; - if (monster->alive() - && monster->is_actual_spellcaster()) - { + if (!mi->is_actual_spellcaster()) + continue; + #ifdef DEBUG_DIAGNOSTICS - mprf(MSGCH_DIAGNOSTICS, "Spellcaster attitude changing: %s on level %d, branch %d", - monster->name(DESC_PLAIN).c_str(), - static_cast<int>(you.your_level), - static_cast<int>(you.where_are_you)); + mprf(MSGCH_DIAGNOSTICS, "Spellcaster attitude changing: %s on level %d, branch %d", + mi->name(DESC_PLAIN).c_str(), + static_cast<int>(you.your_level), + static_cast<int>(you.where_are_you)); #endif - // If you worship Trog, you make all friendly and good neutral - // magic users hostile. - if (you.religion == GOD_TROG && monster->wont_attack()) - { - monster->attitude = ATT_HOSTILE; - monster->del_ench(ENCH_CHARM, true); - behaviour_event(monster, ME_ALERT, MHITYOU); - // For now CREATED_FRIENDLY/WAS_NEUTRAL stays. + // If you worship Trog, you make all friendly and good neutral + // magic users hostile. + if (you.religion == GOD_TROG && mi->wont_attack()) + { + mi->attitude = ATT_HOSTILE; + mi->del_ench(ENCH_CHARM, true); + behaviour_event(*mi, ME_ALERT, MHITYOU); + // For now CREATED_FRIENDLY/WAS_NEUTRAL stays. - success = true; - } + success = true; } } @@ -322,18 +313,17 @@ static bool _make_god_gifts_on_level_disappear(bool seen = false) : GOD_NO_GOD; int count = 0; - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi; mi; ++mi) { - monsters *monster = &menv[i]; - if (is_follower(monster) - && monster->has_ench(ENCH_ABJ) - && mons_is_god_gift(monster, god)) + if (is_follower(*mi) + && mi->has_ench(ENCH_ABJ) + && mons_is_god_gift(*mi, god)) { - if (!seen || simple_monster_message(monster, " abandons you!")) + if (!seen || simple_monster_message(*mi, " abandons you!")) count++; // The monster disappears. - monster_die(monster, KILL_DISMISSED, NON_MONSTER); + monster_die(*mi, KILL_DISMISSED, NON_MONSTER); } } @@ -366,18 +356,17 @@ static bool _make_holy_god_gifts_on_level_good_neutral(bool seen = false) : GOD_NO_GOD; int count = 0; - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi; mi; ++mi) { - monsters *monster = &menv[i]; - if (is_follower(monster) - && !monster->has_ench(ENCH_CHARM) - && monster->is_holy() - && mons_is_god_gift(monster, god)) + if (is_follower(*mi) + && !mi->has_ench(ENCH_CHARM) + && mi->is_holy() + && mons_is_god_gift(*mi, god)) { // monster changes attitude - monster->attitude = ATT_GOOD_NEUTRAL; + mi->attitude = ATT_GOOD_NEUTRAL; - if (!seen || simple_monster_message(monster, " becomes indifferent.")) + if (!seen || simple_monster_message(*mi, " becomes indifferent.")) count++; } } @@ -412,18 +401,17 @@ static bool _make_god_gifts_on_level_hostile(bool seen = false) : GOD_NO_GOD; int count = 0; - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi; mi; ++mi) { - monsters *monster = &menv[i]; - if (is_follower(monster) - && mons_is_god_gift(monster, god)) + if (is_follower(*mi) + && mons_is_god_gift(*mi, god)) { // monster changes attitude and behaviour - monster->attitude = ATT_HOSTILE; - monster->del_ench(ENCH_CHARM, true); - behaviour_event(monster, ME_ALERT, MHITYOU); + mi->attitude = ATT_HOSTILE; + mi->del_ench(ENCH_CHARM, true); + behaviour_event(*mi, ME_ALERT, MHITYOU); - if (!seen || simple_monster_message(monster, " turns against you!")) + if (!seen || simple_monster_message(*mi, " turns against you!")) count++; } } @@ -457,33 +445,32 @@ static bool _yred_slaves_on_level_abandon_you() { bool success = false; - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi; mi; ++mi) { - monsters *monster = &menv[i]; - if (_is_yred_enslaved_body_and_soul(monster)) + if (_is_yred_enslaved_body_and_soul(*mi)) { #ifdef DEBUG_DIAGNOSTICS mprf(MSGCH_DIAGNOSTICS, "Undead soul abandoning: %s on level %d, branch %d", - monster->name(DESC_PLAIN).c_str(), + mi->name(DESC_PLAIN).c_str(), static_cast<int>(you.your_level), static_cast<int>(you.where_are_you)); #endif - yred_make_enslaved_soul(monster, true, true, true); + yred_make_enslaved_soul(*mi, true, true, true); success = true; } - else if (is_yred_undead_slave(monster)) + else if (is_yred_undead_slave(*mi)) { #ifdef DEBUG_DIAGNOSTICS mprf(MSGCH_DIAGNOSTICS, "Undead abandoning: %s on level %d, branch %d", - monster->name(DESC_PLAIN).c_str(), + mi->name(DESC_PLAIN).c_str(), static_cast<int>(you.your_level), static_cast<int>(you.where_are_you)); #endif - monster->attitude = ATT_HOSTILE; - behaviour_event(monster, ME_ALERT, MHITYOU); + mi->attitude = ATT_HOSTILE; + behaviour_event(*mi, ME_ALERT, MHITYOU); // For now CREATED_FRIENDLY stays. success = true; @@ -499,20 +486,19 @@ static bool _beogh_followers_on_level_abandon_you() // Note that orc high priests' summons are gifts of Beogh, so we // can't use is_orcish_follower() here. - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi; mi; ++mi) { - monsters *monster = &menv[i]; - if (mons_is_god_gift(monster, GOD_BEOGH)) + if (mons_is_god_gift(*mi, GOD_BEOGH)) { #ifdef DEBUG_DIAGNOSTICS mprf(MSGCH_DIAGNOSTICS, "Orc abandoning: %s on level %d, branch %d", - monster->name(DESC_PLAIN).c_str(), + mi->name(DESC_PLAIN).c_str(), static_cast<int>(you.your_level), static_cast<int>(you.where_are_you)); #endif - monster->attitude = ATT_HOSTILE; - behaviour_event(monster, ME_ALERT, MHITYOU); + mi->attitude = ATT_HOSTILE; + behaviour_event(*mi, ME_ALERT, MHITYOU); // For now CREATED_FRIENDLY stays. success = true; @@ -526,20 +512,19 @@ static bool _jiyva_slimes_on_level_abandon_you() { bool success = false; - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi; mi; ++mi) { - monsters *monster = &menv[i]; - if (is_fellow_slime(monster)) + if (is_fellow_slime(*mi)) { #ifdef DEBUG_DIAGNOSTICS mprf(MSGCH_DIAGNOSTICS, "Slime abandoning: %s on level %d, branch %d", - monster->name(DESC_PLAIN).c_str(), + mi->name(DESC_PLAIN).c_str(), static_cast<int>(you.your_level), static_cast<int>(you.where_are_you)); #endif - monster->attitude = ATT_HOSTILE; - behaviour_event(monster, ME_ALERT, MHITYOU); + mi->attitude = ATT_HOSTILE; + behaviour_event(*mi, ME_ALERT, MHITYOU); // For now WAS_NEUTRAL stays. success = true; @@ -625,27 +610,25 @@ bool yred_slaves_abandon_you() static bool _fedhas_plants_on_level_hostile() { - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi; mi; ++mi) { - monsters *monster = &menv[i]; - if (monster->alive() - && mons_is_plant(monster)) + if (mons_is_plant(*mi)) { #ifdef DEBUG_DIAGNOSTICS mprf(MSGCH_DIAGNOSTICS, "Plant hostility: %s on level %d, branch %d", - monster->name(DESC_PLAIN).c_str(), + mi->name(DESC_PLAIN).c_str(), static_cast<int>(you.your_level), static_cast<int>(you.where_are_you)); #endif // You can potentially turn an oklob or whatever neutral // again by going back to Fedhas. - if (testbits(monster->flags, MF_ATT_CHANGE_ATTEMPT)) - monster->flags &= ~MF_ATT_CHANGE_ATTEMPT; + if (testbits(mi->flags, MF_ATT_CHANGE_ATTEMPT)) + mi->flags &= ~MF_ATT_CHANGE_ATTEMPT; - monster->attitude = ATT_HOSTILE; - monster->del_ench(ENCH_CHARM, true); - behaviour_event(monster, ME_ALERT, MHITYOU); + mi->attitude = ATT_HOSTILE; + mi->del_ench(ENCH_CHARM, true); + behaviour_event(*mi, ME_ALERT, MHITYOU); // For now WAS_NEUTRAL stays. } } diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc index 27600e0a31..973962a6af 100644 --- a/crawl-ref/source/beam.cc +++ b/crawl-ref/source/beam.cc @@ -45,8 +45,9 @@ #include "message.h" #include "misc.h" #include "mon-behv.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-iter.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "mon-util.h" #include "mutation.h" #include "ouch.h" @@ -1180,14 +1181,14 @@ const zap_info zap_data[] = { }, { - ZAP_BACKLIGHT, + ZAP_CORONA, "0", 100, NULL, NULL, BLUE, true, - BEAM_BACKLIGHT, + BEAM_CORONA, DCHAR_SPACE, false, false, @@ -1196,14 +1197,14 @@ const zap_info zap_data[] = { }, { - ZAP_SLEEP, + ZAP_HIBERNATION, "0", 100, NULL, NULL, BLACK, true, - BEAM_SLEEP, + BEAM_HIBERNATION, DCHAR_SPACE, false, false, @@ -1321,6 +1322,22 @@ const zap_info zap_data[] = { false, false, 0 + }, + + { + ZAP_SLEEP, + "0", + 100, + NULL, + NULL, + BLACK, + true, + BEAM_SLEEP, + DCHAR_SPACE, + false, + false, + false, + 0 } }; @@ -2615,26 +2632,18 @@ bool mass_enchantment( enchant_type wh_enchant, int pow, int origin, const kill_category kc = (origin == MHITYOU ? KC_YOU : KC_OTHER); - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi(&you.get_los()); mi; ++mi) { - monsters* const monster = &menv[i]; - - if (!monster->alive()) - continue; - - if (!mons_near(monster)) - continue; - - if (monster->has_ench(wh_enchant)) + if (mi->has_ench(wh_enchant)) continue; if (m_attempted) ++*m_attempted; - if (_monster_resists_mass_enchantment(monster, wh_enchant, pow)) + if (_monster_resists_mass_enchantment(*mi, wh_enchant, pow)) continue; - if (monster->add_ench(mon_enchant(wh_enchant, 0, kc))) + if (mi->add_ench(mon_enchant(wh_enchant, 0, kc))) { if (m_succumbed) ++*m_succumbed; @@ -2649,11 +2658,11 @@ bool mass_enchantment( enchant_type wh_enchant, int pow, int origin, default: msg = NULL; break; } if (msg) - msg_generated = simple_monster_message(monster, msg); + msg_generated = simple_monster_message(*mi, msg); // Extra check for fear (monster needs to reevaluate behaviour). if (wh_enchant == ENCH_FEAR) - behaviour_event(monster, ME_SCARE, origin); + behaviour_event(*mi, ME_SCARE, origin); } } @@ -2889,7 +2898,7 @@ void fire_tracer(const monsters *monster, bolt &pbolt, bool explode_only) // When a mimic is hit by a ranged attack, it teleports away (the slow // way) and changes its appearance - the appearance change is in -// monster_teleport() in monstuff.cc. +// monster_teleport() in mon-stuff.cc. void mimic_alert(monsters *mimic) { if (!mimic->alive()) @@ -3124,6 +3133,7 @@ void bolt::affect_ground() int rc = create_monster(mgen_data(MONS_BALLISTOMYCETE, beh, + agent(), 0, 0, pos(), @@ -3355,8 +3365,8 @@ void bolt::affect_place_explosion_clouds() (whose_kill() == KC_OTHER ? BEH_HOSTILE : BEH_FRIENDLY); mons_place( - mgen_data(MONS_FIRE_VORTEX, att, 2, SPELL_FIRE_STORM, p, - MHITNOT, 0, god)); + mgen_data(MONS_FIRE_VORTEX, att, agent(), 2, SPELL_FIRE_STORM, + p, MHITNOT, 0, god)); } } } @@ -3667,9 +3677,8 @@ void bolt::tracer_affect_player() for (unsigned int i = 0; i < messages.size(); ++i) mpr(messages[i].c_str(), MSGCH_WARN); - range_used += range_used_on_hit(&you); - apply_hit_funcs(&you, 0); + range_used += range_used_on_hit(&you); } bool bolt::misses_player() @@ -3823,11 +3832,15 @@ void bolt::affect_player_enchantment() switch (flavour) { + case BEAM_HIBERNATION: + you.hibernate(ench_power); + break; + case BEAM_SLEEP: you.put_to_sleep(ench_power); break; - case BEAM_BACKLIGHT: + case BEAM_CORONA: you.backlight(); obvious_effect = true; break; @@ -4053,11 +4066,11 @@ void bolt::affect_player_enchantment() } } + apply_hit_funcs(&you, 0); + // Regardless of effect, we need to know if this is a stopper // or not - it seems all of the above are. range_used += range_used_on_hit(&you); - - apply_hit_funcs(&you, 0); } @@ -4324,8 +4337,8 @@ void bolt::tracer_enchantment_affect_monster(monsters* mon) handle_stop_attack_prompt(mon); if (!beam_cancelled) { - range_used += range_used_on_hit(mon); apply_hit_funcs(mon, 0); + range_used += range_used_on_hit(mon); } } @@ -4484,9 +4497,10 @@ void bolt::tracer_nonenchantment_affect_monster(monsters* mon) mpr(messages[i].c_str(), MSGCH_MONSTER_DAMAGE); } + apply_hit_funcs(mon, final); + // Either way, we could hit this monster, so update range used. range_used += range_used_on_hit(mon); - apply_hit_funcs(mon, final); } void bolt::tracer_affect_monster(monsters* mon) @@ -4585,8 +4599,8 @@ void bolt::enchantment_affect_monster(monsters* mon) beogh_follower_convert(mon, true); } - range_used += range_used_on_hit(mon); apply_hit_funcs(mon, 0); + range_used += range_used_on_hit(mon); } void bolt::monster_post_hit(monsters* mon, int dmg) @@ -4980,9 +4994,8 @@ void bolt::affect_monster(monsters* mon) mon = &orig; } - range_used += range_used_on_hit(mon); - apply_hit_funcs(mon, final, corpse); + range_used += range_used_on_hit(mon); } bool bolt::has_saving_throw() const @@ -5040,8 +5053,8 @@ bool _ench_flavour_affects_monster(beam_type flavour, const monsters* mon) rc = !mon->res_negative_energy(); break; - case BEAM_SLEEP: - rc = mon->can_sleep(); + case BEAM_HIBERNATION: + rc = mon->can_hibernate(); break; case BEAM_PORKALATOR: @@ -5186,7 +5199,7 @@ mon_resist_type bolt::apply_enchantment_to_monster(monsters* mon) } // The monster can be no more than lightly wounded/damaged, - // using the formula from monstuff.cc:mons_get_damage_level(). + // using the formula from mon-stuff.cc:mons_get_damage_level(). if (mon->hit_points <= mon->max_hit_points * 3 / 4) { simple_monster_message(mon, "'s soul is too badly injured."); @@ -5245,17 +5258,17 @@ mon_resist_type bolt::apply_enchantment_to_monster(monsters* mon) mon->hurt(agent(), damage.roll(), flavour); return (MON_AFFECTED); - case BEAM_SLEEP: - if (mon->can_sleep()) + case BEAM_HIBERNATION: + if (mon->can_hibernate()) { if (simple_monster_message(mon, " looks drowsy...")) obvious_effect = true; - mon->put_to_sleep(); + mon->hibernate(); return (MON_AFFECTED); } return (MON_UNAFFECTED); - case BEAM_BACKLIGHT: + case BEAM_CORONA: if (backlight_monsters(mon->pos(), hit, 0)) { obvious_effect = true; @@ -5350,6 +5363,17 @@ mon_resist_type bolt::apply_enchantment_to_monster(monsters* mon) } return (MON_AFFECTED); + case BEAM_SLEEP: + if (mon->has_ench(ENCH_SLEEPY)) + return (MON_UNAFFECTED); + + if (mon->add_ench(mon_enchant(ENCH_SLEEPY, 0, whose_kill()))) + { + if (simple_monster_message(mon, " falls asleep!")) + obvious_effect = true; + } + return (MON_AFFECTED); + case BEAM_INVISIBILITY: { // Store the monster name before it becomes an "it" -- bwr @@ -5358,7 +5382,7 @@ mon_resist_type bolt::apply_enchantment_to_monster(monsters* mon) if (!mon->has_ench(ENCH_INVIS) && mon->add_ench(ENCH_INVIS)) { // A casting of invisibility erases backlight. - mon->del_ench(ENCH_BACKLIGHT); + mon->del_ench(ENCH_CORONA); // Can't use simple_monster_message() here, since it checks // for visibility of the monster (and it's now invisible). @@ -5404,13 +5428,20 @@ mon_resist_type bolt::apply_enchantment_to_monster(monsters* mon) if (mons_is_ghost_demon(mon->type)) return (MON_UNAFFECTED); - monster_type orig_type = mon->type; + monsters orig_mon(*mon); if (monster_polymorph(mon, (mon->holiness() == MH_DEMONIC ? MONS_HELL_HOG : MONS_HOG))) { obvious_effect = true; + + // Don't restore items to monster if it reverts. + orig_mon.inv = mon->inv; + + // For monster reverting to original form. + mon->props[ORIG_MONSTER_KEY] = orig_mon; } - mon->number = ((int) orig_type + 1); + + return (MON_AFFECTED); } @@ -5913,7 +5944,7 @@ bool bolt::nasty_to(const monsters *mon) const // degeneration / sleep / enslave soul if (flavour == BEAM_DEGENERATE - || flavour == BEAM_SLEEP + || flavour == BEAM_HIBERNATION || flavour == BEAM_ENSLAVE_SOUL) { return (mon->holiness() == MH_NATURAL); @@ -6161,8 +6192,9 @@ std::string beam_type_name(beam_type type) case BEAM_ENSLAVE_DEMON: return ("enslave demon"); case BEAM_BLINK: return ("blink"); case BEAM_PETRIFY: return ("petrify"); - case BEAM_BACKLIGHT: return ("backlight"); + case BEAM_CORONA: return ("backlight"); case BEAM_PORKALATOR: return ("porkalator"); + case BEAM_HIBERNATION: return ("hibernation"); case BEAM_SLEEP: return ("sleep"); case BEAM_BERSERK: return ("berserk"); case BEAM_POTION_BLACK_SMOKE: return ("black smoke"); diff --git a/crawl-ref/source/cloud.cc b/crawl-ref/source/cloud.cc index fda354706a..b1a6069c50 100644 --- a/crawl-ref/source/cloud.cc +++ b/crawl-ref/source/cloud.cc @@ -925,7 +925,7 @@ killer_type cloud_struct::whose_to_killer(kill_category whose) { case KC_YOU: return(KILL_YOU_MISSILE); case KC_FRIENDLY: return(KILL_MON_MISSILE); - case KC_OTHER: return(KILL_MON_MISSILE); + case KC_OTHER: return(KILL_MISC); case KC_NCATEGORIES: ASSERT(false); } return (KILL_NONE); diff --git a/crawl-ref/source/clua.cc b/crawl-ref/source/clua.cc index 64fd63b768..4f25a2d362 100644 --- a/crawl-ref/source/clua.cc +++ b/crawl-ref/source/clua.cc @@ -622,6 +622,7 @@ void CLua::init_lua() cluaopen_file(_state); cluaopen_moninf(_state); cluaopen_options(_state); + cluaopen_travel(_state); cluaopen_view(_state); cluaopen_globals(_state); diff --git a/crawl-ref/source/cmd-keys.h b/crawl-ref/source/cmd-keys.h index 5294c04ae0..d9610d58d3 100644 --- a/crawl-ref/source/cmd-keys.h +++ b/crawl-ref/source/cmd-keys.h @@ -242,6 +242,7 @@ {CONTROL('W'), CMD_MAP_ADD_WAYPOINT}, {'e', CMD_MAP_EXCLUDE_AREA}, {CONTROL('E'), CMD_MAP_CLEAR_EXCLUDES}, +{'R', CMD_MAP_EXCLUDE_RADIUS}, {'b', CMD_MAP_MOVE_DOWN_LEFT}, {'h', CMD_MAP_MOVE_LEFT}, {'j', CMD_MAP_MOVE_DOWN}, diff --git a/crawl-ref/source/cmd-name.h b/crawl-ref/source/cmd-name.h index 9940b8e548..0d58833c4d 100644 --- a/crawl-ref/source/cmd-name.h +++ b/crawl-ref/source/cmd-name.h @@ -114,6 +114,7 @@ {CMD_MAP_ADD_WAYPOINT, "CMD_MAP_ADD_WAYPOINT"}, {CMD_MAP_EXCLUDE_AREA, "CMD_MAP_EXCLUDE_AREA"}, {CMD_MAP_CLEAR_EXCLUDES, "CMD_MAP_CLEAR_EXCLUDES"}, +{CMD_MAP_EXCLUDE_RADIUS, "CMD_MAP_EXCLUDE_RADIUS"}, {CMD_MAP_MOVE_LEFT, "CMD_MAP_MOVE_LEFT"}, {CMD_MAP_MOVE_DOWN, "CMD_MAP_MOVE_DOWN"}, {CMD_MAP_MOVE_UP, "CMD_MAP_MOVE_UP"}, diff --git a/crawl-ref/source/command.cc b/crawl-ref/source/command.cc index 457a598224..aef0bc00a1 100644 --- a/crawl-ref/source/command.cc +++ b/crawl-ref/source/command.cc @@ -2425,7 +2425,8 @@ int list_wizard_commands(bool do_redraw_screen) "<w>k</w> : shift section of a labyrinth\n" "<w>u</w>/<w>d</w> : shift up/down one level\n" "<w>~</w> : go to a specific level\n" - "<w>:</w> : find branches in the dungeon\n" + "<w>:</w> : find branches and overflow\n" + " temples in the dungeon\n" "<w>{</w> : magic mapping\n" "\n" "<yellow>Debugging commands</yellow>\n" diff --git a/crawl-ref/source/coord-circle.cc b/crawl-ref/source/coord-circle.cc index 4170662b10..9072c6fa3e 100644 --- a/crawl-ref/source/coord-circle.cc +++ b/crawl-ref/source/coord-circle.cc @@ -41,8 +41,8 @@ void circle_def::init(int param, circle_type ctype) break; case C_CIRCLE: shape = SH_CIRCLE; - radius = static_cast<int>(ceil(sqrt(radius_sq))); radius_sq = param; + radius = static_cast<int>(ceil(sqrt(radius_sq))); break; case C_ROUND: shape = SH_CIRCLE; diff --git a/crawl-ref/source/dat/altar.des b/crawl-ref/source/dat/altar.des index 633caf24da..dd0fd6ebbf 100644 --- a/crawl-ref/source/dat/altar.des +++ b/crawl-ref/source/dat/altar.des @@ -19,14 +19,14 @@ TAGS: allow_dup # More common than the others. WEIGHT: 20 MAP -cccccccccc -cBcBcBcBcc -G.c.c.c.Bc -@.......Bc -@.......Bc -G.c.c.c.Bc -cBcBcBcBcc -cccccccccc +cccccccccccc +cBcBcBcBcBcc +G.c.c.c.c.Bc +@.........Bc +@.........Bc +G.c.c.c.c.Bc +cBcBcBcBcBcc +cccccccccccc ENDMAP NAME: jmf_multi_god_temple @@ -273,14 +273,13 @@ ENDMAP # III Special altars ###################################### -# XXX - The WEIGHTs and PLACE of these Fedhas vaults are temporary. -# Remove once the Ecumenical Temple is updated to cater for -# more than 12 gods. +# NOTE: A vault tagged with only temple_overflow_FOO will only ever be used +# for overflow temples, but one tagged with both temple_overflow_FOO and +# uniq_altar_FOO can be generated either randomly or as an overflow temple. NAME: fedhas_altar_1 -TAGS: uniq_altar_fedhas +TAGS: uniq_altar_fedhas temple_overflow_fedhas DEPTH: D:2-7 -WEIGHT: 75 KFEAT: C = altar_fedhas MONS: plant MAP @@ -292,9 +291,8 @@ MAP ENDMAP NAME: fedhas_altar_2 -TAGS: uniq_altar_fedhas +TAGS: uniq_altar_fedhas temple_overflow_fedhas DEPTH: D:2-7 -WEIGHT: 75 KFEAT: C = altar_fedhas NSUBST: w = 2:W / *:w SUBST: . = ..wW @@ -308,9 +306,8 @@ MAP ENDMAP NAME: fedhas_altar_3 -TAGS: uniq_altar_fedhas +TAGS: uniq_altar_fedhas temple_overflow_fedhas DEPTH: D:2-7 -WEIGHT: 75 KFEAT: C = altar_fedhas NSUBST: b = 1:. / *:1 MONS: plant w:5 / fungus / nothing w:3 @@ -323,9 +320,8 @@ MAP ENDMAP NAME: fedhas_altar_4 -TAGS: uniq_altar_fedhas +TAGS: uniq_altar_fedhas temple_overflow_fedhas DEPTH: D:2-7 -WEIGHT: 75 KFEAT: C = altar_fedhas FTILE: . = floor_lair FTILE: t = floor_lair @@ -345,33 +341,31 @@ ENDMAP NAME: fedhas_altar_5 TAGS: uniq_altar_fedhas -PLACE: D:8 -KFEAT: C = altar_fedhas +KFEAT: _ = altar_fedhas MONS: centaur, bush MAP ...... .2222.. .21222. -.22C22. +.22_22. ...22.. .222.. ENDMAP NAME: cheibriados_altar_1 -TAGS: uniq_altar_cheibriados -PLACE: D:7 -KFEAT: C = altar_cheibriados +TAGS: uniq_altar_cheibriados temple_overflow_cheibriados +KFEAT: _ = altar_cheibriados MAP ... -.C. +._. ... ENDMAP NAME: cheibriados_altar_2 TAGS: uniq_altar_cheibriados DEPTH: D:2-6 -WEIGHT: 100 -KFEAT: C = altar_cheibriados +WEIGHT: 5 +KFEAT: _ = altar_cheibriados MONS: giant slug, giant snail, elephant slug SUBST: 1 : 1:50 2:30 3:10 4:10 NSUBST: 4 = 1:1 / 1:2 / 1:3 @@ -380,7 +374,7 @@ MAP .mmm... .m1m... .mmmmm. -..Cm1m. +.._m1m. .mmmmm. .m1m... .mmm... @@ -388,16 +382,15 @@ MAP ENDMAP NAME: cheibriados_altar_3 -TAGS: uniq_altar_cheibriados +TAGS: uniq_altar_cheibriados temple_overflow_cheibriados DEPTH: D:2-6 -WEIGHT: 100 -KFEAT: C = altar_cheibriados +KFEAT: _ = altar_cheibriados ITEM: potion of slowing ITEM: apple, pear, orange, banana SUBST: e : efgh MAP .d. -eCe +e_e .d. ENDMAP @@ -411,14 +404,14 @@ MONS: patrolling Daeva / patrolling Angel : else MONS: patrolling Angel : end -KFEAT: C = altar_elyvilon / altar_zin / altar_shining_one +KFEAT: _ = altar_elyvilon / altar_zin / altar_shining_one MAP ..... ..xmx.. ..xx>xx.. ..xxx.xxx.. .xxxx1xxxx. -.m>..C..>m. +.m>.._..>m. .xxxx.xxxx. ..xxx.xxx.. ..xx>xx.. @@ -436,15 +429,15 @@ SUBST: 3 = 3L SUBST: 1 = 1:20 4 : end SUBST: L = l. -SUBST: C = C P:1 -KFEAT: C = altar_lugonu/altar_yredelemnul/altar_kikubaaqudgha/altar_makhleb +SUBST: _ = _ P:1 +KFEAT: _ = altar_lugonu/altar_yredelemnul/altar_kikubaaqudgha/altar_makhleb KFEAT: P = enter_abyss MAP ..LLllLL.... .LllllllLLL.. ..Lll323lllLLL. .LLl32123lllLL. -.LLl33C33llLL.. +.LLl33_33llLL.. ..Lll323llLL... ..LLll3llL..... ...LLlllL... @@ -457,11 +450,11 @@ NAME: david_defended_altar_orc DEPTH: D:7-20, Orc MONS: patrolling orc priest TAGS: uniq_defended_altar -KFEAT: D = altar_beogh / w:1 altar_okawaru / w:1 altar_makhleb / w:1 altar_trog +KFEAT: _ = altar_beogh / w:1 altar_okawaru / w:1 altar_makhleb / w:1 altar_trog MAP ccccc... c1..c... -c1D.+.I@ +c1_.+.I@ c1..c... ccccc... ENDMAP @@ -480,14 +473,14 @@ ENDMAP NAME: lemuel_blue_sif_altar DEPTH: D:2-18, Elf, Vault -TAGS: no_monster_gen mini_float +TAGS: no_monster_gen mini_float temple_overflow_sif_muna uniq_altar_sif_muna COLOUR: . = blue FTILE: . = floor_hall, C = floor_hall, @ = floor_hall, + = floor_hall -KFEAT: C = altar_sif_muna +KFEAT: _ = altar_sif_muna MAP xxxxxxxxxxxxxx ...........xxx -@..........+Cx +@..........+_x ...........xxx xxxxxxxxxxxxxx ENDMAP @@ -498,12 +491,12 @@ TAGS: no_pool_fixup MONS: rat zombie / giant bat zombie / nothing w:200 KMONS: w = giant goldfish zombie / big fish zombie / nothing w:200 KFEAT: w = deep_water -KFEAT: C = altar_kikubaaqudgha / altar_yredelemnul +KFEAT: _ = altar_kikubaaqudgha / altar_yredelemnul MAP xxxxxxxxxxxxxxxx xxxxwwwwwwwwxxxx xxxx11111111xxxx -@.............Cx +@............._x xxxx11111111xxxx xxxxwwwwwwwwxxxx xxxxxxxxxxxxxxxx @@ -534,10 +527,10 @@ MONS: w:50 human zombie/orc zombie/elf zombie/w:5 ogre zombie/w:5 troll zombie MONS: w:50 human skeleton/orc skeleton/elf skeleton/w:5 ogre skeleton/\ w:5 troll skeleton MONS: mummy, wight, wraith, necrophage, ghoul -NSUBST: ? = 1:C / *:1 +NSUBST: ? = 1:_ / *:1 SUBST: 1 = 1:25 2 3 4:8 5:6 6:4 7:2 -KFEAT: C = altar_kikubaaqudgha / altar_yredelemnul -KMONS: C = human zombie +KFEAT: _ = altar_kikubaaqudgha / altar_yredelemnul +KMONS: _ = human zombie MAP ccccccccccccccc c?c?c?c?c?c?ccG @@ -552,15 +545,15 @@ ENDMAP # Nemelex altar (Shiori) # Perhaps could have different parameters for the two types of clouds, # and different patterns. -NAME: nemelx_altar_shiori -DEPTH: !Lair, !Orc -TAGS: no_pool_fixup no_monster_gen no_item_gen -TAGS: generate_awake patrolling mini_float no_rotate -TAGS: layout_rooms layout_city layout_open layout_cross -KFEAT: _ = altar_nemelex_xobeh -SUBST: b:aa. , a:n. , d:c. , c:nn. , f:ee. , e:nn. , h:g. , g:n. -SUBST: G:GTUVblw> , C=c -KFEAT: z = teleport trap +NAME: nemelex_altar_shiori +DEPTH: !Lair, !Orc +TAGS: no_pool_fixup no_monster_gen no_item_gen +TAGS: generate_awake patrolling mini_float no_rotate +TAGS: layout_rooms layout_city layout_open layout_cross +KFEAT: _ = altar_nemelex_xobeh +SUBST: b:aa. , a:n. , d:c. , c:nn. , f:ee. , e:nn. , h:g. , g:n. +SUBST: G:GTUVblw> , C=c +KFEAT: z = teleport trap MARKER: R = lua:fog_machine { cloud_type="flame", walk_dist=1, size=9, \ pow_max=20, delay=10, buildup_amnt=14, buildup_time=7, \ spread_rate=3, start_clouds=1 } @@ -599,13 +592,13 @@ MARKER: P = lua:fog_machine { cloud_type="blue smoke", walk_dist=1, \ size=9, pow_max=20, delay=10, buildup_amnt=14, buildup_time=7, \ spread_rate=3, start_clouds=1 } : if crawl.coinflip() then -KFEAT: L = altar_lugonu +KFEAT: _ = altar_lugonu KFEAT: P = enter_abyss : kmons("1 = kobold w:" .. you.absdepth() .. " ; quick blade ego:distortion " .. : "w:6 | sabre ego:distortion | short sword ego:distortion / kobold " .. : "w:80 ; short sword | sabre | quick blade w:3") : else -KFEAT: L = altar_xom +KFEAT: _ = altar_xom : if crawl.one_chance_in(4) then KMONS: P = orange crystal statue : else @@ -623,7 +616,7 @@ cc..P..cc ccc.cccc ccyy.yyyccc cy..111.yyc -cc..1L1..cc +cc..1_1..cc cyy.111..yc cccyy..yycc ccc..ccc @@ -633,14 +626,217 @@ ENDMAP ############################################################################### # Blood-stained Trog altar! -NAME: bloody_trog -DEPTH: D:7-20 -TAGS: uniq_bloody_trog -KPROP: . = bloody / nothing -KFEAT: _ = altar_trog -KITEM: _ = animal skin, knife +NAME: bloody_trog +TAGS: uniq_altar_trog temple_overflow_trog +DEPTH: D:2-20, Orc, Vault +KPROP: . = bloody / nothing +KFEAT: _ = altar_trog +KITEM: _ = animal skin, knife MAP ... ._. ... ENDMAP + +############################################################################### +# Fedhas altar by TGW. +# Threat: two big fish. Loot: some fruits. +# The oklob plant may be abusable (if so, remove it). +NAME: tgw_fedhas +TAGS: no_item_gen no_monster_gen +DEPTH: Lair, D:2-20 +KFEAT: _ = altar_fedhas +MONS: plant, fungus, oklob plant, big fish, bush, toadstool col:random +SUBST: x = TTPPPPP. +SHUFFLE: PQR, TU, ..." +SUBST: P = 112 , Q = 115, R = 111235 +SUBST: T = xt, U = xx +SUBST: " = .....6 +COLOUR: . = green / none +COLOUR: ' = green +COLOUR: x = green / none w:30 +NSUBST: w = 2:4 / *:w +SUBST: 6 = 112 +ITEM: apple / apricot / orange / pear / grape / strawberry / nothing w:70 +MAP +ccccccccccccccccccccccc +cxxxxxxxxxxxxxxxxxxxxxc +cxxxxxxxxxxxxxxPxxd3xxc +cxxxxxxxxxxxxxxPddddxxc +cxxxxxxxxxxxxxxPPPx.dxc +cxxxxxxx.......xxPPxxxc +cxxxxxx..wwdww..xxPPxxc +cxxxxx..wwwdwww..xxxPxc +cxxxx..wwwwdwwww..xxxxc +cxxxx.wwwwwdwwwww.xxxxc +cxxxx.wwww'''wwww.xxxxc +cxxxx.wwww'_'wwww.xxxxc +cxxxx.wwww'''wwww.xxxxc +cxxxx.wwwwwwwwwww.xxxxc +cxxxx..wwwwwwwww..xxxxc +cxxxxx..wwwwwww..xxxxxc +cxxxxxx..wwwww..xxxxxxc +cxxxxxxx.......xxxxxxxc +cxxxxxxxxxc.cxxxxxxxxxc +cxxxxxxxxxc.cxxxxxxxxxc +ccccccccccc@ccccccccccc +ENDMAP + +############################################################################### +# Altars to the good gods by TGW. +NAME: tgw_good +TAGS: no_item_gen no_monster_gen +SHUFFLE: XYZ +KFEAT: X = altar_shining_one +KFEAT: Y = altar_elyvilon +KFEAT: Z = altar_zin +COLOUR: a = darkgrey / red / blue w:3 / lightred w:2 +COLOUR: b = darkgrey w:100 / red w:50 / lightgrey / blue w:30 / cyan / lightred +COLOUR: c = darkgrey w:7 / red w:2 / lightgrey w:4 / blue w:4 / cyan w:2 +COLOUR: d = darkgrey w:4 / lightgrey w:4 / blue / cyan w:4 +COLOUR: e = blue / cyan w:4 +COLOUR: f = blue / cyan w:7 +SUBST: abcdef = w +SUBST: G = ...BBC +NSUBST: H = 2:C / *:H +SUBST: H = .BBCCC +COLOUR: B = white +COLOUR: C = yellow +SUBST: B = . +NSUBST: C = 1:M / 3:d / *:. +ITEM: any scroll / scroll of holy word +MONS: human; falchion / human; falchion ego:holy_wrath w:1 \ + / human; quarterstaff / human; quarterstaff ego:holy_wrath w:1 \ + / human +MONS: gnoll; falchion / gnoll; falchion ego:holy_wrath w:1 / gnoll; \ + quarterstaff / gnoll; quarterstaff ego:holy_wrath w:1 / gnoll +MONS: orc; falchion / orc; falchion ego:holy_wrath w:1 \ + / orc; quarterstaff / orc; quarterstaff ego:holy_wrath w:1 / orc +SUBST: M = 123 +MAP + xxxxxxxxxxxxx + xxaaaaaaaaaaaxx + xxbbbbbbbbbbbbbxx + xxcccccccccccccccxx + xxdddddddddddddddddxx + xxeeeeeeeeeeeeeeeeeeexx +xxxxxxxxxxxxfffffffffffffffffffffxx +x..........GGGGGGHHHHHHHHHHHGGGGGGxx +@..........GGGGGGHHHXHHYHHZHHHGGGGGGx +x..........GGGGGGHHHHHHHHHHHGGGGGGxx +xxxxxxxxxxxxfffffffffffffffffffffxx + xxeeeeeeeeeeeeeeeeeeexx + xxdddddddddddddddddxx + xxcccccccccccccccxx + xxbbbbbbbbbbbbbxx + xxaaaaaaaaaaaxx + xxxxxxxxxxxxx +ENDMAP + +############################################################################### +# Altar to Xom by TGW. +NAME: tgw_xom +TAGS: no_item_gen no_monster gen +KFEAT: _ = altar_xom +MONS: orc; club ego:chaos / orc; dagger ego:chaos / orc; spear ego:chaos +MONS: gnoll; club ego:chaos / gnoll; dagger ego:chaos / gnoll; spear ego:chaos +MONS: place:D:1-8 +NSUBST: ' = 1:_ / *:. +SUBST: . = .:200 ~:70 W:60 w:50 x:80 n:80 v b l Z T U M:20 +NSUBST: Z = 1:* / *:% +SUBST: M : 123333M, 1 = 1.., 2 = 2.., M = 123. +COLOUR: . = random +MAP + xxxxxx@xxxxxx + xx...........xx + xx.............xx +xx...............xx +x.................x +x.................x +x'...............'x +x'...............'x +xx'.............'xx + xx'''''''''''''xx + xx'''''''''''xx + xxxxxxxxxxxxx +ENDMAP + +############################################################################### +# Altar to Trog by TGW. +# Features berserk monsters, so we're careful: no intelligent monsters, so you +# close the door. Provide a chokepoint. +NAME: tgw_trog +TAGS: no_item_gen no_monster_gen +KFEAT: _ = altar_trog +MONS: moth of wrath, rat / worm w:5 +ITEM: any weapon +NSUBST: M = 4:d / *:. +MAP + xxxxxxx + xxxMMMxxx + xxMMM2MMMxx + xxMM22_22MMxx + xx.........xx + x....ooo....x + x...oo1oo...x + x....ooo....x + x...........x + xx.........xx + xx.......xx + xxxx+xxxx + xx@xx +ENDMAP + +############################################################################### +# Altar to Sif by TGW. +NAME: tgw_sif +TAGS: no_item_gen no_monster_gen no_pool_fixup +KFEAT: _ = altar_sif_muna +MONS: orc wizard w:15 / Jessica / Blork the Orc +NSUBST: M = 1:1 / *:" +SUBST: ' : "'., ' = ''. +COLOUR: . = blue +SUBST: ' = ., " = . +ITEM: potion of gain intelligence w:2 / potion of brilliance /\ + potion of magic / any book w:1 +MAP + xx@xx + x...x + x...x + xxx...xxx + xx'''''''xx + xx'''...'''xx + x'''.www.'''x + xx''.wwwww.''xx + x''.wwM"Mww.''x + x''.wwM>Mww.''x + x''.wwMMMww.''x + xx''.wwwww.''xx + x'''.www.'''x + xx'''...'''xx + xx''d'd''xx + xxx...xxx + x._.x + x...x + xxxxx +ENDMAP + +############################################################################### +# TSO's small temple (1KB) +# Idea stolen from protected_by_tso_3. +NAME: tso_altar +TAGS: no_item_gen no_rotate temple_overflow_the_shining_one +COLOUR: _ = yellow +SUBST: _ = . +COLOUR: c = white +KFEAT: A = altar_shining_one +MAP + xxxxx +xxxcccxxx +xcccAcccx +xc.___.cx +xct._.tcx +xc.._..cx +xct...tcx +xccc+cccx +ENDMAP diff --git a/crawl-ref/source/dat/clua/lm_trig.lua b/crawl-ref/source/dat/clua/lm_trig.lua index 336da856b0..d17ea9e0da 100644 --- a/crawl-ref/source/dat/clua/lm_trig.lua +++ b/crawl-ref/source/dat/clua/lm_trig.lua @@ -274,7 +274,7 @@ function Triggerable:do_trigger(triggerer, marker, ev) slaves = { slave_marker } else - dgn.find_markers_by_prop("slaved_to", master_name) + slaves = dgn.find_markers_by_prop("slaved_to", master_name) end -- If all slaves are gone, we're done. @@ -693,7 +693,7 @@ function DgnTriggerer:monster_dies(triggerable, marker, ev) error("DgnTriggerer:monster_dies() didn't get a valid monster index") end - if mons.name == self.target then + if mons.full_name == self.target then triggerable:do_trigger(self, marker, ev) end end diff --git a/crawl-ref/source/dat/database/monspeak.txt b/crawl-ref/source/dat/database/monspeak.txt index e28a854cc9..78c0f659af 100644 --- a/crawl-ref/source/dat/database/monspeak.txt +++ b/crawl-ref/source/dat/database/monspeak.txt @@ -1351,7 +1351,7 @@ VISUAL:@The_monster@ counts something out on his fingers. %%%% _crazy_yiuf_speech_ -w:30 +w:300 @The_monster@ @_crazy_yiuf_speech_verbs_@, "@_crazy_yiuf_sentence_@" VISUAL:@The_monster@ waves his quarterstaff at you. @player_only@ @@ -1732,6 +1732,10 @@ Dowan w:2 @_Dowan_rare_@ %%%% +fleeing Dowan + +VISUAL:@The_monster@ cries in horror. +%%%% _Dowan_common_ VISUAL:@The_monster@ smirks and points a slender finger @at_foe@. @@ -1773,6 +1777,10 @@ _Dowan_Duvessa_dies_invisible_ @The_monster@ screams, "No! No! NO!" %%%% +_Dowan_Duvessa_dies_distance_ + +You hear a distant wail of despair. +%%%% ############ DUANE ### A mercenary guarding the dungeon Duane @@ -1825,6 +1833,10 @@ _Duvessa_Dowan_dies_invisible_ @The_monster@ shouts wrathfully, "No!" %%%% +_Duvessa_Dowan_dies_distance_ + +You hear a distant scream of rage. +%%%% ############ EDMUND ### A mercenary guarding the dungeon Edmund diff --git a/crawl-ref/source/dat/descript/monsters.txt b/crawl-ref/source/dat/descript/monsters.txt index 4e4c7572a7..a6d8023c67 100644 --- a/crawl-ref/source/dat/descript/monsters.txt +++ b/crawl-ref/source/dat/descript/monsters.txt @@ -62,7 +62,7 @@ A being of pure chaos, its form is constantly shifting, growing and then losing %%%% Crazy Yiuf -A withered old goblin with a long silver beard, wielding a quarterstaff and wearing a cloak. He looks like a figure from mythology! Wait, is his beard held on to his ears with hooks? +A withered old gnoll with a long silver beard, wielding a quarterstaff and wearing a cloak. He looks like a figure from mythology! Wait, is his beard held on to his ears with hooks? %%%% Daeva diff --git a/crawl-ref/source/dat/entry.des b/crawl-ref/source/dat/entry.des index d720877302..ee22731e97 100644 --- a/crawl-ref/source/dat/entry.des +++ b/crawl-ref/source/dat/entry.des @@ -191,14 +191,12 @@ MARKER: A = lua:fog_machine { \ SUBST: A = a , a = a m:1 FTILE: a = floor_slime COLOUR: a = lightgreen -KPROP: a = force_exclude SUBST: a = . MARKER: W = lua:fog_machine{\ pow_max = 10, delay_min = 50, delay_max = 300, \ size = 8, start_clouds = 1, \ cloud_type = "freezing vapour"} SUBST: W = w -KPROP: w = force_exclude SUBST: w : Ww'" , ' = wwW" COLOUR: " = blue SUBST: " = . @@ -208,7 +206,6 @@ MARKER: F = lua:fog_machine {\ size = 8, start_clouds = 1, \ cloud_type = "flame"} SUBST: F = f -KPROP: f = force_exclude SUBST: f : fflF , f = llf , F = f FTILE: f = floor_rough_red COLOUR: f = red @@ -224,6 +221,11 @@ SUBST: e =. SHUFFLE: XZ NSUBST: Z = ) / ] NSUBST: X = ( / [ +MARKER: = = lua:props_marker { \ + door_open_prompt="This door is covered in warnings. Open " .. \ + "it anyways?", \ + door_description_prefix="warning scrawled " \ + } MAP ... ccc===ccc diff --git a/crawl-ref/source/dat/float.des b/crawl-ref/source/dat/float.des index 5f1dc8d421..82796011e0 100644 --- a/crawl-ref/source/dat/float.des +++ b/crawl-ref/source/dat/float.des @@ -520,7 +520,7 @@ ENDMAP # NAME: onia_ninara_012_swampy_vault TAGS: no_pool_fixup no_monster_gen -DEPTH: D:16-20, Lair:3-10, Swamp, Snake, Slime +DEPTH: D:16-20, Lair:3-10, Swamp, Snake ORIENT: float SHUFFLE: AB@ SUBST: x = .:30 W x:4 @@ -868,7 +868,7 @@ ENDMAP # Elemental Laboratory (by Mu.) # NAME: elemental_lab_mu -DEPTH: D:16-26, Elf:1-6 +DEPTH: D:13-26, Elf:1-6 ORIENT: float FLAGS: no_monster_gen no_item_gen no_pool_fixup MARKER: ! = lua:fog_machine { \ @@ -890,7 +890,7 @@ KMONS: 1 = fire elemental NSUBST: ; = 3:2 / *=.ll KMONS: 2 = molten gargoyle KMONS: e = earth elemental -SUBST: E = ecxxx.. +SUBST: E = exxx.... NSUBST: ' = 3:3 / 3:W / *:. KMONS: 3 = clay golem NSUBST: w = 3:4 / *:w @@ -900,13 +900,25 @@ NSUBST: " = 3:5 / *:. KMONS: 5 = vapour KMONS: 6 = air elemental KMONS: 7 = fire vortex +# : if you.in_branch("elf") then -KMONS: Z = deep elf sorcerer ; robe ego:fire_resistance race:elven | \ - robe ego:cold_resistance race:elven | \ - robe ego:resistance race:elven +KMONS: Z = col:gila deep elf sorcerer \ + name:deep_elf_elementalist name_replace \ + spells:iron_shot;summon_air_elementals;sticky_flame;\ + summon_water_elementals;haste;blink actual_spells \ + ; robe ego:fire_resistance race:elven | \ + robe ego:cold_resistance race:elven | \ + robe ego:resistance race:elven . dagger ego:freezing race:elven | \ + dagger ego:flaming race:elven | dagger ego:electrocution race:elven : else -KMONS: Z = wizard ; robe ego:fire_resistance | robe ego:cold_resistance | \ - robe ego:resistance +KMONS: Z = col:gila vault guard \ + name:master_elementalist name_replace \ + spells:iron_shot;summon_air_elementals;sticky_flame;\ + summon_water_elementals;haste;blink actual_spells \ + ; robe ego:fire_resistance | robe ego:cold_resistance | \ + robe ego:resistance \ + . dagger ego:freezing | dagger ego:flaming | \ + dagger ego:electrocution : end KITEM: B = any book KITEM: | = staff of fire / staff of cold / staff of earth / staff of air diff --git a/crawl-ref/source/dat/icecave.des b/crawl-ref/source/dat/icecave.des index c5d1f55f63..fe5ee6868a 100644 --- a/crawl-ref/source/dat/icecave.des +++ b/crawl-ref/source/dat/icecave.des @@ -330,10 +330,10 @@ ITEM: potion of resistance w:5 / potion of gain strength / \ potion of might / potion of confusion / potion of levitation / \ potion of experience w:2 MAP - xxxx xxxxxxxx - xxxx..xxxx xxxx12....xx - xxxxxxxx...xx...xxxx...2xxx...xxxx - xxxx......1..xxxxx..x212.xxxxxxx...1xxxx + xxxxx xxxxxxxx + xxx...xxxx xxxx12....xx + xxxxxxxx...x....xxxx...2.x....xxxx + xxxx......1..xxxx...x212.xxxxxxx...1xxxx xx.......1..1.xxxxxx....xxxxxxxxxxxx21..xxx xxx...xxxx.3.1....xxxxxxxxxxxxxwwwxxxxxx....xxx xx...xxxfgxx.1..1...xxxxxxxxxxwwwwwxxxxxxxx....xxx @@ -342,34 +342,34 @@ MAP x...x....$$xx.....xxxxwwwwxxwwwwwwwwwwwwxxxxxx11xx xx.......xxx.....xxwwwwxxxxxxxxxwwwwwwxxxxx...2xx xx............xxxwwwwxxxxxxxxxxxwwwxxxx......xx - xxx"xx.........x'wwwwwxxxxxxxxxxxxwxxxx...xxxxxx -xxwwxxxxxxxxxxxxxxwwwxxxxxxxxxxxxxxxxxx..xxx + xxx"xx.........x'wwwwwxxxxxxxxxxxxwxxxx...x.xxxx +xxwwwxxxxxxxxxxxxxwwwxxxxxxxxxxxxxxxxxx..xxxxx xxwwwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxxxx..xx - xwwwwwwwwwwwwwwwwwx'xxxxxxxxxxxxxxx5...xxx + xwwwwwwwwwwwwwwwww''xxxxxxxxxxxxxxx5...xxx xwwwxxxxxxxxxxwwxx'x'xxxxxxxxxxxxx.......xxx -xxwwxxxxxxxxxxxwwxxx'xxxxxxxxxxxxxxxx.......xxx -x"xxxxxxxxxxxxxxwxx'xxxxxx"xxxxxxxxxxx....2...xx -xx"xxxxxxxxxxxxxxx'xxxxxxx""""x..xxxxxxx2......x - xx"xxxxxxxxxxxxx'xxxxxxx"xxxx.......xxx.......x - x"xxxxxxxxxxxxx''xxxxx"xxx''xx......21x.....xx - xx""xxxxxxxxxxxxx'xxx"xxx'xxxxx....1..2....xx - xxx""""xxxxxxxxxx'xx"xxx'xxwwxx.1......1.xx - xxxxx"xxxxxxxxx'xxx"xxx'xxwwxx.x....x.xx - xxx"xxxxxxxxx'xxx"xxxxx'xxwwxxxx..xxxx - xx""xxxxxxxxx'xxx"xxxxxx'xxxwwxxx..x - xx"xxxxxxxxxxx''xxx"xxxxxx'xxwwxx..xx - xx"xxxxxxxxxxxxx'xxxx""xxxx'xxwxx..xx - xx"xxxxxxxxxxxxxxx'xxxx"xxx'xxxwwx...xx - x"xxxxxxxxxxxxxxxxx'xxxx"x'xxxxwwxx...xx - x"xxxxxxxxxxxxxxxxx'xxxxx2xxxxxwwxxx44.x - xx"xxxxxxxxxxxxxxxxx'x..x.xxxxxwwxxxx4.4x - x"xxxxxxxxxxxxxxxxxxx.hx.xxxxxxwwxxx...xx -xx"xxxxxxxxxxxxxxxx.1xhxhx.xxxxwwwxxx...xx -x"xxxxxxxxxxxxxxxxx.xhxhxh.xxxwwwxxx.....xx -xx"xxxxxxxxx"xxxxxxx1.....xx xxwwxx...A...x - xx"""xxx"""x""xxx""xxxxxxx xwwxx.......x - xxxx"""xxxxxx"""xxx xxwwxxx..<..xx - xxxxx xxxxx xwwwx xx...xx +xxwwxxxxxxxxxxxwwxxx'xxxxxxx"xxxxxxxx.......xxx +x""xxxxxxxxxxxxxwxx''xxxxx"""xxxxxxxxx....2...xx +xx""xxxxxxxxxxxxxx''xxxxxx"""""..xxxxxxx2......x + xx""xxxxxxxxxxxx'x'xxxx"""xxx.......xxx.......x + x"x"xxxxxxxxxxx''xxxxx"xx'''xx......21x.....xx + xx"""xxxxxxxxxxx''xxx""x''x'''x....1..2....xx + xxx""""xxxxxxxxx''xx"xx''xxwwxx.1......1.xx + xxx"x"xxxxxxxxx'xx""xx''xxwwxx.x....x.xx + xxx"xxxxxxxxx''x""xxxx''xxwwxxxx..xxxx + xx"""xxxxxxxx'x'x"x"xxxx''xxwwxxx..x + xx""xxxxxxxxxx''xxx"x"xxxx''xwwxx..xx + xx""x"xxxxxxxxxx''xxx""xxx''xxwxx..xx + xx""x"xxxxxxxxxxxx'xxxx""x''xxxwwx...xx + x""xxxxxxxxxxxxxx'x'xxxx""'xxxxwwxx...xx + x"x"xxxxxxxxxxxxxx'''xxxx2'xxxxwwxxx44.x + xx""xxxxxxxxxxxxxxxx'x..x.'xxxxwwxxxx4.4x +xx""xxxxxxxxxxxxxxxxxx.hx.xxxxxxwwxxx...xx +x""xxxxxxxxxxxxxxxx.1xhxhx.xxxxwwwxxx...xx +x"x"xxxxxxxxxxxxxxx.xhxhxh.xxxwwwxxx.....xx +xx"x"xxxx""x"xxxxxx"1.....xx xxwwxx...A...x + xx""""x""""x""x""""xxxxxxx xwwxx.......x + xxxx"""xxx"x""""xxx xxwwxxx..<..xx + xxxxx xxxxxxxx xwwwx xx...xx xxwxx xxxxx xxx ENDMAP @@ -395,37 +395,37 @@ ITEM: any jewellery good_item / gold w:5 / nothing w:5 MAP xxxxxxxx xxxx......xxxx - xx.....xxx....xxx - x..xxxxxxx...2..xxx - xxxx.xxxx$$.2....dexx - xx..xx.xx$$$$....deddx - xx.xx..xx$$$$$$..deddxx - xx..xxxxxxxx$$$$$$$xxx'x - xxxx11xxxxwwwxxxxxxxxxxwx'x - xxxx...1xxwwwwwwwwwwwwwwwwwwxxx + xx......x.....xxx + x...xx.xxx...2..xxx + xxxxx..xxx$$.2....dexx + xx...xx.xx$$$$....deddx + xx.x....x$$$$$$..deddxx + xx..xxx.xxxx$$$$$$$xx''x + xxxx11xxxxxxwxxxxxxxxxxwx'x + xxxx...1xxwwwwwwwwwwwwwwwwwwwxx xxx......xxwwwwwwwwwwwwwwwwwwwwwxx xx...xxxxxxxxwwwwwwwwwxxwwwwwwwwwwx xx..xxxxxxxxxxxxwwwwwxxxxxxxx'xwwxxx - xxx..xxxxxxxxxxxxxxxxxxxxxxxxx.xxwwwx - xxx....xxxxxxxxxxxxxxxxxxx"""x..$$xxwxx - xx........xxxxxxxx""xxxxx""xxx.xxx$xxxx - xx...........xxxxx"xx""x""xxxxxx'xxx"xx -xx..............x""xxxxx"xxxxxxxxx'xxx"x -x................xxxxxxxxxxxxxxxxxx'xx"xx -x.................xxxxxxxxxxxxxxxxxx'xx"x -xx...1.111.1....xx'xxxxxxxxxxxxxxxxx'xx"x - xx...1.1.1.....xxx'xxx''xxxxx''x'x'xx"xx - xx..........xxxxxx'''xx'xxx'xx'x'xx"xx - xx4x....x4xxxxxxxxxxxxx''$xxxxxxx"xx - xxxx..xxxxxxxxxxxxxxxxx$$$xxxx""xx - xx..xxxxxxxxxxxxxx"xx$$$$xx"xxx - xx..xxxxxxxxxxxxxx"x""x$$"xxx"x - x..xxxxxxxxxxxxxxx"xxxxxxx"x"xx - x...x""x"xxxxxxxxxx"xx xx"xx - xx...xx"x""xxxxxxxxx"x xxx - xx33.xxxxx""xxxxx""xx - xx3.3x xxx"""x"xxx - x...xx xxxx"xx + xxx..xxxxxxxxxxxxxxxxxxxxxxxxx..xwwwx + xxx....xxxxxxxxxxx"xxxxxx""""x..$$xxwxx + xx........xxxxxxxx"""x"x"""x"x.'xx$xxxx + xx...........xxxx"""x""x""xxxx"x''xx""xx +xx..............x""xxxxx"xxxxxxxxx''xx""xx +x................xxxxxxxxxxxxxxxxxx''x"x"x +x.................xxxxxxxxxxxxxxxxxx'xx"xx +xx...1.111.1....x'''xxxxxxxxxxxxxx'''x""x + xx...1.1.1.....xxx''xx''xxxx'''x'x'xx"xx + xx..........xxxxxx''''x''x''x''''xx""x + xx4x....x4xxxxxxxx'xxxx''$xxxxxx"""xx + xxxx..xxxxxxxxxxxxxxxxx$$$xxx""""xx + xx..xxxxxxxxxxxxx"""x$$$$xx"x"xx + xx..xxxxxxxxxxxxxx"x""x$$""xx"xx + x..xxxx"xxxxxxxxx""xxxxxxx""""x + x...x""x""xxxxxxxx"""x xx"xxx + xx..."x"x"""xxxxx"xx"x xxx + xx33.xxxxx"""x"xx""xx + xx3.3x xxx""""""xx + x...xx xxxx"xxx xx...xx xxx xx.....xx x...A...x @@ -504,12 +504,12 @@ x...xxffxx...xxxxx*%....3.3..xwwwwwxx6.6x x....xxxx...xxxxxxxxx.......xxxwwwxx...xx xxx.........xxxxxxxxxxx...xxxxwwwxxx...xx x...7....xxxxxxxxxxxxx..xxxwwwxxx.....xx - xx------xxxxxxxxxxxxxxxx..xxwwxx...A...x - xx----xxxxxx...xxxxxxxx...xwwxx.......x - x---xxxx...xx...xx.....xxxwwxxx..<..xx + xx------xxxxx.xxxxxxxxxx..xxwwxx...A...x + xx----xxxxx....xxxxx..x...xwwxx.......x + x---xx.x...xx....x.....xxxwwxxx..<..xx xx.......xxxxxx....xxxxxxwwwwxxx...xx - xxxxxxxxx xxxxxx xxwwwxxxxxxx - xwwxx + xxx.xx.xx xxxxxx xxwwwxxxxxxx + xxxxxxx xwwxx xxxx ENDMAP @@ -605,21 +605,21 @@ NAME: ice_cave_tombish # This is an ice cave which is also a tomb of a necromancer who likes staying # alive and simulacrums, or just a chillout of an ice fiend. By Zaba. # Weighted as a small cave, although this is pretty tough. --Eino -TAGS: ice_cave no_item_gen no_monster_gen +TAGS: ice_cave no_item_gen no_monster_gen ORIENT: encompass WEIGHT: 6 # S is either an ice statue or a granite statue. -SUBST: S = GGS -KMONS: S = ice statue +SUBST: S = GGS +KMONS: S = ice statue # I is an ice statue with loot underneath. -KITEM: I = any scroll q:3 -KMONS: I = ice statue -MONS: ice devil / blue devil / nothing w:7 +KITEM: I = any scroll q:3 +KMONS: I = ice statue +MONS: ice devil / blue devil / nothing w:7 # FIXME: I can't quite make up more simulacrums -MONS: grizzly bear simulacrum / bear simulacrum / dragon simulacrum /\ - human simulacrum / golden dragon simulacrum w:1 -MONS: Ice Fiend w:2 / necromancer -ITEM: any potion / any scroll / any weapon good_item / any armour good_item +MONS: grizzly bear simulacrum / bear simulacrum / dragon simulacrum /\ + human simulacrum / golden dragon simulacrum w:1 +MONS: ice fiend w:2 / necromancer +ITEM: any potion / any scroll / any weapon good_item / any armour good_item KFEAT: ' = alarm trap / net trap / arrow trap / bolt trap w:5 / floor w:5 : ice_cave_colours(_G) : ice_cave_milestone(_G) diff --git a/crawl-ref/source/dat/mini.des b/crawl-ref/source/dat/mini.des index e08d81b994..b27857e9fc 100644 --- a/crawl-ref/source/dat/mini.des +++ b/crawl-ref/source/dat/mini.des @@ -774,6 +774,27 @@ cccccccccc ENDMAP ################################### +# This wizard likes to experiment! +# +NAME: laboratory_2 +MONS: col:lightred wizard spells:polymorph_other;paralyse;blink\ + ;bolt_of_fire;bolt_of_fire;teleport_self +DEPTH: D:10-26, Vault +MONS: col:red name:altered name_adjective rat spells:fire_breath +MAP +ccccccc+cc +c........c +c........c +c..1.....c +c........c +cc+ccccccc +c***c2222c +c|**+2222c +c||*c2222c +cccccccccc +ENDMAP + +################################### # Beehive minivault # NAME: minivault_7 @@ -2627,3 +2648,15 @@ MAP ............. ............. ENDMAP + +############################################################################## +# Hunter's Booth (1KB) +# +NAME: hunters_booth +DEPTH: D:5-15 +MONS: centaur, bush +MAP +.....xxx +@....21=@ +.....xxx +ENDMAP diff --git a/crawl-ref/source/dat/pan.des b/crawl-ref/source/dat/pan.des index 64503836f3..8ccf336169 100644 --- a/crawl-ref/source/dat/pan.des +++ b/crawl-ref/source/dat/pan.des @@ -548,9 +548,13 @@ ENDMAP NAME: pan_disco_hall TAGS: pan no_rotate ORIENT: float -COLOUR: . = random -COLOUR: x = random -MONS: col:random plant +SUBST: - = 0:1 / .:10 +COLOUR: .x = random +COLOUR: 0123456789 = random +MONS: col:random name:demonic name_adjective plant +MONS: red devil ; demon trident good_item ego:distortion +MONS: red devil ; lajatang good_item ego:distortion +MONS: red devil ; katana good_item ego:distortion RTILE: x = wall_zot_blue / wall_zot_green / wall_zot_cyan / wall_zot_red /\ wall_zot_magenta / wall_zot_yellow # alas, floor tiles are not distinguished from walls enough, commenting out: @@ -563,19 +567,19 @@ MAP x1.1x x...x xxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxx - x........................x...............x - x.x.x.x.x.x.x.x.x.x.x.x..x...............x - x........................x...............xxxxxx - x.x.x.x.x.x.x.x.x.x.x.x..x..............._....x -xxxx........................................_....x -x1.x........................................_....x -@..........................................._....x -x1.x........................................_....x -xxxx........................................_....x - x.xxxxxxxxxxxxxxxxxxxxx..x..............._....x - x.x...x...x...x...x...x..x...............xxxxxx - x.x...x...x...x...x...x..x...............x - x........................x...............x + x........................x---------------x + x.x.x.x.x.x.x.x.x.x.x.x..x---------------x + x........................x---------------xxxxxx + x.x.x.x.x.x.x.x.x.x.x.x..x---------------_....x +xxxx.........................---------------_..2.x +x1.x.........................---------------_....x +@............................---------------_..3.x +x1.x.........................---------------_....x +xxxx.........................---------------_..4.x + x.xxxxxxxxxxxxxxxxxxxxx..x---------------_....x + x.x0.0x..0x0.0x0.0x..0x..x---------------xxxxxx + x.x0..x0..x...x0..x...x..x---------------x + x........................x---------------x xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ENDMAP diff --git a/crawl-ref/source/dat/shrine.des b/crawl-ref/source/dat/shrine.des deleted file mode 100644 index c1e6d8b402..0000000000 --- a/crawl-ref/source/dat/shrine.des +++ /dev/null @@ -1,406 +0,0 @@ -############################################################################### -# Shrines.des: -# The shrines are thematic portal vaults which offer early religion in -# exchange for one's safety. -############################################################################### -# Setup functions: -{{ -function shrine_portal_setup (e) - e.lua_marker("O", one_way_stair { desc = "An entrance to a Shrine", - dst = "shrine" }) - e.kfeat("O = enter_portal_vault") -end - -function shrine_setup(e) - e.kfeat("> = exit_portal_vault") - crawl.mark_milestone("br.enter", "entered a Shrine.") -end -}} -############################################################################### -# Entry vaults: -default-depth: D:2-6 - -NAME: shrine_entry_a -TAGS: luniq_shrine -ORIENT: float -: shrine_portal_setup(_G) -MAP -x x -x.T.x -x...x -@.O.@ -x...x -x.T.x -x x -ENDMAP - -NAME: shrine_entry_b -TAGS: luniq_shrine -ORIENT: float -: shrine_portal_setup (_G) -MAP - x x - xx.xx -xx...xx - ..O..@ -xx...xx - xx.xx - x x -ENDMAP - -NAME: shrine_entry_c -TAGS: uniq_shrine -ORIENT: float -: shrine_portal_setup (_G) -MAP -....... -.x...x. -......@ -...O..@ -......@ -.x...x. -....... -ENDMAP - -############################################################################### -# The portals themselves. -default-depth: - -NAME: shrine_yred_kiku_a -WEIGHT: 5 -TAGS: shrine no_item_gen no_monster_gen no_pool_fixup -ORIENT: encompass -SHUFFLE: XY -KFEAT: X = altar_yredelemnul -KFEAT: Y = altar_kikubaaqudgha -NSUBST: M = 2:. / *:M -SUBST: M = 1 2 3:5 4:5 -NSUBST: N = 4:. / *:N -SUBST: N = 1 2 3:15 4:15 -SUBST: . = ZZ. -COLOUR: Z = darkgrey -SUBST: Z = . -COLOUR: x = darkgrey -MONS: place:D:4 zombie, place:D:5 skeleton, place:D:6 zombie, \ - place:D:7 skeleton -ITEM: any wand w:5 / wand of enslavement / q:1-3 any scroll w:2 \ - / scroll of torment w:2 -: shrine_setup(_G) -MAP - xxxxxxx - xx.....xx - x..NYN..x - x..NNN..x -xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx..T..xxxxx -xwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwW...Wwwwwx -xwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwW.d.Wwwwwx -xwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwW...Wwwwwx -xwwww.......................................wwwwx -xwwww..A.>.G.M.G.M.G.M.G.M.G.M.G.M.G.M.M....wwwwx -xwwww.......................................wwwwx -xwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwW...Wwwwwx -xwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwW.d.Wwwwwx -xwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwW...Wwwwwx -xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx..T..xxxxx - x..NNN..x - x..NXN..x - xx.....xx - xxxxxxx -ENDMAP - -NAME: shrine_yred_kiku_b -WEIGHT: 5 -TAGS: shrine no_item_gen no_monster_gen no_pool_fixup -ORIENT: encompass -SHUFFLE: XY -SHUFFLE: A> -KFEAT: X = altar_yredelemnul -KFEAT: Y = altar_kikubaaqudgha -NSUBST: . = 8:M / *:. -SUBST: M = 12 -NSUBST: H = 2:N / 3:M / *:. -SUBST: N = 34 -MONS: place:D:4 zombie, place:D:5 skeleton -MONS: place:D:6 zombie, place:D:6 skeleton -SUBST: S = . -SUBST: . = .ZZ -COLOUR: Z = darkgrey -SUBST: Z = . -COLOUR: x = darkgrey -ITEM: any wand w:5 / wand of enslavement / q:1-3 any scroll w:2 / \ - scroll of torment w:2 -: shrine_setup(_G) -MAP -xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -x.............SSSx............x -x............SSSSx............x -x...........SSSSSx............x -x...xxxxxxxxxxSSSx...xxxxxx...x -x...xHHH.....xS>Sx.....HHHx...x -x...xHXH.d...xSSSx...d.HYHx...x -x...xHHH.....xSASx.....HHHx...x -x...xxxxxx...xSSSxxxxxxxxxx...x -x............xSSSSS...........x -x............xSSSS............x -x............xSSS.............x -xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -ENDMAP - -NAME: shrine_makh_vehu_a -WEIGHT: 5 -TAGS: shrine no_item_gen no_monster_gen no_pool_fixup -ORIENT: encompass -SHUFFLE: YZ -KFEAT: Y = altar_vehumet -KFEAT: Z = altar_makhleb -MONS: imp / shadow imp / white imp -NSUBST: M = 5:1 / *:. -ITEM: tome of destruction / q:1-3 scroll of summoning / q:2-3 \ - scroll of immolation / q:1-3 any scroll / wand of flame w:5 / \ - wand of frost w:5 / wand of lightning w:5 / any wand w:3 -: shrine_setup(_G) -MAP -xxxxxxxxxxxxxxxxxxxxxxxxxxxxx -x.........www.........www...x -x........Mwww..M......www.Z.x -x...www...www...www...www...x -x...www...www...www...wwwMY.x -x...www...www...www...www...x -x...www...www...wwwM..www.d.x -x.A.www...www...www...www...x -x...www...www.M.www...www...x -x.>.www...M.....www....M....x -x...www.........www.........x -xxxxxxxxxxxxxxxxxxxxxxxxxxxxx -ENDMAP - -NAME: shrine_makh_vehu_b -WEIGHT: 5 -TAGS: shrine no_item_gen no_monster_gen no_pool_fixup -ORIENT: encompass -SHUFFLE: XY -KFEAT: X = altar_makhleb -KFEAT: Y = altar_vehumet -MONS: neqoxec -ITEM: tome of destruction / q:1-3 scroll of summoning / q:2-3 \ - scroll of immolation / q:1-3 any scroll / wand of flame w:5 / \ - wand of frost w:5 / wand of lightning w:5 / any wand w:3 -: shrine_setup(_G) -MAP - xxxxx - xx...xx - xx.....xx - xx...w...xx -xx.Y.www.A.xx -x...wcncw...x -xd.wwn1nww..x -x...wcncw...x -xx.X.www.>.xx - xx...w...xx - xx.....xx - xx...xx - xxxxx -ENDMAP - -NAME: shrine_good -TAGS: shrine no_item_gen no_monster_gen -ORIENT: encompass -SHUFFLE: XYZ -KFEAT: X = altar_shining_one -KFEAT: Y = altar_elyvilon -KFEAT: Z = altar_zin -COLOUR: a = darkgrey / red / blue w:3 / lightred w:2 -COLOUR: b = darkgrey / red w:5 / lightgrey w:1 / blue w:3 / cyan w:1 / \ - lightred w:1 -COLOUR: c = darkgrey w:7 / red w:2 / lightgrey w:4 / blue w:4 / cyan w:2 -COLOUR: d = darkgrey w:4 / lightgrey w:4 / blue / cyan w:4 -COLOUR: e = blue / cyan w:4 -COLOUR: f = blue / cyan w:7 -SUBST: abcdef = w -SUBST: G = ...BBC -NSUBST: H = 2:C / *:H -SUBST: H = .BBCCC -COLOUR: B = white -COLOUR: C = yellow -SUBST: B = . -NSUBST: C = 3:M / 3:d / *:. -ITEM: any scroll / scroll of holy word -MONS: human; falchion / human; falchion ego:holy_wrath w:1 \ - / human; quarterstaff / human; quarterstaff ego:holy_wrath w:1 \ - / human -MONS: gnoll; falchion / gnoll; falchion ego:holy_wrath w:1 / gnoll; \ - quarterstaff / gnoll; quarterstaff ego:holy_wrath w:1 / gnoll -MONS: orc; falchion / orc; falchion ego:holy_wrath w:1 \ - / orc; quarterstaff / orc; quarterstaff ego:holy_wrath w:1 / orc -SUBST: M = 1222333 -: shrine_setup(_G) -MAP - xxxxxxxxxxxxx - xxaaaaaaaaaaaxx - xxbbbbbbbbbbbbbxx - xxcccccccccccccccxx - xxdddddddddddddddddxx - xxeeeeeeeeeeeeeeeeeeexx -xxxxxxxxxxxxfffffffffffffffffffffxx -x..........GGGGGGHHHHHHHHHHHGGGGGGxx -x.>.A.....GGGGGGHHHXHHYHHZHHHGGGGGGx -x..........GGGGGGHHHHHHHHHHHGGGGGGxx -xxxxxxxxxxxxfffffffffffffffffffffxx - xxeeeeeeeeeeeeeeeeeeexx - xxdddddddddddddddddxx - xxcccccccccccccccxx - xxbbbbbbbbbbbbbxx - xxaaaaaaaaaaaxx - xxxxxxxxxxxxx -ENDMAP - -NAME: shrine_trog_oka -TAGS: shrine no_item_gen no_monster_gen -ORIENT: encompass -SHUFFLE: YZ -KFEAT: Y = altar_okawaru -KFEAT: Z = altar_trog -MONS: moth of wrath -MONS: orc warrior; nothing w:15 / orc warrior / orc; nothing -ITEM: any weapon -NSUBST: M = 8:d / *:. -: shrine_setup(_G) -MAP - xxxxxxx - xxxMMMxxx - xxMMM2MMMxx - xxMMY...ZMMxx - xx.........xx - x....ooo....x - x...oo1oo...x - x....ooo....x - x...........x - xx...A.>...xx - xx.......xx - xxx...xxx - xxxxx -ENDMAP - -NAME: shrine_xom_nemelex -TAGS: shrine no_item_gen no_monster gen -ORIENT: encompass -SHUFFLE: XY -KFEAT: X = altar_xom -KFEAT: Y = altar_nemelex_xobeh -MONS: orc; club ego:chaos / orc; dagger ego:chaos / orc; spear ego:chaos -MONS: gnoll; club ego:chaos / gnoll; dagger ego:chaos \ - / gnoll; spear ego:chaos -MONS: place:D:1-8 -NSUBST: . = 1:X / 1:Y / *:. -SUBST: . = ....................~~~~~~~WWWWWWwwwwwxxxxxxxxvnnnnnnnnbvlZTUMM -SUBST: Z = **%%%| -SUBST: M = 123333. -SUBST: S = ...W -SUBST: R = ....................~~~~~~~WWWWWWwwwwwxxxxxxxxvnnnnnnnnbvlTU -COLOUR: . = random -: shrine_setup(_G) -MAP - xxxxxxxxxxxxxxxxxxxxxxxxxxxxx - xx...........................xx - xx.............................xx -xx...............................xx -x.................................x -x.................................x -x.................................x -x...............RRR...............x -x..............RRARR..............x -x..............RRSRR..............x -x...............RSR...............x -x..............RRSRR..............x -x..............RR>RR..............x -x...............RRR...............x -x.................................x -x.................................x -x.................................x -xx...............................xx - xx.............................xx - xx...........................xx - xxxxxxxxxxxxxxxxxxxxxxxxxxxxx -ENDMAP - -NAME: shrine_sif -TAGS: shrine no_item_gen no_monster_gen no_pool_fixup -ORIENT: encompass -KFEAT: X = altar_sif_muna -MONS: orc wizard w:15 / Jessica / Blork the Orc -NSUBST: M = 2:1 / *:. -SUBST: . = ..Z -COLOUR: Z = blue -SUBST: Z = . -ITEM: potion of gain intelligence / q:2 potion of gain intelligence w:5 \ - / q:2 potion of magic / any book w:2 / nothing -: shrine_setup(_G) -MAP - xxxxx - x...x - x.A.x - xxx...xxx - xx...>...xx - xx.........xx - x....www....x - xx...wwwww...xx - x...wwM.Mww...x - x...WWMMMWW...x - x...wwMMMww...x - xx...wwwww...xx - x....www....x - xx.........xx - xx..d.d..xx - xxx...xxx - x.X.x - x...x - xxxxx -ENDMAP - -NAME: shrine_fedhas -TAGS: shrine no_item_gen no_monster_gen -ORIENT: encompass -KFEAT: X = altar_fedhas -MONS: plant, fungus, oklob plant -SUBST: . = .F -COLOUR: F = green -SUBST: F = . -NSUBST: w = 2:Z / *:w -KFEAT: Z = w -KMONS: Z = big fish -SUBST: x = xxxV -COLOUR: V = green -SUBST: V = x -SUBST: x = xx11122. -SUBST: y = x -SUBST: d = dd. -SHUFFLE: A> -SUBST: 6 = 112 -ITEM: apple / apricot / orange / pear / grape / sultana \ - / strawberry / nothing w:30 -: shrine_setup(_G) -MAP -yyyyyyyyyyyyyyyyyyyyyyy -yxxxxxxxxxxxxxxxxxxxxxy -yxxxxxxxxxxxxxx6xxd3xxy -yxxxxxxxxxxxxxx6ddddxxy -yxxxxxxxxxxxxxx666x.dxy -yxxxxxxx.......xx66xxxy -yxxxxxx..wwdww..xx66xxy -yxxxxx..wwwdwww..xxx6xy -yxxxx..wwwwdwwww..xxxxy -yxxxx.wwwwwdwwwww.xxxxy -yxxxx.wwwwFFFwwww.xxxxy -yxxxx.wwwwFXFwwww.xxxxy -yxxxx.wwwwFFFwwww.xxxxy -yxxxx.wwwwwwwwwww.xxxxy -yxxxx..wwwwwwwww..xxxxy -yxxxxx..wwwwwww..xxxxxy -yxxxxxx..wwwww..xxxxxxy -yxxxxxxx..A.>..xxxxxxxy -yxxxxxxxxxxxxxxxxxxxxxy -yxxxxxxxxxxxxxxxxxxxxxy -yxxxxxxxxxxxxxxxxxxxxxy -yxxxxxxxxxxxxxxxxxxxxxy -yyyyyyyyyyyyyyyyyyyyyyy -ENDMAP diff --git a/crawl-ref/source/dat/temple.des b/crawl-ref/source/dat/temple.des index 840a89dea7..64a59bcf4b 100644 --- a/crawl-ref/source/dat/temple.des +++ b/crawl-ref/source/dat/temple.des @@ -382,6 +382,12 @@ ENDMAP # Temple maps ############################################################################## +# To make a main temple (Ecumenical Temple branch) vault with an +# arbitrary number of altars, give it the tag "temple_main_N", where +# N is the number of altars. If no vaults are found for the specific +# number of altars, then the game will pick a random vault for +# "PLACE: Temple". + ########################################################################## # Circular temple (David Ploog). 12 = 1 x 12 @@ -461,6 +467,7 @@ NAME: twelve_chambers_temple PLACE: Temple TAGS: no_rotate ORIENT: encompass +WEIGHT: 5 MAP xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvxx @@ -491,6 +498,44 @@ xvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ENDMAP +############################################################################## +# Fourteen chambers temple (David Ploog). 14 = 14 x 1 + +NAME: fourteen_chambers_temple +PLACE: Temple +TAGS: no_rotate +ORIENT: encompass +WEIGHT: 5 +MAP +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +xvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvxx +xvvvvvvvvvvv..........................................vvvvvvvvvxx +xvvvvvvv.....vvv.vvvvvvv.vvvvvvv.vvvvvvv.vvvvvvv.vvvv.....vvvvvxx +xvvvvv...vvvvv.....vvv.....vvv.....vvv.....vvv.....vvvvvv...vvvxx +xvvvvv.vvvvvv...B...v...B...v...B...v...B...v...B...vvvvvvv.vvvxx +xvv.....vvvvv.......v.......v.......v.......v.......vvvvv.....vvx +xv.......vvvvv.....vvv.....vvv.....vvv.....vvv.....vvvvv.......vx +xv..B....vvvvvvv.vvvvvvv.vvvvvvv.vvvvvvv.vvvvvvv.vvvvvvv....B..vx +xv........vvvvvv.vvvvvvv.vvvvvvv.vvvvvvv.vvvvvvv.vvvvvv........vx +xvv.....v..vvvvv.vvvvvvv.vvvvvvv.vvvvvvv.vvvvvvv.vvvvv..v.....vvx +xvvvv.vvvv.............................................vvvv.vvvvx +xvvv..vvvv.............................................vvvv..vvvx +xvvv.vvvvv........T.........(...{...[.........T........vvvvv.vvvx +xvvv..vvvv.............................................vvvv..vvvx +xvvvv.vvvv.............................................vvvv.vvvvx +xvv.....v..vvvvv.vvvvvvv.vvvvvvv.vvvvvvv.vvvvvvv.vvvvv..v.....vvx +xv........vvvvvv.vvvvvvv.vvvvvvv.vvvvvvv.vvvvvvv.vvvvvv........vx +xv..B....vvvvvvv.vvvvvvv.vvvvvvv.vvvvvvv.vvvvvvv.vvvvvvv....B..vx +xv.......vvvvv.....vvv.....vvv.....vvv.....vvv.....vvvvv.......vx +xvv.....vvvvv.......v.......v.......v.......v.......vvvvv.....vvx +xvvvvv.vvvvvv...B...v...B...v...B...v...B...v...B...vvvvvv.vvvvxx +xvvvvv...vvvvv.....vvv.....vvv.....vvv.....vvv.....vvvvv...vvvvxx +xvvvvvvv.....vvv.vvvvvvv.vvvvvvv.vvvvvvv.vvvvvvv.vvv.....vvvvvvxx +xvvvvvvvvvvv.........................................vvvvvvvvvvxx +xvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvxx +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +ENDMAP + ########################################################################## # Another temple (David Ploog). 12 + 3 = 1 + 2 + 3 + 4 + 5 @@ -558,7 +603,7 @@ xcwww......B.............................B......wwwcx xcwww.............B...............B.............wwwcx xcww......................(......................wwcx xcww.............................................wwcx -xcww...B..................T..................B...wwcx +xcww...B......B...........T...........B......B...wwcx xcww.............................................wwcx xcww...................[.....{...................wwcx xcwww.............B...............B.............wwwcx @@ -660,65 +705,66 @@ ENDMAP ########################################################################## # Five rooms temple (David Ploog). 12 + 3 = 5 x 3 -NAME: five_temple -PLACE: Temple -TAGS: no_rotate -ORIENT: encompass -SHUFFLE: ABC/DEF/GHI/JKL/MNO -SHUFFLE: ABC, DEF, GHI, JKL, MNO -SUBST: A=[, B=(, C={ -KFEAT: D = altar_trog -KFEAT: E = altar_makhleb -KFEAT: F = altar_okawaru -KFEAT: G = altar_shining_one -KFEAT: H = altar_zin -KFEAT: I = altar_elyvilon -KFEAT: J = altar_sif_muna -KFEAT: K = altar_vehumet -KFEAT: L = altar_kikubaaqudgha -KFEAT: M = altar_yredelemnul -KFEAT: N = altar_xom -KFEAT: O = altar_nemelex_xobeh -KFEAT: X : G / U / T -MAP -xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -xxxxxxxxxxxxxxxxxxxx.......xxxxxxxxxxxxxxxxxxxx -xxxxxxxxxxxxxxx........x........xxxxxxxxxxxxxxx -xxxxxxxxxx........xxxxx+xxxxx........xxxxxxxxxx -xxxxxxx.....xxxxxxxxx.....xxxxxxxxx.....xxxxxxx -xxxxxx...xxxxxxxxxx.........xxxxxxxxxx...xxxxxx -xxxxx..xxxxxxxxxxx..A.....C..xxxxxxxxxxx..xxxxx -xxxx..xxxxxxxxxxxx.....X.....xxxxxxxxxxxx..xxxx -xxx..xxxxxxxxxxxxx...........xxxxxxxxxxxxx..xxx -xxx..xxx.....xxxxxx....B....xxxxxx.....xxx..xxx -xx..+x..O......xxxxxx.....xxxxxx......F..x+..xx -xx..x...........xxxxxxxxxxxxxxx...........x..xx -x..xx.....X..N..xxxxxxxxxxxxxxx..D..X.....xx..x -x..xx...........xxxxxxxxxxxxxxx...........xx..x -x..xxx..M......xxxxxxxxxxxxxxxxx......E..xxx..x -x..xxxxx.....xxxxxxxxxxxxxxxxxxxxx.....xxxxx..x -x..xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx..x -x..xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx..x -x..xxxxxxxxxx.....xxxxxxxxxxx.....xxxxxxxxxx..x -xx..xxxxxxx......K..xxxxxxx..G......xxxxxxx..xx -xx..xxxxxx.L.........xxxxx.........H.xxxxxx..xx -xxx..xxxxx.....X.....xxxxx.....X.....xxxxx..xxx -xxx..xxxxx...........xxxxx...........xxxxx..xxx -xxxx..xxxxx......J..xxxxxxx..I......xxxxx..xxxx -xxxxx..xxxxxx.....xxxxxxxxxxx.....xxxxxx..xxxxx -xxxxxx...xxx+xxxxxxxxxxxxxxxxxxxxx+xxx...xxxxxx -xxxxxxxx....xxxxxxxxxxxxxxxxxxxxxxx....xxxxxxxx -xxxxxxxxxx........xxxxxxxxxxx........xxxxxxxxxx -xxxxxxxxxxxxxxx........x........xxxxxxxxxxxxxxx -xxxxxxxxxxxxxxxxxxxx.......xxxxxxxxxxxxxxxxxxxx -xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -ENDMAP +#NAME: five_temple +#PLACE: Temple +#TAGS: no_rotate +#ORIENT: encompass +#SHUFFLE: ABC/DEF/GHI/JKL/MNO +#SHUFFLE: ABC, DEF, GHI, JKL, MNO +#SUBST: A=[, B=(, C={ +#KFEAT: D = altar_trog +#KFEAT: E = altar_makhleb +#KFEAT: F = altar_okawaru +#KFEAT: G = altar_shining_one +#KFEAT: H = altar_zin +#KFEAT: I = altar_elyvilon +#KFEAT: J = altar_sif_muna +#KFEAT: K = altar_vehumet +#KFEAT: L = altar_kikubaaqudgha +#KFEAT: M = altar_yredelemnul +#KFEAT: N = altar_xom +#KFEAT: O = altar_nemelex_xobeh +#KFEAT: X : G / U / T +#MAP +#xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +#xxxxxxxxxxxxxxxxxxxx.......xxxxxxxxxxxxxxxxxxxx +#xxxxxxxxxxxxxxx........x........xxxxxxxxxxxxxxx +#xxxxxxxxxx........xxxxx+xxxxx........xxxxxxxxxx +#xxxxxxx.....xxxxxxxxx.....xxxxxxxxx.....xxxxxxx +#xxxxxx...xxxxxxxxxx.........xxxxxxxxxx...xxxxxx +#xxxxx..xxxxxxxxxxx..A.....C..xxxxxxxxxxx..xxxxx +#xxxx..xxxxxxxxxxxx.....X.....xxxxxxxxxxxx..xxxx +#xxx..xxxxxxxxxxxxx...........xxxxxxxxxxxxx..xxx +#xxx..xxx.....xxxxxx....B....xxxxxx.....xxx..xxx +#xx..+x..O......xxxxxx.....xxxxxx......F..x+..xx +#xx..x...........xxxxxxxxxxxxxxx...........x..xx +#x..xx.....X..N..xxxxxxxxxxxxxxx..D..X.....xx..x +#x..xx...........xxxxxxxxxxxxxxx...........xx..x +#x..xxx..M......xxxxxxxxxxxxxxxxx......E..xxx..x +#x..xxxxx.....xxxxxxxxxxxxxxxxxxxxx.....xxxxx..x +#x..xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx..x +#x..xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx..x +#x..xxxxxxxxxx.....xxxxxxxxxxx.....xxxxxxxxxx..x +#xx..xxxxxxx......K..xxxxxxx..G......xxxxxxx..xx +#xx..xxxxxx.L.........xxxxx.........H.xxxxxx..xx +#xxx..xxxxx.....X.....xxxxx.....X.....xxxxx..xxx +#xxx..xxxxx...........xxxxx...........xxxxx..xxx +#xxxx..xxxxx......J..xxxxxxx..I......xxxxx..xxxx +#xxxxx..xxxxxx.....xxxxxxxxxxx.....xxxxxx..xxxxx +#xxxxxx...xxx+xxxxxxxxxxxxxxxxxxxxx+xxx...xxxxxx +#xxxxxxxx....xxxxxxxxxxxxxxxxxxxxxxx....xxxxxxxx +#xxxxxxxxxx........xxxxxxxxxxx........xxxxxxxxxx +#xxxxxxxxxxxxxxx........x........xxxxxxxxxxxxxxx +#xxxxxxxxxxxxxxxxxxxx.......xxxxxxxxxxxxxxxxxxxx +#xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +#ENDMAP ########################################################################## # Eino's temples -NAME: temple_eino_001 +NAME: temple_eino_001a PLACE: Temple ORIENT: encompass +WEIGHT: 5 SHUFFLE: {([ COLOUR: c = red MAP @@ -749,6 +795,34 @@ cccccccclccccccclcccccccc ccccccccccccccccccccccccc ENDMAP +NAME: temple_eino_001b +PLACE: Temple +ORIENT: encompass +WEIGHT: 5 +SHUFFLE: {([ +COLOUR: c = red +MAP +ccccccccccccccccccccccccc +cccccccclccccccclcccccccc +cccccccl.lcclccl.lccccccc +cccclll...c...c...lllcccc +ccclll..B.G...G.B..lllccc +cccll.......B.......llccc +cccl.................lccc +ccccG...............Gcccc +ccc...................ccc +ccl..B....{.(.[....B..lcc +ccc...................ccc +ccccG...............Gcccc +cccl.................lccc +cccll.......B.......llccc +ccclll..B.G...G.B..lllccc +cccclll...c...c...lllcccc +cccccccl.lcclccl.lccccccc +cccccccclccccccclcccccccc +ccccccccccccccccccccccccc +ENDMAP + NAME: temple_eino_002 PLACE: Temple TAGS: no_pool_fixup @@ -893,3 +967,152 @@ bbbbbbbbbbbbbbb.B.bbbbbbbbbbbbbbb bbbbbbbbbbbbbbb...bbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb ENDMAP + +NAME: temple_eino_005a +PLACE: Temple +ORIENT: encompass +WEIGHT: 5 +SHUFFLE: {([ +MAP + bbbbb + bbb...bbb + b...(...b + bbbbbbb.b...b.bbbbbbb + b...b...........b...b +bbbbb.{.....b.T.b.....[.bbbbb +b...b.....B.......B.....b...b +b.B....bb...b...b...bb....B.b +b...b...b.....B.....b...b...b +bbbbb.B....bb...bb....B.bbbbb + b...b...b...b...b...b + bbbbb.B.......B.bbbbb + b...b...b...b + bbbbb.B.bbbbb + b...b + bbbbb +ENDMAP + +NAME: temple_eino_005b +PLACE: Temple +ORIENT: encompass +WEIGHT: 5 +SHUFFLE: {([ +MAP + bbbbb + bbbbb...bbbbb + b...b.(.b...b + b.B.......B.b + bbbbb...bbbbb...bbbbb + b...bb.bbbbbbbbbb...b +bbbbb.{.b...bbbbb.....[.bbbbb +b...b...b.B.......B.b...b...b +b.B....bb...b...b...bb....B.b +b...b...bbbbb.B.bbbbb...b...b +bbbbb.B....bb...bb....B.bbbbb + b...b...bbbbb...b...b + bbbbb.B.......B.bbbbb + b...b...b...b + bbbbb.B.bbbbb + b...b + bbbbb +ENDMAP + +NAME: temple_eino_006a +PLACE: Temple +ORIENT: encompass +SHUFFLE: {([ +WEIGHT: 5 +MAP +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +x..x...xxx....xxxxxxx....xxx...x..x +x.x.....x.......xxx.......x.....x.x +xx...B..x..B.....x.....B..x..B...xx +x.......x.................x.......x +xx.....xxx.......{.......xxx.....xx +xxx...xxxxx...xx...xx...xxxxx...xxx +xx.....xxx.....xx.xx.....xxx.....xx +x.......x.......x.x.......x.......x +x..B.........B..x(x..B.........B..x +x.......x.......x.x.......x.......x +xx.....xxx.....xx.xx.....xxx.....xx +xxx...xxxxx...xx...xx...xxxxx...xxx +xx.....xxx.......[.......xxx.....xx +x.......x.................x.......x +xx...B..x..B.....x.....B..x..B...xx +x.x.....x.......xxx.......x.....x.x +x..x...xxx....xxxxxxx....xxx...x..x +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +ENDMAP + +NAME: temple_eino_006b +PLACE: Temple +ORIENT: encompass +SHUFFLE: {([ +WEIGHT: 5 +MAP +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +x..x...xxx....xxxxxxx....xxx...x..x +x.x.....x.......xxx.......x.....x.x +xx...B..x..B.....x.....B..x..B...xx +x.......x.................x.......x +xx.....xxx.......{.......xxx.....xx +xxx...xxxxx...xx...xx...xxxxx...xxx +xx.....xxx...xxxx.xxxx...xxx.....xx +x.......x...xxxx...xxxx...x.......x +x..B.......xxxx..(..xxxx.......B..x +x.......x...xxxx...xxxx...x.......x +xx.....xxx...xxxx.xxxx...xxx.....xx +xxx...xxxxx...xx...xx...xxxxx...xxx +xx.....xxx.......[.......xxx.....xx +x.......x.................x.......x +xx...B..x..B.....x.....B..x..B...xx +x.x.....x.......xxx.......x.....x.x +x..x...xxx....xxxxxxx....xxx...x..x +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +ENDMAP + +NAME: mini_greek_temple +PLACE: Temple +ORIENT: encompass +SHUFFLE: {([ +MONS: plant, bush +MAP +tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt +tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt +tttttttttttt....1111tttttttttttttttttttttttttttttttttttttttt +tttttttt.........1111....tttttttttttt.........tttttttttttttt +tttt.......................1tttttt.......t.........ttttttttt +tt.........2........t...............................2222tttt +tt.....{..21...t.................ccccccccccccccc.....22.tttt +ttt...........ttt.......(........G.c...........ctt..t..ttttt +tttt......2........................c.B.B.B.B.B.ctt......tttt +tttttt.....................t.....G.c...........cttt.....tttt +ttttttttt..1.....2...t.............+...B.B.B.B.ctt...t....tt +tttttttt.....[...................G.c...........ct...ttt..ttt +ttttttttt...................1......c.B.B.B.B.B.ct..tttt.tttt +ttttttttttttttt....2....t........G.c...........ct....t..tttt +ttttttttttttttttt................ccccccccccccccct.......2ttt +tttttttttttttttttt..........t.........t......ttt......2ttttt +ttttttttttttttttttttt...............................22tttttt +ttttttttttttttttttttttt............t..........t....ttttttttt +tttttttttttttttttttttttttttt...........t.........ttttttttttt +ttttttttttttttttttttttttttttttt..............ttttttttttttttt +tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt +tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt +ENDMAP + +############################################################################# +# Overflow temples +############################################################################## + +# To make an overflow temple for N altars, give it the tag +# "temple_overflow_N". + +############################################################################## +# Overflow temples with one altar, must have tag "temple_overflow_1" +# +NAME: overflow_temple_1_a +TAGS: temple_overflow_1 allow_dup +MAP +B +ENDMAP diff --git a/crawl-ref/source/dat/uniques.des b/crawl-ref/source/dat/uniques.des index 42e680646e..5934928d9d 100644 --- a/crawl-ref/source/dat/uniques.des +++ b/crawl-ref/source/dat/uniques.des @@ -129,9 +129,19 @@ MAP 1 ENDMAP -NAME: uniq_gastronok -DEPTH: 8-9, 10-13, Lair:4-8 -TAGS: place_unique +NAME: uniq_gastronok_1 +DEPTH: 8-9, 10-13, !Lair +TAGS: place_unique uniq_gastronok +WEIGHT: 5 +MONS: Gastronok +MAP +1 +ENDMAP + +NAME: uniq_gastronok_2 +DEPTH: Lair:4-8 +TAGS: place_unique uniq_gastronok +WEIGHT: 15 MONS: Gastronok MAP 1 @@ -170,7 +180,7 @@ MAP ENDMAP NAME: uniq_urug -DEPTH: 10-13, 14-16, !Lair, !Tomb, !Lair +DEPTH: 10-13, 14-16, !Lair, !Lair TAGS: place_unique MONS: Urug MAP @@ -178,7 +188,7 @@ MAP ENDMAP NAME: uniq_michael -DEPTH: 10-13, 14-16, !Lair, !Tomb, !Lair +DEPTH: 10-13, 14-16, !Lair, !Lair TAGS: place_unique MONS: Michael MAP @@ -186,7 +196,7 @@ MAP ENDMAP NAME: uniq_eustachio -DEPTH: 10-13, 14-16, !Lair, !Tomb, !Lair +DEPTH: 10-13, 14-16, !Lair, !Lair TAGS: place_unique MONS: Eustachio MAP @@ -194,7 +204,7 @@ MAP ENDMAP NAME: uniq_sonja -DEPTH: 10-13, 14-16, !Lair, !Tomb, !Lair +DEPTH: 10-13, 14-16, !Lair, !Lair TAGS: place_unique MONS: Sonja MAP @@ -210,7 +220,7 @@ MAP ENDMAP NAME: uniq_erica -DEPTH: 10-13, 14-16, !Lair, !Tomb, !Lair +DEPTH: 10-13, 14-16, !Lair, !Lair TAGS: place_unique MONS: Erica MAP @@ -218,7 +228,7 @@ MAP ENDMAP NAME: uniq_josephine -DEPTH: 10-13, 14-16, !Lair, !Tomb, !Lair +DEPTH: 10-13, 14-16, !Lair, !Lair TAGS: place_unique MONS: Josephine band MAP @@ -226,7 +236,7 @@ MAP ENDMAP NAME: uniq_jozef -DEPTH: 10-13, 14-16, !Lair, !Tomb, !Lair +DEPTH: 10-13, 14-16, !Lair, !Lair TAGS: place_unique MONS: Jozef MAP @@ -234,7 +244,7 @@ MAP ENDMAP NAME: uniq_harold -DEPTH: 10-13, 14-16, !Lair, !Tomb, !Lair +DEPTH: 10-13, 14-16, !Lair, !Lair TAGS: place_unique MONS: Harold MAP @@ -242,7 +252,7 @@ MAP ENDMAP NAME: uniq_norbert -DEPTH: 10-13, 14-16, !Lair, !Tomb, !Lair +DEPTH: 10-13, 14-16, !Lair, !Lair TAGS: place_unique MONS: Norbert MAP @@ -250,7 +260,7 @@ MAP ENDMAP NAME: uniq_snorg -DEPTH: 14-16, 17-19, !Tomb, !Lair +DEPTH: 14-16, 17-19, !Lair TAGS: place_unique MONS: Snorg MAP @@ -258,7 +268,7 @@ MAP ENDMAP NAME: uniq_roxanne -DEPTH: 14-16, 17-19, !Tomb, !Lair +DEPTH: 14-16, 17-19, !Lair TAGS: place_unique MONS: Roxanne MAP @@ -266,7 +276,7 @@ MAP ENDMAP NAME: uniq_rupert -DEPTH: 14-16, 17-19, !Tomb, !Lair +DEPTH: 14-16, 17-19, !Lair TAGS: place_unique MONS: Rupert MAP @@ -274,7 +284,7 @@ MAP ENDMAP NAME: uniq_azrael -DEPTH: 14-16, 17-19, !Tomb, !Lair, !Swamp, !Shoal +DEPTH: 14-16, 17-19, !Lair, !Swamp, !Shoal TAGS: place_unique MONS: Azrael band MAP @@ -282,7 +292,7 @@ MAP ENDMAP NAME: uniq_nessos -DEPTH: 14-16, 17-19, !Tomb, !Lair +DEPTH: 14-16, 17-19, !Lair TAGS: place_unique MONS: Nessos MAP @@ -290,7 +300,7 @@ MAP ENDMAP NAME: uniq_agnes -DEPTH: 14-16, !Tomb, !Lair +DEPTH: 14-16, !Lair TAGS: place_unique MONS: Agnes MAP @@ -298,7 +308,7 @@ MAP ENDMAP NAME: uniq_nikola -DEPTH: 14-16, 17-19, !Tomb, !Lair +DEPTH: 14-16, 17-19, !Lair TAGS: place_unique MONS: Nikola MAP @@ -306,7 +316,7 @@ MAP ENDMAP NAME: uniq_maud -DEPTH: 14-16, !Tomb, !Lair +DEPTH: 14-16, !Lair TAGS: place_unique MONS: Maud MAP @@ -314,7 +324,7 @@ MAP ENDMAP NAME: uniq_louise -DEPTH: 14-16, 17-19, !Tomb, !Lair +DEPTH: 14-16, 17-19, !Lair TAGS: place_unique MONS: Louise MAP @@ -322,7 +332,7 @@ MAP ENDMAP NAME: uniq_nergalle -DEPTH: 14-16, 17-19, !Tomb, !Lair +DEPTH: 14-16, 17-19, !Lair TAGS: place_unique MONS: Nergalle MAP @@ -330,7 +340,7 @@ MAP ENDMAP NAME: uniq_kirke -DEPTH: 14-16, 17-19, !Tomb, !Lair +DEPTH: 14-16, 17-19, !Lair TAGS: place_unique MONS: Kirke band MAP @@ -338,7 +348,7 @@ MAP ENDMAP NAME: uniq_francis -DEPTH: 17-19, 20-27, !Tomb, !Lair +DEPTH: 17-19, 20-27, !Lair TAGS: place_unique MONS: Francis MAP @@ -346,7 +356,7 @@ MAP ENDMAP NAME: uniq_frances -DEPTH: 17-19, 20-27, !Tomb, !Lair +DEPTH: 17-19, 20-27, !Lair TAGS: place_unique MONS: Frances MAP @@ -354,7 +364,7 @@ MAP ENDMAP NAME: uniq_wayne -DEPTH: 17-19, 20-27, !Tomb, !Lair +DEPTH: 17-19, 20-27, !Lair TAGS: place_unique MONS: Wayne MAP @@ -362,7 +372,7 @@ MAP ENDMAP NAME: uniq_duane -DEPTH: 17-19, 20-27, !Tomb, !Lair +DEPTH: 17-19, 20-27, !Lair TAGS: place_unique MONS: Duane MAP @@ -370,7 +380,7 @@ MAP ENDMAP NAME: uniq_norris -DEPTH: 17-19, !Tomb, !Lair +DEPTH: 17-19, !Lair TAGS: place_unique MONS: Norris MAP @@ -378,7 +388,7 @@ MAP ENDMAP NAME: uniq_saint_roka -DEPTH: 17-19, 20-27, !Tomb, !Lair +DEPTH: 17-19, 20-27, !Lair TAGS: place_unique MONS: Saint Roka band MAP @@ -386,7 +396,7 @@ MAP ENDMAP NAME: uniq_xtahua -DEPTH: 20-27, !Tomb, !Lair +DEPTH: 20-27, !Lair TAGS: place_unique MONS: Xtahua MAP @@ -394,7 +404,7 @@ MAP ENDMAP NAME: uniq_frederick -DEPTH: 20-27, !Tomb, !Lair +DEPTH: 20-27, !Lair TAGS: place_unique MONS: Frederick MAP @@ -402,7 +412,7 @@ MAP ENDMAP NAME: uniq_margery -DEPTH: 20-27, !Tomb, !Lair +DEPTH: 20-27, !Lair TAGS: place_unique MONS: Margery band MAP @@ -423,7 +433,7 @@ MAP ENDMAP NAME: uniq_aizul -DEPTH: 20-27, !Tomb, !Lair +DEPTH: 20-27, !Lair TAGS: place_unique MONS: Aizul MAP diff --git a/crawl-ref/source/dat/volcano.des b/crawl-ref/source/dat/volcano.des index f986ea9641..db0a8bb924 100644 --- a/crawl-ref/source/dat/volcano.des +++ b/crawl-ref/source/dat/volcano.des @@ -223,7 +223,10 @@ end function make_fiery_weapon (e, weapon) local weapon_string = "" for _, wt in ipairs(weapon) do - weapon_string = weapon_string .. " / " .. wt .. " ego:flaming good_item" + if string.find(wt, "bow") == nil + then weapon_string = weapon_string .. " / " .. wt .. " ego:flaming good_item" + else weapon_string = weapon_string .. " / " .. wt .. " ego:flame good_item" + end end local n_weapon = string.gsub(weapon_string, "%s*\/$", "") e.item(n_weapon) diff --git a/crawl-ref/source/dbg-util.cc b/crawl-ref/source/dbg-util.cc index 1ccabe928d..12b2bf7931 100644 --- a/crawl-ref/source/dbg-util.cc +++ b/crawl-ref/source/dbg-util.cc @@ -12,7 +12,7 @@ #include "cio.h" #include "coord.h" #include "dungeon.h" -#include "monstuff.h" +#include "mon-stuff.h" #include "mon-util.h" #include "religion.h" #include "shopping.h" diff --git a/crawl-ref/source/decks.cc b/crawl-ref/source/decks.cc index e82ba90e70..b57989a745 100644 --- a/crawl-ref/source/decks.cc +++ b/crawl-ref/source/decks.cc @@ -31,8 +31,9 @@ #include "maps.h" #include "message.h" #include "misc.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-iter.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "mutation.h" #include "ouch.h" #include "player.h" @@ -2372,7 +2373,7 @@ static bool _trowel_card(int power, deck_rarity_type rarity) if (create_monster( mgen_data::hostile_at( - RANDOM_ELEMENT(statues), + RANDOM_ELEMENT(statues), "the Trowel card", true, 0, 0, you.pos())) != -1) { mpr("A menacing statue appears!"); @@ -2386,7 +2387,7 @@ static bool _trowel_card(int power, deck_rarity_type rarity) if (create_monster( mgen_data(RANDOM_ELEMENT(golems), - BEH_FRIENDLY, 5, 0, + BEH_FRIENDLY, &you, 5, 0, you.pos(), MHITYOU)) != -1) { mpr("You construct a golem!"); @@ -2513,16 +2514,13 @@ static void _crusade_card(int power, deck_rarity_type rarity) if (power_level >= 1) { // A chance to convert opponents. - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi(&you.get_los()); mi; ++mi) { - monsters* const monster = &menv[i]; - if (!monster->alive() - || !mons_near(monster) - || monster->friendly() - || monster->holiness() != MH_NATURAL - || mons_is_unique(monster->type) - || mons_immune_magic(monster) - || player_will_anger_monster(monster)) + if (mi->friendly() + || mi->holiness() != MH_NATURAL + || mons_is_unique(mi->type) + || mons_immune_magic(*mi) + || player_will_anger_monster(*mi)) { continue; } @@ -2531,35 +2529,35 @@ static void _crusade_card(int power, deck_rarity_type rarity) // (though not immunity) check. Specifically, // you can convert Killer Klowns this way. // Might be too good. - if (monster->hit_dice * 35 < random2(power)) + if (mi->hit_dice * 35 < random2(power)) { - simple_monster_message(monster, " is converted."); + simple_monster_message(*mi, " is converted."); if (one_chance_in(5 - power_level)) { - monster->attitude = ATT_FRIENDLY; + mi->attitude = ATT_FRIENDLY; // If you worship a god that lets you recruit // permanent followers, or a god allied with one, // count this as a recruitment. if (is_good_god(you.religion) || you.religion == GOD_BEOGH - && mons_species(monster->type) == MONS_ORC - && !monster->is_summoned() - && !monster->is_shapeshifter()) + && mons_species(mi->type) == MONS_ORC + && !mi->is_summoned() + && !mi->is_shapeshifter()) { // Prevent assertion if the monster was // previously worshipping a different god, // rather than already worshipping your god or // being an atheist. - monster->god = GOD_NO_GOD; + mi->god = GOD_NO_GOD; - mons_make_god_gift(monster, is_good_god(you.religion) ? + mons_make_god_gift(*mi, is_good_god(you.religion) ? GOD_SHINING_ONE : GOD_BEOGH); } } else - monster->add_ench(ENCH_CHARM); + mi->add_ench(ENCH_CHARM); } } } @@ -2584,7 +2582,7 @@ static void _summon_demon_card(int power, deck_rarity_type rarity) // and thus not print the message. // This hack appears later in this file as well. if (create_monster( - mgen_data(summon_any_demon(dct), BEH_FRIENDLY, + mgen_data(summon_any_demon(dct), BEH_FRIENDLY, &you, std::min(power/50 + 1, 6), 0, you.pos(), MHITYOU), false) == -1) @@ -2640,7 +2638,7 @@ static void _summon_any_monster(int power, deck_rarity_type rarity) const bool friendly = (power_level > 0 || !one_chance_in(4)); if (create_monster(mgen_data(mon_chosen, - friendly ? BEH_FRIENDLY : BEH_HOSTILE, + friendly ? BEH_FRIENDLY : BEH_HOSTILE, &you, 3, 0, chosen_spot, MHITYOU), false) == -1) { @@ -2656,7 +2654,7 @@ static void _summon_dancing_weapon(int power, deck_rarity_type rarity) const int mon = create_monster( mgen_data(MONS_DANCING_WEAPON, - friendly ? BEH_FRIENDLY : BEH_HOSTILE, + friendly ? BEH_FRIENDLY : BEH_HOSTILE, &you, power_level + 3, 0, you.pos(), MHITYOU), false); @@ -2742,7 +2740,7 @@ static void _summon_flying(int power, deck_rarity_type rarity) { create_monster( mgen_data(result, - friendly ? BEH_FRIENDLY : BEH_HOSTILE, + friendly ? BEH_FRIENDLY : BEH_HOSTILE, &you, std::min(power/50 + 1, 6), 0, you.pos(), MHITYOU)); } @@ -2757,7 +2755,7 @@ static void _summon_skeleton(int power, deck_rarity_type rarity) }; if (create_monster(mgen_data(skeltypes[power_level], - friendly ? BEH_FRIENDLY : BEH_HOSTILE, + friendly ? BEH_FRIENDLY : BEH_HOSTILE, &you, std::min(power/50 + 1, 6), 0, you.pos(), MHITYOU), false) == -1) @@ -2780,6 +2778,7 @@ static void _summon_ugly(int power, deck_rarity_type rarity) if (create_monster(mgen_data(ugly, friendly ? BEH_FRIENDLY : BEH_HOSTILE, + &you, std::min(power/50 + 1, 6), 0, you.pos(), MHITYOU), false) == -1) diff --git a/crawl-ref/source/delay.cc b/crawl-ref/source/delay.cc index 0ef9aa6aca..b05ca85380 100644 --- a/crawl-ref/source/delay.cc +++ b/crawl-ref/source/delay.cc @@ -34,7 +34,7 @@ #include "message.h" #include "misc.h" #include "mon-behv.h" -#include "monstuff.h" +#include "mon-stuff.h" #include "mon-util.h" #include "notes.h" #include "ouch.h" @@ -165,7 +165,7 @@ static int _recite_to_monsters(coord_def where, int pow, int, actor *) case 6: case 7: case 8: - mon->put_to_sleep(); + mon->hibernate(); simple_monster_message(mon, " falls asleep!"); break; case 9: diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc index 933bd6886d..426cba067f 100644 --- a/crawl-ref/source/describe.cc +++ b/crawl-ref/source/describe.cc @@ -40,7 +40,7 @@ #include "macro.h" #include "menu.h" #include "message.h" -#include "monstuff.h" +#include "mon-stuff.h" #include "mon-util.h" #include "newgame.h" #include "jobs.h" @@ -689,14 +689,14 @@ static std::string _describe_demon(const monsters &mons) void append_weapon_stats(std::string &description, const item_def &item) { - description += "$Damage rating: "; - _append_value(description, property( item, PWPN_DAMAGE ), false); - description += " "; - - description += "Accuracy rating: "; + description += "$Accuracy rating: "; _append_value(description, property( item, PWPN_HIT ), true); description += " "; + description += "Damage rating: "; + _append_value(description, property( item, PWPN_DAMAGE ), false); + description += " "; + description += "Base attack delay: "; _append_value(description, property( item, PWPN_SPEED ) * 10, false); description += "%"; @@ -748,9 +748,14 @@ static std::string _describe_weapon(const item_def &item, bool verbose) "cause great damage to the undead and demons."; break; case SPWPN_ELECTROCUTION: - description += "Occasionally, upon striking a foe, it will " - "discharge some electrical energy and cause terrible " - "harm."; + if (is_range_weapon(item)) + description += "It charges the ammunition it shoots with " + "electricity; occasionally upon a hit, such missiles " + "may discharge and cause terrible harm."; + else + description += "Occasionally, upon striking a foe, it will " + "discharge some electrical energy and cause terrible " + "harm."; break; case SPWPN_ORC_SLAYING: description += "It is especially effective against all of " @@ -763,7 +768,7 @@ static std::string _describe_weapon(const item_def &item, bool verbose) break; case SPWPN_VENOM: if (is_range_weapon(item)) - description += "It poisons the unbranded ammo it fires."; + description += "It poisons the ammo it fires."; else description += "It poisons the flesh of those it strikes."; break; @@ -1992,10 +1997,17 @@ std::string get_item_description( const item_def &item, bool verbose, } } - if (good_god_hates_item_handling(item)) + if (conduct_type ct = good_god_hates_item_handling(item)) { description << "$$" << god_name(you.religion) << " opposes the use of " - << "such an evil item."; + << "such an "; + + if (ct == DID_NECROMANCY) + description << "evil"; + else + description << "unholy"; + + description << " item."; } else if (god_hates_item_handling(item)) { @@ -2940,6 +2952,19 @@ void get_monster_db_desc(const monsters& mons, describe_info &inf, << mitm[mons.inv[i]].name(DESC_NOCAP_A, false, true); } } + + if (mons.props.exists("blame")) + { + inf.body << "$$Monster blame chain:$"; + + const CrawlVector& blame = mons.props["blame"].get_vector(); + + for (CrawlVector::const_iterator it = blame.begin(); + it != blame.end(); ++it) + { + inf.body << " " << it->get_string() << "$"; + } + } #endif } diff --git a/crawl-ref/source/directn.cc b/crawl-ref/source/directn.cc index 50fdc78af6..3d225bfd6c 100644 --- a/crawl-ref/source/directn.cc +++ b/crawl-ref/source/directn.cc @@ -44,7 +44,7 @@ #include "message.h" #include "menu.h" #include "misc.h" -#include "monstuff.h" +#include "mon-stuff.h" #include "mon-info.h" #include "mon-util.h" #include "output.h" @@ -695,7 +695,7 @@ void full_describe_view() const coord_def c = list_features[i]; std::string desc = ""; #ifndef USE_TILE - const coord_def e = c - you.pos() + coord_def(9,9); + const coord_def e = c - you.pos() + coord_def(8,8); show_type object = env.show(e); unsigned short col = object.colour; unsigned ch; @@ -2902,6 +2902,13 @@ std::string feature_description(const coord_def& where, bool bloody, if (grid == DNGN_OPEN_DOOR || feat_is_closed_door(grid)) { + const std::string door_desc_prefix = + env.markers.property_at(where, MAT_ANY, + "door_description_prefix"); + const std::string door_desc_suffix = + env.markers.property_at(where, MAT_ANY, + "door_description_suffix"); + std::set<coord_def> all_door; find_connected_identical(where, grd(where), all_door); const char *adj, *noun; @@ -2911,12 +2918,8 @@ std::string feature_description(const coord_def& where, bool bloody, desc += (grid == DNGN_OPEN_DOOR) ? "open " : "closed "; if (grid == DNGN_DETECTED_SECRET_DOOR) desc += "detected secret "; - desc += noun; - const std::string door_desc_suffix = - env.markers.property_at(where, MAT_ANY, - "door_description_suffix"); - desc += door_desc_suffix; + desc += door_desc_prefix + noun + door_desc_suffix; if (bloody) desc += ", spattered with blood"; @@ -2965,6 +2968,7 @@ static std::string _describe_mons_enchantment(const monsters &mons, // Suppress silly-looking combinations, even if they're // internally valid. if (paralysed && (ench.ench == ENCH_SLOW || ench.ench == ENCH_HASTE + || ench.ench == ENCH_SWIFT || ench.ench == ENCH_PETRIFIED || ench.ench == ENCH_PETRIFYING)) { @@ -2992,7 +2996,7 @@ static std::string _describe_mons_enchantment(const monsters &mons, case ENCH_POISON: return "poisoned"; case ENCH_SICK: return "sick"; case ENCH_ROT: return "rotting away"; //jmf: "covered in sores"? - case ENCH_BACKLIGHT: return "softly glowing"; + case ENCH_CORONA: return "softly glowing"; case ENCH_SLOW: return "moving slowly"; case ENCH_BERSERK: return "berserk"; case ENCH_BATTLE_FRENZY: return "consumed by blood-lust"; @@ -3006,6 +3010,7 @@ static std::string _describe_mons_enchantment(const monsters &mons, case ENCH_PETRIFIED: return "petrified"; case ENCH_PETRIFYING: return "slowly petrifying"; case ENCH_LOWERED_MR: return "susceptible to magic"; + case ENCH_SWIFT: return "moving somewhat quickly"; default: return ""; } } diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc index 9b9998584e..401c53ab1d 100644 --- a/crawl-ref/source/dungeon.cc +++ b/crawl-ref/source/dungeon.cc @@ -41,7 +41,7 @@ #include "message.h" #include "misc.h" #include "mon-util.h" -#include "monplace.h" +#include "mon-place.h" #include "notes.h" #include "place.h" #include "player.h" @@ -55,6 +55,10 @@ #include "traps.h" #include "travel.h" +#ifdef DEBUG_DIAGNOSTICS +#define DEBUG_TEMPLES 1 +#endif + #ifdef WIZARD #include "cio.h" // for cancelable_get_line() #endif @@ -211,10 +215,15 @@ static void _dgn_load_colour_grid(); static void _dgn_map_colour_fixup(); // ALTAR FUNCTIONS +static int _setup_temple_altars(CrawlHashTable &temple); +static dungeon_feature_type _pick_temple_altar(vault_placement &place); static dungeon_feature_type _pick_an_altar(); static void _place_altar(); static void _place_altars(); +static std::vector<god_type> _temple_altar_list; +static CrawlHashTable* _current_temple_hash = NULL; // XXX: hack! + typedef std::list<coord_def> coord_list; // MISC FUNCTIONS @@ -295,6 +304,9 @@ bool builder(int level_number, int level_type) dgn_reset_level(); + if (player_in_branch(BRANCH_ECUMENICAL_TEMPLE)) + _setup_temple_altars(you.props); + // If we're getting low on available retries, disable random vaults // and minivaults (special levels will still be placed). if (tries < 5) @@ -948,6 +960,9 @@ void dgn_reset_level() dgn_check_connectivity = false; dgn_zones = 0; + _temple_altar_list.clear(); + _current_temple_hash = NULL; + // Forget level properties. env.properties.clear(); @@ -1617,6 +1632,142 @@ static void _dgn_verify_connectivity(unsigned nvaults) } } +// Structure of OVERFLOW_TEMPLES: +// +// * A vector, with one cell per dungeon level (unset if there's no +// overflow temples on that level). +// +// * The cell of the previous vector is a vector, with one overlfow +// temple definition per cell. +// +// * The cell of the previous vector is a hash table, containing the +// list of gods for the overflow temple and (optionally) the name of +// the vault to use for the temple. If no map name is supplied, +// it will randomly pick from vaults tagged "temple_overflow_num", +// where "num" is the number of gods in the temple. Gods are listed +// in the order their altars are placed. +static void _build_overflow_temples(int level_number) +{ + if (!you.props.exists(OVERFLOW_TEMPLES_KEY)) + // Levels built while in testing mode. + return; + + CrawlVector &levels = you.props[OVERFLOW_TEMPLES_KEY].get_vector(); + + // Are we deeper than the last overflow temple? + if (level_number >= levels.size()) + return; + + CrawlStoreValue &val = levels[level_number]; + + // Does this level have an overflow temple? + if (val.get_flags() & SFLAG_UNSET) + return; + + CrawlVector &temples = val.get_vector(); + + if (temples.size() == 0) + return; + + if (!can_create_vault) + { + mpr("WARNING: Overriding can_create_vault", + MSGCH_DIAGNOSTICS); + can_create_vault = true; + } + + for (unsigned int i = 0; i < temples.size(); i++) + { + CrawlHashTable &temple = temples[i].get_table(); + + const int num_gods = _setup_temple_altars(temple); + + const map_def *vault = NULL; + + if (temple.exists(TEMPLE_MAP_KEY)) + { + std::string name = temple[TEMPLE_MAP_KEY].get_string(); + + vault = find_map_by_name(name); + if (vault == NULL) + { + mprf(MSGCH_ERROR, + "Couldn't find overflow temple map '%s'!", + name.c_str()); + } + } + else + { + std::string vault_tag; + + // For a single-altar temple, first try to find a temple specialized + // for that god. + if (num_gods == 1) + { + CrawlVector &god_vec = temple[TEMPLE_GODS_KEY]; + god_type god = (god_type) god_vec[0].get_byte(); + + std::string name = god_name(god); + name = replace_all(name, " ", "_"); + lowercase(name); + + if (you.uniq_map_tags.find("uniq_altar_" + name) + != you.uniq_map_tags.end()) + { + // We've already placed a specialized temple for this + // god, so do nothing. +#ifdef DEBUG_TEMPLES + mprf(MSGCH_DIAGNOSTICS, "Already placed specialized " + "single-altar temple for %s", name.c_str()); +#endif + continue; + } + + vault_tag = make_stringf("temple_overflow_%s", name.c_str()); + + vault = random_map_for_tag(vault_tag, true); +#ifdef DEBUG_TEMPLES + if (vault == NULL) + mprf(MSGCH_DIAGNOSTICS, "Couldn't find overflow temple " + "for god %s", name.c_str()); +#endif + } + + if (vault == NULL) + { + vault_tag = make_stringf("temple_overflow_%d", num_gods); + + vault = random_map_for_tag(vault_tag, true); + if (vault == NULL) + { + mprf(MSGCH_ERROR, + "Couldn't find overflow temple tag '%s'!", + vault_tag.c_str()); + } + } + } + + if (vault == NULL) + // Might as well build the rest of the level if we couldn't + // find the overflow temple map, so don't veto the level. + return; + + if (!_ensure_vault_placed(_build_vaults(level_number, vault), false)) + { +#ifdef DEBUG_TEMPLES + mprf(MSGCH_DIAGNOSTICS, "Couldn't place overlfow temple '%s', " + "vetoing level.", vault->name.c_str()); +#endif + return; + } +#ifdef DEBUG_TEMPLES + mprf(MSGCH_DIAGNOSTICS, "Placed overflow temple %s", + vault->name.c_str()); +#endif + } + _current_temple_hash = NULL; // XXX: hack! +} + static void _build_dungeon_level(int level_number, int level_type) { spec_room sr; @@ -1663,9 +1814,16 @@ static void _build_dungeon_level(int level_number, int level_type) // Any further vaults must make sure not to disrupt level layout. dgn_check_connectivity = !player_in_branch(BRANCH_SHOALS); + if (you.where_are_you == BRANCH_MAIN_DUNGEON) + { + _build_overflow_temples(level_number); + + if (dgn_level_vetoed) + return; + } + // Try to place minivaults that really badly want to be placed. Still // no guarantees, seeing this is a minivault. - _place_minivaults(); _place_branch_entrances( level_number, level_type ); _place_extra_vaults(); @@ -2503,7 +2661,27 @@ static bool _place_portal_vault(int stair, const std::string &tag, int dlevel) static const map_def *_dgn_random_map_for_place(bool minivault) { - const level_id lid = level_id::current(); + if (!minivault && player_in_branch(BRANCH_ECUMENICAL_TEMPLE)) + { + // Temple vault determined at new game tiem. + std::string name = you.props[TEMPLE_MAP_KEY]; + + // Tolerate this for a little while, for old games. + if (!name.empty()) + { + const map_def *vault = find_map_by_name(name); + + if (vault == NULL) + { + end(1, false, "Unable to place Temple vault '%s'", + name.c_str()); + } + return (vault); + } + } + + const level_id lid = level_id::current(); + const map_def *vault = random_map_for_place(lid, minivault); // Disallow entry vaults for tutorial (only complicates things). @@ -2517,6 +2695,20 @@ static const map_def *_dgn_random_map_for_place(bool minivault) return (vault); } +static int _setup_temple_altars(CrawlHashTable &temple) +{ + _current_temple_hash = &temple; // XXX: hack! + + CrawlVector god_list = temple[TEMPLE_GODS_KEY].get_vector(); + + _temple_altar_list.clear(); + + for (unsigned int i = 0; i < god_list.size(); i++) + _temple_altar_list.push_back( (god_type) god_list[i].get_byte() ); + + return ( (int) god_list.size() ); +} + // Returns BUILD_SKIP if we should skip further generation, // BUILD_QUIT if we should immediately quit, and BUILD_CONTINUE // otherwise. @@ -4796,9 +4988,6 @@ dungeon_feature_type map_feature_at(map_def *map, const coord_def &c, int rawfea : DNGN_FLOOR); // includes everything else } -// Returns altar_count - seems rather odd to me to force such a return -// when I believe the value is only used in the case of the ecumenical -// temple - oh, well... {dlb} (XXX) static void _vault_grid( vault_placement &place, int vgrid, const coord_def& where, @@ -4871,9 +5060,7 @@ static void _vault_grid( vault_placement &place, (vgrid == ']') ? DNGN_STONE_STAIRS_DOWN_III : (vgrid == '[') ? DNGN_STONE_STAIRS_UP_III : (vgrid == 'A') ? DNGN_STONE_ARCH : - (vgrid == 'B') ? - static_cast<dungeon_feature_type>( - DNGN_ALTAR_FIRST_GOD + place.altar_count) :// see below + (vgrid == 'B') ? _pick_temple_altar(place) : (vgrid == 'C') ? _pick_an_altar() : // f(x) elsewhere {dlb} (vgrid == 'I') ? DNGN_ORCISH_IDOL : (vgrid == 'G') ? DNGN_GRANITE_STATUE : @@ -4890,9 +5077,6 @@ static void _vault_grid( vault_placement &place, // then, handle oddball grids {dlb}: switch (vgrid) { - case 'B': - place.altar_count++; - break; case '@': place.exits.push_back( where ); break; @@ -5311,6 +5495,27 @@ static void _many_pools(dungeon_feature_type pool_type) } } // end many_pools() +static dungeon_feature_type _pick_temple_altar(vault_placement &place) +{ + if (_temple_altar_list.empty()) + { + if (_current_temple_hash != NULL) + { + mprf("Ran out of altars for temple!", MSGCH_ERROR); + return (DNGN_FLOOR); + } + // Randomized altar list for mini-temples. + _temple_altar_list = temple_god_list(); + std::random_shuffle(_temple_altar_list.begin(), _temple_altar_list.end()); + } + + const god_type god = _temple_altar_list.back(); + + _temple_altar_list.pop_back(); + + return altar_for_god(god); +} + //jmf: Generate altar based on where you are, or possibly randomly. static dungeon_feature_type _pick_an_altar() { @@ -8231,7 +8436,10 @@ static bool _fixup_interlevel_connectivity() void vault_placement::reset() { - altar_count = 0; + if (_current_temple_hash != NULL) + _setup_temple_altars(*_current_temple_hash); + else + _temple_altar_list.clear(); } void vault_placement::apply_grid() @@ -8286,10 +8494,10 @@ void remember_vault_placement(std::string key, vault_placement &place) table.size() + 1); std::string place_str - = make_stringf("(%d,%d) (%d,%d) orient: %d lev: %d alt: %d rune: %d " + = make_stringf("(%d,%d) (%d,%d) orient: %d lev: %d rune: %d " "subst: %d", place.pos.x, place.pos.y, place.size.x, place.size.y, - place.orient, place.level_number, place.altar_count, + place.orient, place.level_number, place.num_runes, place.rune_subst); table[name] = place_str; diff --git a/crawl-ref/source/dungeon.h b/crawl-ref/source/dungeon.h index f6932d1cb6..c9c236cb9b 100644 --- a/crawl-ref/source/dungeon.h +++ b/crawl-ref/source/dungeon.h @@ -29,6 +29,12 @@ #define YOU_PORTAL_VAULT_NAMES_KEY "you_portal_vault_names_key" +// See _build_overflow_temples() in dungeon.cc for details on overflow +// temples. +#define TEMPLE_GODS_KEY "temple_gods_key" +#define OVERFLOW_TEMPLES_KEY "overflow_temples_key" +#define TEMPLE_MAP_KEY "temple_map_key" + enum portal_type { PORTAL_NONE = 0, @@ -140,7 +146,7 @@ public: map_def map; std::vector<coord_def> exits; - int level_number, altar_count, num_runes; + int level_number, num_runes; // If we're not placing runes, this is the substitute feature. int rune_subst; @@ -148,8 +154,7 @@ public: public: vault_placement() : pos(-1, -1), size(0, 0), orient(0), map(), - exits(), level_number(0), altar_count(0), num_runes(0), - rune_subst(-1) + exits(), level_number(0), num_runes(0), rune_subst(-1) { } diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc index 195aaa9792..f74729b323 100644 --- a/crawl-ref/source/effects.cc +++ b/crawl-ref/source/effects.cc @@ -43,8 +43,9 @@ #include "misc.h" #include "mon-behv.h" #include "mon-cast.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-iter.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "mon-util.h" #include "mutation.h" #include "notes.h" @@ -2449,44 +2450,35 @@ bool recharge_wand(int item_slot) return (false); } +// Berserking monsters cannot be ordered around. +static bool _follows_orders(monsters* mon) +{ + return (mon->friendly() && mon->type != MONS_GIANT_SPORE + && !mon->berserk()); +} + // Sets foe target of friendly monsters. // If allow_patrol is true, patrolling monsters get MHITNOT instead. static void _set_friendly_foes(bool allow_patrol = false) { - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi(&you.get_los()); mi; ++mi) { - monsters *mon(&menv[i]); - if (!mon->alive() || !mons_near(mon) || !mon->friendly() - || mon->type == MONS_GIANT_SPORE) - { + if (!_follows_orders(*mi)) continue; - } - - // Berserking monsters cannot be ordered around. - if (mon->berserk()) - continue; - - mon->foe = (allow_patrol && mon->is_patrolling() ? MHITNOT + mi->foe = (allow_patrol && mi->is_patrolling() ? MHITNOT : you.pet_target); } } static void _set_allies_patrol_point(bool clear = false) { - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi(&you.get_los()); mi; ++mi) { - monsters *mon(&menv[i]); - if (!mon->alive() || !mons_near(mon) || !mon->friendly()) + if (!_follows_orders(*mi)) continue; - - // Berserking monsters cannot be ordered around. - if (mon->berserk() || mon->type == MONS_GIANT_SPORE) - continue; - - mon->patrol_point = (clear ? coord_def(0, 0) : mon->pos()); - + mi->patrol_point = (clear ? coord_def(0, 0) : mi->pos()); if (!clear) - mon->behaviour = BEH_WANDER; + mi->behaviour = BEH_WANDER; } } @@ -2868,7 +2860,7 @@ static void _hell_effects() if (summon_instead) { create_monster( - mgen_data::hostile_at(which_beastie, + mgen_data::hostile_at(which_beastie, "the effects of Hell", true, 0, 0, you.pos())); } else @@ -2890,6 +2882,7 @@ static void _hell_effects() mgen_data mg; mg.pos = you.pos(); mg.foe = MHITYOU; + mg.non_actor_summoner = "the effects of Hell"; create_monster(mg); for (int i = 0; i < 4; ++i) @@ -3944,8 +3937,9 @@ void handle_time(long time_delta) || monster_at(newpos) || env.cgrid(newpos) != EMPTY_CLOUD); - mgen_data mg(MONS_JELLY, BEH_STRICT_NEUTRAL, 0, 0, newpos, + mgen_data mg(MONS_JELLY, BEH_STRICT_NEUTRAL, 0, 0, 0, newpos, MHITNOT, 0, GOD_JIYVA); + mg.non_actor_summoner = "Jiyva"; if (create_monster(mg) != -1) success = true; @@ -4166,57 +4160,52 @@ void update_level(double elapsedTime) dungeon_events.fire_event( dgn_event(DET_TURN_ELAPSED, coord_def(0, 0), turns * 10)); - for (int m = 0; m < MAX_MONSTERS; m++) + for (monster_iterator mi; mi; ++mi) { - monsters *mon = &menv[m]; - - if (!mon->alive()) - continue; - #if DEBUG_DIAGNOSTICS mons_total++; #endif // Pacified monsters often leave the level now. - if (mon->pacified() && turns > random2(40) + 21) + if (mi->pacified() && turns > random2(40) + 21) { - make_mons_leave_level(mon); + make_mons_leave_level(*mi); continue; } // Following monsters don't get movement. - if (mon->flags & MF_JUST_SUMMONED) + if (mi->flags & MF_JUST_SUMMONED) continue; // XXX: Allow some spellcasting (like Healing and Teleport)? - bwr - // const bool healthy = (mon->hit_points * 2 > mon->max_hit_points); + // const bool healthy = (mi->hit_points * 2 > mi->max_hit_points); // This is the monster healing code, moved here from tag.cc: - if (mons_can_regenerate(mon)) + if (mons_can_regenerate(*mi)) { - if (monster_descriptor(mon->type, MDSC_REGENERATES) - || mon->type == MONS_PLAYER_GHOST) + if (monster_descriptor(mi->type, MDSC_REGENERATES) + || mi->type == MONS_PLAYER_GHOST) { - mon->heal(turns); + mi->heal(turns); } else { // Set a lower ceiling of 0.1 on the regen rate. const int regen_rate = - std::max(mons_natural_regen_rate(mon) * 2, 5); + std::max(mons_natural_regen_rate(*mi) * 2, 5); - mon->heal(div_rand_round(turns * regen_rate, 50)); + mi->heal(div_rand_round(turns * regen_rate, 50)); } } // Handle nets specially to remove the trapping property of the net. - if (mon->caught()) - mon->del_ench(ENCH_HELD, true); + if (mi->caught()) + mi->del_ench(ENCH_HELD, true); - _catchup_monster_moves(mon, turns); + _catchup_monster_moves(*mi, turns); - if (turns >= 10 && mon->alive()) - mon->timeout_enchantments(turns / 10); + if (turns >= 10 && mi->alive()) + mi->timeout_enchantments(turns / 10); } #if DEBUG_DIAGNOSTICS @@ -4458,7 +4447,7 @@ static int _mushroom_ring(item_def &corpse, int & seen_count, return (0); mgen_data temp(MONS_TOADSTOOL, - toadstool_behavior, 0, 0, + toadstool_behavior, 0, 0, 0, coord_def(), MHITNOT, MG_FORCE_PLACE, @@ -4554,6 +4543,7 @@ int spawn_corpse_mushrooms(item_def &corpse, toadstool_behavior, 0, 0, + 0, current, MHITNOT, MG_FORCE_PLACE, diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index f452a9523c..d33a2ec149 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -243,24 +243,25 @@ enum beam_type // beam[].flavour BEAM_ENSLAVE_DEMON, BEAM_BLINK, BEAM_PETRIFY, - BEAM_BACKLIGHT, // 45 + BEAM_CORONA, // 45 BEAM_PORKALATOR, - BEAM_SLEEP, + BEAM_HIBERNATION, BEAM_BERSERK, - BEAM_LAST_ENCHANTMENT = BEAM_BERSERK, + BEAM_SLEEP, + BEAM_LAST_ENCHANTMENT = BEAM_SLEEP, // new beams for evaporate - BEAM_POTION_STINKING_CLOUD, // 50 + BEAM_POTION_STINKING_CLOUD, BEAM_POTION_POISON, BEAM_POTION_MIASMA, BEAM_POTION_STEAM, BEAM_POTION_FIRE, - BEAM_POTION_COLD, // 55 + BEAM_POTION_COLD, BEAM_POTION_BLACK_SMOKE, BEAM_POTION_GREY_SMOKE, BEAM_POTION_MUTAGENIC, BEAM_POTION_BLUE_SMOKE, - BEAM_POTION_RAIN, // 60 + BEAM_POTION_RAIN, BEAM_POTION_RANDOM, BEAM_LAST_REAL = BEAM_POTION_RANDOM, @@ -579,6 +580,7 @@ enum command_type CMD_MAP_ADD_WAYPOINT, CMD_MAP_EXCLUDE_AREA, CMD_MAP_CLEAR_EXCLUDES, + CMD_MAP_EXCLUDE_RADIUS, CMD_MAP_MOVE_LEFT, CMD_MAP_MOVE_DOWN, @@ -1147,7 +1149,7 @@ enum duration_type DUR_CONFUSING_TOUCH, DUR_SURE_BLADE, - DUR_BACKLIGHT, + DUR_CORONA, DUR_DEATHS_DOOR, DUR_FIRE_SHIELD, @@ -1221,7 +1223,7 @@ enum enchant_type ENCH_ROT, // 10 ENCH_SUMMON, ENCH_ABJ, - ENCH_BACKLIGHT, + ENCH_CORONA, ENCH_CHARM, ENCH_STICKY_FLAME, // 15 ENCH_GLOWING_SHAPESHIFTER, @@ -1245,6 +1247,7 @@ enum enchant_type ENCH_AQUATIC_LAND, // Water monsters lose hp while on land. ENCH_SPORE_PRODUCTION, // 35 ENCH_SLOUCH, + ENCH_SWIFT, // Update enchantment names in mon-util.cc when adding or removing // enchantments. @@ -1921,7 +1924,7 @@ enum monster_type // (int) menv[].type MONS_WHITE_DRACONIAN, MONS_PALE_DRACONIAN, // 320 Should always be last colour. - // Sync up with monplace.cc's draconian selection if adding more. + // Sync up with mon-place.cc's draconian selection if adding more. MONS_DRACONIAN_CALLER, MONS_DRACONIAN_MONK, MONS_DRACONIAN_ZEALOT, @@ -2092,7 +2095,8 @@ enum beh_type BEH_STRICT_NEUTRAL, BEH_NEUTRAL, // creation only BEH_HOSTILE, // creation only - BEH_GUARD // creation only - monster is guard + BEH_GUARD, // creation only - monster is guard + BEH_COPY // creation only - copy from summoner }; enum mon_attitude_type @@ -2151,8 +2155,10 @@ enum monster_flag_type MF_SPELLCASTER = 0x200000, MF_ACTUAL_SPELLS = 0x400000, // Can use spells and is a spellcaster for // Trog purposes. - MF_PRIEST = 0x800000 // Is a priest (divine spells) + MF_PRIEST = 0x800000, // Is a priest (divine spells) // for the conduct. + + MF_GOING_BERSERK = 0x1000000 // Is about to go berserk! }; // Adding slots breaks saves. YHBW. @@ -2821,8 +2827,8 @@ enum spell_type SPELL_CALL_CANINE_FAMILIAR, SPELL_SUMMON_DRAGON, SPELL_TAME_BEASTS, - SPELL_SLEEP, - SPELL_MASS_SLEEP, + SPELL_HIBERNATION, + SPELL_ENGLACIATION, SPELL_DETECT_SECRET_DOORS, SPELL_SEE_INVISIBLE, SPELL_PHASE_SHIFT, @@ -2832,7 +2838,7 @@ enum spell_type SPELL_SHATTER, SPELL_DISPERSAL, SPELL_DISCHARGE, - SPELL_BACKLIGHT, + SPELL_CORONA, SPELL_INTOXICATE, SPELL_EVAPORATE, SPELL_FRAGMENTATION, @@ -2880,6 +2886,7 @@ enum spell_type SPELL_FIRE_ELEMENTALS, SPELL_EARTH_ELEMENTALS, SPELL_AIR_ELEMENTALS, + SPELL_SLEEP, NUM_SPELLS }; @@ -3120,8 +3127,8 @@ enum zap_type ZAP_ORB_OF_FRAGMENTATION, ZAP_THROW_ICICLE, ZAP_ICE_STORM, - ZAP_BACKLIGHT, - ZAP_SLEEP, + ZAP_CORONA, + ZAP_HIBERNATION, ZAP_FLAME_TONGUE, ZAP_SANDBLAST, ZAP_SMALL_SANDBLAST, @@ -3134,6 +3141,7 @@ enum zap_type ZAP_CHAOS, ZAP_SLIME, ZAP_PORKALATOR, + ZAP_SLEEP, NUM_ZAPS }; diff --git a/crawl-ref/source/exclude.cc b/crawl-ref/source/exclude.cc index 6ddbcd9c2b..6b7e3a9ae7 100644 --- a/crawl-ref/source/exclude.cc +++ b/crawl-ref/source/exclude.cc @@ -19,6 +19,9 @@ #include "tutorial.h" #include "view.h" +typedef std::map<coord_def, travel_exclude*> exclmap; +static exclmap _curr_excludes_map; + static bool _mon_needs_auto_exclude(const monsters *mon, bool sleepy = false) { if (mons_is_stationary(mon)) @@ -111,8 +114,7 @@ static opacity_excl opc_excl; // Note: circle_def(r, C_ROUND) gives a circle with square radius r*r+1; // this doesn't work well for radius 0, but then we want to // skip LOS calculation in that case anyway since it doesn't -// currently short-cut for small bounds. So radius 0 is special-cased. - +// currently short-cut for small bounds. So radius 0, 1 are special-cased. travel_exclude::travel_exclude(const coord_def &p, int r, bool autoexcl, monster_type mons, bool vaultexcl) : pos(p), radius(r), @@ -125,7 +127,7 @@ travel_exclude::travel_exclude(const coord_def &p, int r, void travel_exclude::set_los() { uptodate = true; - if (radius > 0) + if (radius > 1) { // Radius might have been changed, and this is cheap. los.set_bounds(circle_def(radius, C_ROUND)); @@ -140,31 +142,42 @@ bool travel_exclude::affects(const coord_def& p) const pos.x, pos.y, p.x, p.y); if (radius == 0) return (p == pos); - return (los.see_cell(p)); + else if (radius == 1) + return ((p - pos).rdist() <= 1); + else + return (los.see_cell(p)); } bool travel_exclude::in_bounds(const coord_def &p) const { return (radius == 0 && p == pos + || radius == 1 && (p - pos).rdist() <= 1 || los.in_bounds(p)); } void _mark_excludes_non_updated(const coord_def &p) { - for (exclvec::iterator it = curr_excludes.begin(); + _curr_excludes_map.clear(); + + for (exclvec::iterator it = curr_excludes.begin(); it != curr_excludes.end(); ++it) { it->uptodate = it->uptodate && it->in_bounds(p); - } + _curr_excludes_map[it->pos] = &(*it); + } } -void _update_exclusion_los(bool all=false) +static void _update_exclusion_los(bool all=false) { + _curr_excludes_map.clear(); + for (exclvec::iterator it = curr_excludes.begin(); it != curr_excludes.end(); ++it) { if (all || !it->uptodate) it->set_los(); + + _curr_excludes_map[it->pos] = &(*it); } } @@ -199,9 +212,11 @@ bool is_excluded(const coord_def &p, const exclvec &exc) static travel_exclude *_find_exclude_root(const coord_def &p) { - for (unsigned int i = 0; i < curr_excludes.size(); ++i) - if (curr_excludes[i].pos == p) - return (&curr_excludes[i]); + exclmap::iterator it = _curr_excludes_map.find(p); + + if (it !=_curr_excludes_map.end()) + return it->second; + return (NULL); } @@ -256,12 +271,14 @@ void clear_excludes() #endif curr_excludes.clear(); + _curr_excludes_map.clear(); clear_level_exclusion_annotation(); _exclude_update(); } -// Cycles the radius of an exclusion, including "off" state. +// Cycles the radius of an exclusion, including "off" state; +// may start at 0 < radius < LOS_RADIUS, but won't cycle there. void cycle_exclude_radius(const coord_def &p) { // XXX: scanning through curr_excludes twice @@ -270,10 +287,7 @@ void cycle_exclude_radius(const coord_def &p) if (exc->radius == LOS_RADIUS) set_exclude(p, 0); else - { - ASSERT(exc->radius == 0); del_exclude(p); - } } else set_exclude(p, LOS_RADIUS); @@ -286,6 +300,7 @@ void del_exclude(const coord_def &p) if (curr_excludes[i].pos == p) { curr_excludes.erase(curr_excludes.begin() + i); + _curr_excludes_map.erase(p); break; } _exclude_update(p); @@ -316,6 +331,7 @@ void set_exclude(const coord_def &p, int radius, bool autoexcl, bool vaultexcl) curr_excludes.push_back(travel_exclude(p, radius, autoexcl, montype, vaultexcl)); + _curr_excludes_map[p] = &curr_excludes.back(); } _exclude_update(p); @@ -390,6 +406,7 @@ void marshallExcludes(writer& outf, const exclvec& excludes) void unmarshallExcludes(reader& inf, char minorVersion, exclvec &excludes) { excludes.clear(); + _curr_excludes_map.clear(); int nexcludes = unmarshallShort(inf); if (nexcludes) { @@ -406,6 +423,7 @@ void unmarshallExcludes(reader& inf, char minorVersion, exclvec &excludes) mon = static_cast<monster_type>(unmarshallShort(inf)); } excludes.push_back(travel_exclude(c, radius, autoexcl, mon)); + _curr_excludes_map[c] = &curr_excludes.back(); } } } diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc index 7bd0f6d512..ada19b5efc 100644 --- a/crawl-ref/source/fight.cc +++ b/crawl-ref/source/fight.cc @@ -44,8 +44,8 @@ #include "misc.h" #include "mon-behv.h" #include "mon-cast.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "mon-util.h" #include "mutation.h" #include "ouch.h" @@ -2854,7 +2854,8 @@ static bool _make_zombie(monsters* mon, int corpse_class, int corpse_index, mitm[last_item].link = idx; animate_remains(mon->pos(), CORPSE_BODY, mon->behaviour, - mon->foe, mon->god, true, true, true, &zombie_index); + mon->foe, 0, "a chaos effect", mon->god, + true, true, true, &zombie_index); } // No equipment to get, or couldn't get it for some reason. @@ -2862,10 +2863,11 @@ static bool _make_zombie(monsters* mon, int corpse_class, int corpse_index, { monster_type type = (mons_zombie_size(mon->type) == Z_SMALL) ? MONS_ZOMBIE_SMALL : MONS_ZOMBIE_LARGE; - zombie_index = create_monster( - mgen_data(type, mon->behaviour, 0, 0, mon->pos(), - mon->foe, MG_FORCE_PLACE, mon->god, - mon->type, mon->number)); + mgen_data mg(type, mon->behaviour, 0, 0, 0, mon->pos(), + mon->foe, MG_FORCE_PLACE, mon->god, + mon->type, mon->number); + mg.non_actor_summoner = "a chaos effect"; + zombie_index = create_monster(mg); } if (zombie_index == -1) diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc index cd63e9cd15..9bfb072dc3 100644 --- a/crawl-ref/source/files.cc +++ b/crawl-ref/source/files.cc @@ -8,7 +8,7 @@ #include "delay.h" #include "files.h" -#include "monplace.h" +#include "mon-place.h" #include <errno.h> #include <string.h> @@ -59,7 +59,7 @@ #include "message.h" #include "misc.h" #include "mon-act.h" -#include "monstuff.h" +#include "mon-stuff.h" #include "mon-util.h" #include "mtransit.h" #include "newgame.h" diff --git a/crawl-ref/source/fixary.h b/crawl-ref/source/fixary.h index 8743e4573a..faf35b7c38 100644 --- a/crawl-ref/source/fixary.h +++ b/crawl-ref/source/fixary.h @@ -78,56 +78,6 @@ protected: FixedVector<Column, WIDTH> mData; }; -template <typename Z> -class Matrix { -public: - Matrix(int width, int height, const Z &initial); - Matrix(int width, int height); - ~Matrix(); - - void init(const Z &initial); - Z &operator () (int x, int y) - { - return data[x + y * width]; - } - const Z &operator () (int x, int y) const - { - return data[x + y * width]; - } - -private: - Z *data; - int width, height, size; -}; - -template <typename Z> -Matrix<Z>::Matrix(int _width, int _height, const Z &initial) - : data(NULL), width(_width), height(_height), size(_width * _height) -{ - data = new Z [ size ]; - init(initial); -} - -template <typename Z> -Matrix<Z>::Matrix(int _width, int _height) - : data(NULL), width(_width), height(_height), size(_width * _height) -{ - data = new Z [ size ]; -} - -template <typename Z> -Matrix<Z>::~Matrix() -{ - delete [] data; -} - -template <typename Z> -void Matrix<Z>::init(const Z &initial) -{ - for (int i = 0; i < size; ++i) - data[i] = initial; -} - // A fixed array centered around the origin. template <class TYPE, int RADIUS> class SquareArray { //----------------------------------- diff --git a/crawl-ref/source/fixvec.h b/crawl-ref/source/fixvec.h index 94ea8b5315..476eded773 100644 --- a/crawl-ref/source/fixvec.h +++ b/crawl-ref/source/fixvec.h @@ -7,11 +7,6 @@ #ifndef FIXVEC_H #define FIXVEC_H -#ifdef TARGET_COMPILER_VC -// Benign: FixedVector has an array in member init list -# pragma warning(disable : 4351) -#endif - #include <cstdarg> #include <cstring> diff --git a/crawl-ref/source/ghost.cc b/crawl-ref/source/ghost.cc index 901a4b92d4..6cb75f44d0 100644 --- a/crawl-ref/source/ghost.cc +++ b/crawl-ref/source/ghost.cc @@ -16,6 +16,7 @@ #include "externs.h" #include "itemname.h" #include "itemprop.h" +#include "mon-iter.h" #include "ng-input.h" #include "random.h" #include "skills2.h" @@ -67,8 +68,8 @@ static spell_type search_order_conj[] = { SPELL_SHOCK, SPELL_SANDBLAST, SPELL_MAGIC_DART, - SPELL_SLEEP, - SPELL_BACKLIGHT, + SPELL_HIBERNATION, + SPELL_CORONA, SPELL_NO_SPELL, // end search }; @@ -84,6 +85,7 @@ static spell_type search_order_third[] = { SPELL_DEMONIC_HORDE, SPELL_HASTE, SPELL_SUMMON_UGLY_THING, + SPELL_SWIFTNESS, SPELL_SUMMON_ICE_BEAST, SPELL_ANIMATE_DEAD, // 10 @@ -113,7 +115,7 @@ static spell_type search_order_misc[] = { SPELL_TELEPORT_OTHER, // 10 SPELL_DIG, - SPELL_BACKLIGHT, + SPELL_CORONA, SPELL_NO_SPELL, // end search }; @@ -846,16 +848,13 @@ void ghost_demon::announce_ghost(const ghost_demon &g) void ghost_demon::find_extra_ghosts( std::vector<ghost_demon> &gs, int n ) { - for (int i = 0; n > 0 && i < MAX_MONSTERS; ++i) + for (monster_iterator mi; mi; ++mi) { - if (!menv[i].alive()) - continue; - - if (menv[i].type == MONS_PLAYER_GHOST && menv[i].ghost.get()) + if (mi->type == MONS_PLAYER_GHOST && mi->ghost.get()) { // Bingo! - announce_ghost(*menv[i].ghost); - gs.push_back(*menv[i].ghost); + announce_ghost(*(mi->ghost)); + gs.push_back(*(mi->ghost)); --n; } } diff --git a/crawl-ref/source/godabil.cc b/crawl-ref/source/godabil.cc index 8bac2d4ee0..69986ec4be 100644 --- a/crawl-ref/source/godabil.cc +++ b/crawl-ref/source/godabil.cc @@ -23,8 +23,9 @@ #include "misc.h" #include "mon-act.h" #include "mon-behv.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-iter.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "mon-util.h" #include "mutation.h" #include "options.h" @@ -203,22 +204,21 @@ static bool _yred_enslaved_souls_on_level_disappear() { bool success = false; - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi; mi; ++mi) { - monsters *monster = &menv[i]; - if (_is_yred_enslaved_soul(monster)) + if (_is_yred_enslaved_soul(*mi)) { #ifdef DEBUG_DIAGNOSTICS mprf(MSGCH_DIAGNOSTICS, "Undead soul disappearing: %s on level %d, branch %d", - monster->name(DESC_PLAIN).c_str(), + mi->name(DESC_PLAIN).c_str(), static_cast<int>(you.your_level), static_cast<int>(you.where_are_you)); #endif - simple_monster_message(monster, " is freed."); + simple_monster_message(*mi, " is freed."); // The monster disappears. - monster_die(monster, KILL_DISMISSED, NON_MONSTER); + monster_die(*mi, KILL_DISMISSED, NON_MONSTER); success = true; } @@ -386,6 +386,7 @@ int fungal_bloom() const int mushroom = create_monster( mgen_data(MONS_TOADSTOOL, BEH_FRIENDLY, + &you, 0, 0, pos, @@ -458,6 +459,7 @@ static int _create_plant(coord_def & target) const int plant = create_monster(mgen_data (MONS_PLANT, BEH_FRIENDLY, + &you, 0, 0, target, @@ -560,6 +562,7 @@ bool sunlight() // Create a plant. const int plant = create_monster(mgen_data(MONS_PLANT, BEH_HOSTILE, + &you, 0, 0, target, @@ -876,6 +879,7 @@ int rain(const coord_def &target) const int plant = create_monster(mgen_data (coinflip() ? MONS_PLANT : MONS_FUNGUS, BEH_GOOD_NEUTRAL, + &you, 0, 0, *rad, @@ -953,6 +957,7 @@ int corpse_spores(beh_type behavior) int rc = create_monster(mgen_data(MONS_GIANT_SPORE, behavior, + &you, 0, 0, *rad, diff --git a/crawl-ref/source/goditem.cc b/crawl-ref/source/goditem.cc index f5c6e8976b..cfe29fcd8f 100644 --- a/crawl-ref/source/goditem.cc +++ b/crawl-ref/source/goditem.cc @@ -429,15 +429,23 @@ bool god_hates_rod(const item_def& item) conduct_type good_god_hates_item_handling(const item_def &item) { - if (!is_good_god(you.religion) || !is_evil_item(item)) + if (!is_good_god(you.religion) + || (!is_unholy_item(item) && !is_evil_item(item))) + { return (DID_NOTHING); + } + + if (item_type_known(item)) + { + if (is_evil_item(item)) + return (DID_NECROMANCY); + else + return (DID_UNHOLY); + } if (is_demonic(item)) return (DID_UNHOLY); - if (item_type_known(item)) - return (DID_NECROMANCY); - return (DID_NOTHING); } @@ -590,7 +598,7 @@ bool god_dislikes_spell_type(spell_type spell, god_type god) // into a state where attacking them would be unchivalrous. if (spell == SPELL_CAUSE_FEAR || spell == SPELL_PARALYSE || spell == SPELL_CONFUSE || spell == SPELL_MASS_CONFUSION - || spell == SPELL_SLEEP || spell == SPELL_MASS_SLEEP) + || spell == SPELL_HIBERNATION || spell == SPELL_ENGLACIATION) { return (true); } diff --git a/crawl-ref/source/goditem.h b/crawl-ref/source/goditem.h index e08c09b43b..f6e9e3caf0 100644 --- a/crawl-ref/source/goditem.h +++ b/crawl-ref/source/goditem.h @@ -16,6 +16,7 @@ bool is_unholy_item(const item_def& item); bool is_potentially_evil_item(const item_def& item); bool is_evil_item(const item_def& item); bool is_chaotic_item(const item_def& item); +bool is_hasty_item(const item_def& item); bool is_holy_discipline(int discipline); bool is_evil_discipline(int discipline); bool is_holy_spell(spell_type spell, god_type god = GOD_NO_GOD); diff --git a/crawl-ref/source/godwrath.cc b/crawl-ref/source/godwrath.cc index d896de98c3..0408bb228c 100644 --- a/crawl-ref/source/godwrath.cc +++ b/crawl-ref/source/godwrath.cc @@ -22,8 +22,8 @@ #include "message.h" #include "misc.h" #include "mon-util.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "mutation.h" #include "ouch.h" #include "quiver.h" @@ -61,7 +61,8 @@ static bool _yred_random_zombified_hostile() else z_type = skel ? MONS_SKELETON_SMALL : MONS_ZOMBIE_SMALL; - return (create_monster(mgen_data::hostile_at(z_type, true, + return (create_monster(mgen_data::hostile_at(z_type, + "the anger of Yredelemnul", true, 0, 0, you.pos(), 0, GOD_YREDELEMNUL, z_base)) != -1); } @@ -83,7 +84,7 @@ static bool _okawaru_random_servant() : MONS_TITAN); // 5% return (create_monster( - mgen_data::hostile_at(mon_type, + mgen_data::hostile_at(mon_type, "the fury of Okawaru", true, 0, 0, you.pos(), 0, GOD_OKAWARU)) != -1); } @@ -202,7 +203,7 @@ static bool _zin_retribution() mon_pos = you.pos(); if (mons_place( - mgen_data::hostile_at(mon, + mgen_data::hostile_at(mon, "the power of Zin", true, 0, 0, mon_pos, 0, god)) != -1) { success = true; @@ -234,7 +235,7 @@ static bool _zin_retribution() confuse_player(3 + random2(10), false); break; case 1: - you.put_to_sleep(); + you.hibernate(); break; case 2: you.paralyse(NULL, 3 + random2(10)); @@ -372,7 +373,7 @@ static bool _cheibriados_retribution() case 2: case 3: mpr("You lose track of time."); - you.put_to_sleep(); + you.hibernate(); break; case 4: @@ -400,6 +401,7 @@ static bool _makhleb_retribution() mgen_data::hostile_at( static_cast<monster_type>( MONS_EXECUTIONER + random2(5)), + "the fury of Makhleb", true, 0, 0, you.pos(), 0, god)) != -1); simple_god_message(success ? " sends a greater servant after you!" @@ -417,6 +419,7 @@ static bool _makhleb_retribution() mgen_data::hostile_at( static_cast<monster_type>( MONS_NEQOXEC + random2(5)), + "the fury of Makhleb", true, 0, 0, you.pos(), 0, god)) != -1) { count++; @@ -445,6 +448,7 @@ static bool _kikubaaqudgha_retribution() { if (create_monster( mgen_data::hostile_at(MONS_REAPER, + "the malice of Kikubaaqudgha", true, 0, 0, you.pos(), 0, god)) != -1) { success = true; @@ -646,6 +650,7 @@ static bool _beogh_retribution() const int mon = create_monster( mgen_data::hostile_at(MONS_DANCING_WEAPON, + "the wrath of Beogh", true, 0, 0, you.pos(), 0, god)); if (mon != -1) @@ -724,6 +729,7 @@ static bool _beogh_retribution() int mons = create_monster( mgen_data::hostile_at(punisher, + "the wrath of Beogh", true, 0, 0, you.pos(), MG_PERMIT_BANDS, god)); // sometimes name band leader @@ -835,6 +841,7 @@ static bool _lugonu_retribution() mgen_data::hostile_at( static_cast<monster_type>( MONS_GREEN_DEATH + random2(3)), + "the touch of Lugonu", true, 0, 0, you.pos(), 0, god)) != -1); simple_god_message(success ? " sends a demon after you!" @@ -851,6 +858,7 @@ static bool _lugonu_retribution() mgen_data::hostile_at( static_cast<monster_type>( MONS_NEQOXEC + random2(5)), + "the touch of Lugonu", true, 0, 0, you.pos(), 0, god)) != -1) { success = true; @@ -977,6 +985,7 @@ static bool _jiyva_retribution() if (create_monster( mgen_data::hostile_at(static_cast<monster_type>(slime), + "the vengence of Jiyva", true, 0, 0, you.pos(), 0, god)) != -1) { success = true; @@ -1043,12 +1052,14 @@ static bool _fedhas_retribution() unsigned free_thresh = 30; mgen_data temp(MONS_OKLOB_PLANT, - BEH_HOSTILE, 0, 0, + BEH_HOSTILE, 0, 0, 0, coord_def(), MHITNOT, MG_FORCE_PLACE, GOD_FEDHAS); + temp.non_actor_summoner = "the enmity of Fedhas Madash"; + // If we have a lot of space to work with (the circle with // radius 6 is substantially unoccupied), we can do something // flashy. diff --git a/crawl-ref/source/hiscores.cc b/crawl-ref/source/hiscores.cc index 73b19f57a8..8c87b7bc41 100644 --- a/crawl-ref/source/hiscores.cc +++ b/crawl-ref/source/hiscores.cc @@ -499,6 +499,8 @@ void scorefile_entry::init_from(const scorefile_entry &se) mon_num = se.mon_num; death_source_name = se.death_source_name; auxkilldata = se.auxkilldata; + indirectkiller = se.indirectkiller; + killerpath = se.killerpath; dlvl = se.dlvl; level_type = se.level_type; branch = se.branch; @@ -594,6 +596,8 @@ void scorefile_entry::init_with_fields() death_type = str_to_kill_method(fields->str_field("ktyp")); death_source_name = fields->str_field("killer"); auxkilldata = fields->str_field("kaux"); + indirectkiller = fields->str_field("ikiller"); + killerpath = fields->str_field("kpath"); branch = str_to_branch(fields->str_field("br"), BRANCH_MAIN_DUNGEON); dlvl = fields->int_field("lvl"); @@ -713,6 +717,8 @@ void scorefile_entry::set_score_fields() const fields->add_field("dam", "%d", damage); fields->add_field("kaux", "%s", auxkilldata.c_str()); + fields->add_field("ikiller", "%s", indirectkiller.c_str()); + fields->add_field("kpath", "%s", killerpath.c_str()); if (piety > 0) fields->add_field("piety", "%d", piety); @@ -837,11 +843,33 @@ void scorefile_entry::init_death_cause(int dam, int dsrc, death_source_name += " (shapeshifter)"; else if (monster->has_ench(ENCH_GLOWING_SHAPESHIFTER)) death_source_name += " (glowing shapeshifter)"; + + if (monster->props.exists("blame")) + { + const CrawlVector& blame = monster->props["blame"].get_vector(); + + indirectkiller = blame[blame.size() - 1].get_string(); + killerpath = ""; + + for (CrawlVector::const_iterator it = blame.begin(); + it != blame.end(); ++it) + { + killerpath = killerpath + ":" + xlog_escape(it->get_string()); + } + + killerpath.erase(killerpath.begin()); + } + else + { + indirectkiller = death_source_name; + killerpath = ""; + } } else { mon_num = 0; death_source_name.clear(); + indirectkiller = killerpath = ""; } if (death_type == KILLED_BY_WEAKNESS @@ -871,6 +899,8 @@ void scorefile_entry::reset() mon_num = 0; death_source_name.clear(); auxkilldata.clear(); + indirectkiller.clear(); + killerpath.clear(); dlvl = 0; level_type = LEVEL_DUNGEON; branch = BRANCH_MAIN_DUNGEON; @@ -1850,6 +1880,9 @@ std::string scorefile_entry::death_description(death_desc_verbosity verbosity) else if (needs_called_by_monster_line) desc += death_source_name; + if (!killerpath.empty()) + desc += "[" + indirectkiller + "]"; + if (needs_damage && damage > 0) desc += " " + damage_string(true); } @@ -1932,6 +1965,31 @@ std::string scorefile_entry::death_description(death_desc_verbosity verbosity) needs_damage = true; } + if (!killerpath.empty()) + { + std::vector<std::string> summoners + = xlog_split_fields(killerpath); + + for (std::vector<std::string>::iterator it = summoners.begin(); + it != summoners.end(); ++it) + { + if (!semiverbose) + { + desc += "... summoned by " + *it; + desc += _hiscore_newline_string(); + } + else + { + desc += " (summoned by " + *it; + } + } + + if (semiverbose) + { + desc += std::string(summoners.size(), ')'); + } + } + if (!semiverbose) { if (needs_damage && !done_damage && damage > 0) @@ -1989,23 +2047,23 @@ xlog_fields::xlog_fields(const std::string &line) : fields(), fieldmap() init(line); } -std::string::size_type -xlog_fields::next_separator(const std::string &s, - std::string::size_type start) const +static std::string::size_type +_xlog_next_separator(const std::string &s, + std::string::size_type start) { std::string::size_type p = s.find(':', start); if (p != std::string::npos && p < s.length() - 1 && s[p + 1] == ':') - return next_separator(s, p + 2); + return _xlog_next_separator(s, p + 2); return (p); } -std::vector<std::string> xlog_fields::split_fields(const std::string &s) const +std::vector<std::string> xlog_split_fields(const std::string &s) { std::string::size_type start = 0, end = 0; std::vector<std::string> fs; - for ( ; (end = next_separator(s, start)) != std::string::npos; + for ( ; (end = _xlog_next_separator(s, start)) != std::string::npos; start = end + 1 ) { fs.push_back( s.substr(start, end - start) ); @@ -2019,7 +2077,7 @@ std::vector<std::string> xlog_fields::split_fields(const std::string &s) const void xlog_fields::init(const std::string &line) { - std::vector<std::string> rawfields = split_fields(line); + std::vector<std::string> rawfields = xlog_split_fields(line); for (int i = 0, size = rawfields.size(); i < size; ++i) { const std::string field = rawfields[i]; @@ -2037,13 +2095,13 @@ void xlog_fields::init(const std::string &line) } // xlogfile escape: s/:/::/g -std::string xlog_fields::xlog_escape(const std::string &s) const +std::string xlog_escape(const std::string &s) { return replace_all(s, ":", "::"); } // xlogfile unescape: s/::/:/g -std::string xlog_fields::xlog_unescape(const std::string &s) const +std::string xlog_unescape(const std::string &s) { return replace_all(s, "::", ":"); } diff --git a/crawl-ref/source/hiscores.h b/crawl-ref/source/hiscores.h index f2b4fd53a4..2fc108c37d 100644 --- a/crawl-ref/source/hiscores.h +++ b/crawl-ref/source/hiscores.h @@ -29,6 +29,11 @@ void mark_milestone(const std::string &type, const std::string &milestone); std::string xlog_status_line(); #endif +std::string xlog_unescape(const std::string &); +std::string xlog_escape(const std::string &); + +std::vector<std::string> xlog_split_fields(const std::string &s); + class xlog_fields { public: @@ -46,12 +51,7 @@ public: long long_field(const std::string &) const; private: - std::string xlog_unescape(const std::string &) const; - std::string xlog_escape(const std::string &) const; void map_fields() const; - std::string::size_type next_separator(const std::string &s, - std::string::size_type start) const; - std::vector<std::string> split_fields(const std::string &s) const; private: typedef std::vector< std::pair<std::string, std::string> > xl_fields; @@ -79,6 +79,8 @@ public: int mon_num; // sigh... std::string death_source_name; // overrides death_source std::string auxkilldata; // weapon wielded, spell cast, etc + std::string indirectkiller; // the effect or real monster that summoned + std::string killerpath; // colon-separated intermediate killers char dlvl; // dungeon level (relative) level_area_type level_type; // what kind of level died on.. branch_type branch; // dungeon branch diff --git a/crawl-ref/source/it_use2.cc b/crawl-ref/source/it_use2.cc index b8cee7b101..bbe84c93e7 100644 --- a/crawl-ref/source/it_use2.cc +++ b/crawl-ref/source/it_use2.cc @@ -304,7 +304,7 @@ bool potion_effect(potion_type pot_eff, int pow, bool drank_it, bool was_known) // And also cancel backlight (for whatever good that will // do). - you.duration[DUR_BACKLIGHT] = 0; + you.duration[DUR_CORONA] = 0; return (true); } @@ -324,7 +324,7 @@ bool potion_effect(potion_type pot_eff, int pow, bool drank_it, bool was_known) } // Invisibility cancels backlight. - you.duration[DUR_BACKLIGHT] = 0; + you.duration[DUR_CORONA] = 0; // Now multiple invisiblity casts aren't as good. -- bwr if (!you.duration[DUR_INVIS]) diff --git a/crawl-ref/source/it_use3.cc b/crawl-ref/source/it_use3.cc index f36bae0148..d1bfd030c6 100644 --- a/crawl-ref/source/it_use3.cc +++ b/crawl-ref/source/it_use3.cc @@ -30,7 +30,7 @@ #include "itemprop.h" #include "mapmark.h" #include "message.h" -#include "monplace.h" +#include "mon-place.h" #include "misc.h" #include "player.h" #include "religion.h" @@ -145,8 +145,8 @@ void shadow_lantern_effect() { if (x_chance_in_y(player_spec_death() + 1, 8)) { - create_monster(mgen_data(MONS_SHADOW, BEH_FRIENDLY, 2, 0, you.pos(), - MHITYOU)); + create_monster(mgen_data(MONS_SHADOW, BEH_FRIENDLY, &you, 2, 0, + you.pos(), MHITYOU)); item_def *lantern = you.weapon(); @@ -336,7 +336,7 @@ static bool evoke_horn_of_geryon() { mpr("You produce a hideous howling noise!", MSGCH_SOUND); create_monster( - mgen_data::hostile_at(MONS_BEAST, + mgen_data::hostile_at(MONS_BEAST, "the horn of Geryon", true, 4, 0, you.pos())); } return (rc); @@ -352,7 +352,7 @@ static bool _efreet_flask(int slot) create_monster( mgen_data(MONS_EFREET, friendly ? BEH_FRIENDLY : BEH_HOSTILE, - 0, 0, you.pos(), + &you, 0, 0, you.pos(), MHITYOU, MG_FORCE_BEH)); if (monster != -1) @@ -530,6 +530,7 @@ void tome_of_power(int slot) { if (create_monster( mgen_data::hostile_at(MONS_ABOMINATION_SMALL, + "a tome of Destruction", true, 6, 0, you.pos())) != -1) { mpr("A horrible Thing appears!"); @@ -630,7 +631,7 @@ static bool _box_of_beasts(item_def &box) beha = BEH_HOSTILE; if (create_monster( - mgen_data(beasty, beha, 2 + random2(4), 0, + mgen_data(beasty, beha, &you, 2 + random2(4), 0, you.pos(), MHITYOU)) != -1) { success = true; diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc index 8214497c93..e9a0160bea 100644 --- a/crawl-ref/source/item_use.cc +++ b/crawl-ref/source/item_use.cc @@ -45,8 +45,8 @@ #include "misc.h" #include "mon-behv.h" #include "mon-util.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "notes.h" #include "options.h" #include "ouch.h" @@ -519,10 +519,14 @@ void wield_effects(int item_wield_2, bool showMsgs) { if (is_holy_item(item) && you.religion == GOD_YREDELEMNUL) mpr("You really shouldn't be using a holy item like this."); + else if (is_unholy_item(item) && is_good_god(you.religion)) + mpr("You really shouldn't be using an unholy item like this."); else if (is_evil_item(item) && is_good_god(you.religion)) mpr("You really shouldn't be using an evil item like this."); else if (is_chaotic_item(item) && you.religion == GOD_ZIN) mpr("You really shouldn't be using a chaotic item like this."); + else if (is_hasty_item(item) && you.religion == GOD_CHEIBRIADOS) + mpr("You really shouldn't be using a fast item like this."); } // Call unrandrt equip func before item is identified. @@ -1790,8 +1794,8 @@ static bool _reaping_hit_victim(bolt& beam, actor* victim, int dmg, int corpse) } int midx = NON_MONSTER; - if (animate_remains(victim->pos(), CORPSE_BODY, beh, hitting, GOD_NO_GOD, - true, true, true, &midx) <= 0) + if (animate_remains(victim->pos(), CORPSE_BODY, beh, hitting, agent, "", + GOD_NO_GOD, true, true, true, &midx) <= 0) { return (false); } @@ -1894,6 +1898,60 @@ static bool _dispersal_hit_victim(bolt& beam, actor* victim, int dmg, return (true); } +static bool _electricity_water_explosion(const bolt &beam, const actor *victim, + int &used) +{ + used = 1000; + + ASSERT(!beam.is_tracer); + if (you.can_see(victim)) + mpr("Electricity arcs through the water!"); + conduct_electricity(victim->pos(), beam.agent()); + + return (true); +} + +static bool _charged_hit_victim(bolt &beam, actor* victim, int &dmg, + std::string &dmg_msg) +{ + if (victim->airborne() || victim->res_elec() > 0 || !one_chance_in(3)) + return (false); + + dmg += 10 + random2(15); + + if (beam.is_tracer) + return (false); + + if (you.can_see(victim)) + if (victim->atype() == ACT_PLAYER) + dmg_msg = "You are electrocuted!"; + else + dmg_msg = "There is a sudden explosion of sparks!"; + + if (feat_is_water(grd(victim->pos()))) + { + beam.range_funcs.insert(beam.range_funcs.begin(), + _electricity_water_explosion); + } + + return (false); +} + +static bool _blessed_hit_victim(bolt &beam, actor* victim, int &dmg, + std::string &dmg_msg) +{ + if (victim->undead_or_demonic()) + { + dmg += 1 + (random2(dmg * 15) / 10); + + if (!beam.is_tracer && you.can_see(victim)) + dmg_msg = victim->name(DESC_CAP_THE) + " " + + victim->conj_verb("convulse") + "!"; + } + + return (false); +} + bool setup_missile_beam(const actor *agent, bolt &beam, item_def &item, std::string &ammo_name, bool &returning) { @@ -1992,7 +2050,11 @@ bool setup_missile_beam(const actor *agent, bolt &beam, item_def &item, const bool silver = (ammo_brand == SPMSL_SILVER); const bool disperses = (ammo_brand == SPMSL_DISPERSAL); const bool reaping = (bow_brand == SPWPN_REAPING - || ammo_brand == SPMSL_REAPING); + || ammo_brand == SPMSL_REAPING) + && bow_brand != SPWPN_HOLY_WRATH; + const bool charged = bow_brand == SPWPN_ELECTROCUTION; + const bool blessed = bow_brand == SPWPN_HOLY_WRATH + && ammo_brand != SPMSL_REAPING; ASSERT(!exploding || !is_artefact(item)); @@ -2061,6 +2123,10 @@ bool setup_missile_beam(const actor *agent, bolt &beam, item_def &item, beam.hit_funcs.push_back(_reaping_hit_victim); if (disperses) beam.hit_funcs.push_back(_dispersal_hit_victim); + if (charged) + beam.damage_funcs.push_back(_charged_hit_victim); + if (blessed) + beam.damage_funcs.push_back(_blessed_hit_victim); if (reaping && ammo.special != SPMSL_REAPING) { @@ -2092,6 +2158,18 @@ bool setup_missile_beam(const actor *agent, bolt &beam, item_def &item, ammo_name = "silvery " + ammo_name; } + if (charged) + { + beam.name = "charged " + beam.name; + ammo_name = "charged " + ammo_name; + } + + if (blessed) + { + beam.name = "blessed " + beam.name; + ammo_name = "blessed " + ammo_name; + } + // Do this here so that we get all the name mods except for a // redundant "exploding". if (exploding) @@ -4987,11 +5065,12 @@ static void _vulnerability_scroll() const enchant_type lost_enchantments[] = { ENCH_SLOW, ENCH_HASTE, + ENCH_SWIFT, ENCH_MIGHT, ENCH_FEAR, ENCH_CONFUSION, ENCH_INVIS, - ENCH_BACKLIGHT, + ENCH_CORONA, ENCH_CHARM, ENCH_PARALYSIS, ENCH_PETRIFYING, @@ -5183,7 +5262,7 @@ void read_scroll(int slot) { const int monster = create_monster( mgen_data(MONS_ABOMINATION_SMALL, BEH_FRIENDLY, - 0, 0, you.pos(), MHITYOU, + &you, 0, 0, you.pos(), MHITYOU, MG_FORCE_BEH)); if (monster != -1) { diff --git a/crawl-ref/source/itemname.cc b/crawl-ref/source/itemname.cc index 16adb7a234..5de5f16256 100644 --- a/crawl-ref/source/itemname.cc +++ b/crawl-ref/source/itemname.cc @@ -1637,9 +1637,14 @@ std::string item_def::name_aux(description_level_type desc, if (food_is_rotten(*this) && !dbname) buff << "rotting "; - const std::string _name = get_corpse_name(*this); + unsigned long name_type; + + const std::string _name = get_corpse_name(*this, &name_type); const bool shaped = starts_with(_name, "shaped "); + if (!_name.empty() && name_type == MF_NAME_ADJECTIVE) + buff << _name << " "; + if (!dbname && !starts_with(_name, "the ")) { buff << mons_type_name(it_plus, DESC_PLAIN) << ' '; @@ -1655,8 +1660,13 @@ std::string item_def::name_aux(description_level_type desc, else buff << "corpse bug"; - if (!_name.empty() && !shaped) - buff << " of " << _name; + if (!_name.empty() && !shaped && name_type != MF_NAME_ADJECTIVE) + { + if (name_type == MF_NAME_SUFFIX) + buff << " " << _name; + else + buff << " of " << _name; + } break; } @@ -3065,12 +3075,18 @@ bool is_named_corpse(const item_def &corpse) return (corpse.props.exists(CORPSE_NAME_KEY)); } -std::string get_corpse_name(const item_def &corpse) +std::string get_corpse_name(const item_def &corpse, unsigned long *name_type) { ASSERT(corpse.base_type == OBJ_CORPSES); if (!corpse.props.exists(CORPSE_NAME_KEY)) return (""); + if (name_type != NULL) + { + *name_type + = (unsigned long) corpse.props[CORPSE_NAME_TYPE_KEY].get_long(); + } + return (corpse.props[CORPSE_NAME_KEY].get_string()); } diff --git a/crawl-ref/source/itemname.h b/crawl-ref/source/itemname.h index 731c7b7443..271bf2d340 100644 --- a/crawl-ref/source/itemname.h +++ b/crawl-ref/source/itemname.h @@ -10,7 +10,8 @@ #include "externs.h" -#define CORPSE_NAME_KEY "corpse_name_key" +#define CORPSE_NAME_KEY "corpse_name_key" +#define CORPSE_NAME_TYPE_KEY "corpse_name_type_key" struct item_types_pair { @@ -126,6 +127,7 @@ std::vector<std::string> item_name_list_for_glyph(unsigned glyph); const char* wand_type_name(int wandtype); bool is_named_corpse(const item_def &corpse); -std::string get_corpse_name(const item_def &corpse); +std::string get_corpse_name(const item_def &corpse, + unsigned long *name_type = NULL); #endif diff --git a/crawl-ref/source/itemprop.cc b/crawl-ref/source/itemprop.cc index 565827c41c..20acaf45aa 100644 --- a/crawl-ref/source/itemprop.cc +++ b/crawl-ref/source/itemprop.cc @@ -27,7 +27,7 @@ #include "itemprop.h" #include "macro.h" #include "mon-util.h" -#include "monstuff.h" +#include "mon-stuff.h" #include "notes.h" #include "player.h" #include "quiver.h" @@ -485,7 +485,7 @@ void do_curse_item( item_def &item, bool quiet ) { if (!quiet) { - mprf("Your %s glows black briefly, but repels the curse", + mprf("Your %s glows black briefly, but repels the curse.", item.name(DESC_PLAIN).c_str()); } return; diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc index 625dafd11d..2e366841c7 100644 --- a/crawl-ref/source/items.cc +++ b/crawl-ref/source/items.cc @@ -43,8 +43,8 @@ #include "libutil.h" #include "message.h" #include "misc.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "mon-util.h" #include "mutation.h" #include "notes.h" diff --git a/crawl-ref/source/kills.cc b/crawl-ref/source/kills.cc index 589a9b3972..6857c3d82c 100644 --- a/crawl-ref/source/kills.cc +++ b/crawl-ref/source/kills.cc @@ -10,7 +10,7 @@ #include "describe.h" #include "mon-util.h" -#include "monstuff.h" +#include "mon-stuff.h" #include "files.h" #include "ghost.h" #include "place.h" diff --git a/crawl-ref/source/l_defs.h b/crawl-ref/source/l_defs.h index 641af4a117..8d0974a918 100644 --- a/crawl-ref/source/l_defs.h +++ b/crawl-ref/source/l_defs.h @@ -14,6 +14,7 @@ const char *dungeon_feature_name(dungeon_feature_type feat); std::string dgn_set_default_depth(const std::string &s); void dgn_reset_default_depth(); bool in_show_bounds(const coord_def &c); +coord_def player2grid(const coord_def &p); #endif diff --git a/crawl-ref/source/l_dgnmon.cc b/crawl-ref/source/l_dgnmon.cc index 4b8a7bc5ba..7c37b6bdb0 100644 --- a/crawl-ref/source/l_dgnmon.cc +++ b/crawl-ref/source/l_dgnmon.cc @@ -11,8 +11,8 @@ #include "dungeon.h" #include "mapdef.h" #include "mon-util.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-place.h" +#include "mon-stuff.h" #define MONSLIST_METATABLE "crawldgn.monster_list" diff --git a/crawl-ref/source/l_libs.h b/crawl-ref/source/l_libs.h index ecbecd12ba..a97eb7dc75 100644 --- a/crawl-ref/source/l_libs.h +++ b/crawl-ref/source/l_libs.h @@ -19,6 +19,7 @@ void cluaopen_item(lua_State *ls); void cluaopen_kills(lua_State *ls); // defined in kills.cc void cluaopen_moninf(lua_State *ls); void cluaopen_options(lua_State *ls); +void cluaopen_travel(lua_State *ls); void cluaopen_view(lua_State *ls); void cluaopen_you(lua_State *ls); diff --git a/crawl-ref/source/l_mons.cc b/crawl-ref/source/l_mons.cc index 8ace3eb119..5f9defaf6c 100644 --- a/crawl-ref/source/l_mons.cc +++ b/crawl-ref/source/l_mons.cc @@ -5,7 +5,7 @@ #include "delay.h" #include "mon-util.h" -#include "monstuff.h" +#include "mon-stuff.h" ///////////////////////////////////////////////////////////////////// // Monster handling @@ -39,6 +39,26 @@ void push_monster(lua_State *ls, monsters *mons) MDEF(name) { + PLUARET(string, mons->name(DESC_PLAIN, true).c_str()); +} + +MDEF(base_name) +{ + PLUARET(string, mons->base_name(DESC_PLAIN, true).c_str()); +} + +MDEF(full_name) +{ + PLUARET(string, mons->full_name(DESC_PLAIN, true).c_str()); +} + +MDEF(db_name) +{ + PLUARET(string, mons->name(DESC_DBNAME, true).c_str()); +} + +MDEF(type_name) +{ PLUARET(string, mons_type_name(mons->type, DESC_PLAIN).c_str()); } @@ -145,14 +165,20 @@ struct MonsAccessor static MonsAccessor mons_attrs[] = { - { "name", l_mons_name }, + { "name", l_mons_name }, + { "base_name", l_mons_base_name }, + { "full_name", l_mons_full_name }, + { "db_name", l_mons_db_name }, + { "type_name", l_mons_type_name }, + { "x" , l_mons_x }, { "y" , l_mons_y }, { "hd" , l_mons_hd }, { "muse", l_mons_muse }, { "meat", l_mons_meat }, - { "dismiss", l_mons_dismiss }, - { "experience", l_mons_experience }, + + { "dismiss", l_mons_dismiss }, + { "experience", l_mons_experience }, { "random_teleport", l_mons_random_teleport } }; diff --git a/crawl-ref/source/l_travel.cc b/crawl-ref/source/l_travel.cc new file mode 100644 index 0000000000..8c32d65812 --- /dev/null +++ b/crawl-ref/source/l_travel.cc @@ -0,0 +1,54 @@ +/* + * File: l_travel.cc + * Summary: Travel and exclusions. + */ + +#include "AppHdr.h" + +#include "l_libs.h" +#include "l_defs.h" + +#include "cluautil.h" +#include "coord.h" +#include "exclude.h" +#include "player.h" + +LUAFN(l_set_exclude) +{ + coord_def s; + s.x = luaL_checkint(ls, 1); + s.y = luaL_checkint(ls, 2); + const coord_def p = player2grid(s); + if (!in_bounds(p)) + return (0); + int r = LOS_MAX_RADIUS; + if (lua_gettop(ls) > 2) + r = luaL_checkint(ls, 3); + set_exclude(p, r); + return (0); +} + +LUAFN(l_del_exclude) +{ + coord_def s; + s.x = luaL_checkint(ls, 1); + s.y = luaL_checkint(ls, 2); + const coord_def p = player2grid(s); + if (!in_bounds(p)) + return (0); + del_exclude(p); + return (0); +} + +static const struct luaL_reg travel_lib[] = +{ + { "set_exclude", l_set_exclude }, + { "del_exclude", l_del_exclude }, + + { NULL, NULL } +}; + +void cluaopen_travel(lua_State *ls) +{ + luaL_openlib(ls, "travel", travel_lib, 0); +} diff --git a/crawl-ref/source/lev-pand.cc b/crawl-ref/source/lev-pand.cc index 827e753cd1..a772d6e3d6 100644 --- a/crawl-ref/source/lev-pand.cc +++ b/crawl-ref/source/lev-pand.cc @@ -12,7 +12,7 @@ #include "externs.h" #include "dungeon.h" -#include "monplace.h" +#include "mon-place.h" #include "mon-pick.h" #include "random.h" diff --git a/crawl-ref/source/makefile b/crawl-ref/source/makefile index 2adc7a79ae..7f2819dd74 100644 --- a/crawl-ref/source/makefile +++ b/crawl-ref/source/makefile @@ -663,15 +663,11 @@ LIBS += $(CONTRIB_LIBS) $(EXTRA_LIBS) GAME_DEPENDS := $(DESTTILEFILES) $(OBJECTS) $(EXTRA_OBJECTS) $(CONTRIB_LIBS) SRC_PKG_BASE := stone_soup SRC_VERSION := $(shell git describe --tags --long) -PKG_SRC_DIR := $(SRC_PKG_BASE)-$(SRC_VERSION)-src -SRC_PKG_TAR := $(PKG_SRC_DIR).tbz2 +PKG_SRC_DIR := $(SRC_PKG_BASE)-$(SRC_VERSION) +SRC_PKG_TAR := $(PKG_SRC_DIR).tar.bz2 SRC_PKG_ZIP := $(PKG_SRC_DIR).zip -PKG_TIDY_LIST := $(UTIL)*.o $(LEVCOMP) *.o \ - $(UTIL)*.tab.cc $(UTIL)*.tab.h $(UTIL)*.lex.cc *.ixx -PKG_EXCLUDES := $(PWD)/misc/src-pkg-excludes.lst - -.PHONY: all test install clean clean-contrib distclean debug profile wizard +.PHONY: all test install clean clean-contrib distclean debug profile wizard package-source all: $(GAME) @@ -707,7 +703,7 @@ DEPS := $(OBJECTS:.o=.d) ifeq ($(shell which fastdep 2> /dev/null),) DEPEND := $(CXX) -MM $(ALL_CFLAGS) else -DEPEND := fastdep $(DEFINES) $(INCLUDES) +DEPEND := fastdep $(DEFINES) $(DEFINES_L) $(INCLUDES) $(INCLUDES_L) endif %.d: %.cc .cflags @@ -901,32 +897,26 @@ clean-rltiles: # # To package, you *must* have lex and yacc to generate the intermediates. -package-source: - +$(MAKE) distclean - +$(MAKE) prebuildyacc - +$(MAKE) pkgtidy - +$(MAKE) depend - +$(MAKE) removeold - +$(MAKE) vlink - +$(MAKE) pkgtarbz2 - +$(MAKE) pkgzip - -pkgtidy: - $(RM) $(PKG_TIDY_LIST) +BSRC = build/crawl-ref/source/ +package-source: prebuildyacc depend removeold + rm -rf build + mkdir build + (cd ../..;git ls-files| \ + grep -v -f crawl-ref/source/misc/src-pkg-excludes.lst| \ + tar cf - -T -)|tar xf - -C build + cp -p *.d $(BSRC) + for x in lua pcre sqlite; \ + do \ + mkdir -p $(BSRC)contrib/$$x; \ + (cd contrib/$$x;git ls-files|tar cf - -T -)| \ + tar xf - -C $(BSRC)contrib/$$x; \ + done + find build -name .gitignore -execdir rm -f '{}' + + cd build && mv crawl-ref $(PKG_SRC_DIR) + cd build && tar cfj ../../../$(SRC_PKG_TAR) $(PKG_SRC_DIR) + cd build && zip -rq ../../../$(SRC_PKG_ZIP) $(PKG_SRC_DIR) + rm -rf build removeold: if [ -f ../../$(SRC_PKG_TAR) ]; then $(RM) ../../$(SRC_PKG_TAR); fi if [ -f ../../$(SRC_PKG_ZIP) ]; then $(RM) ../../$(SRC_PKG_ZIP); fi - -# [ds] Existing directory names could produce a bad package! -vlink: - cd .. && WHERE=$$PWD && cd .. && \ - ( [ -e $(PKG_SRC_DIR) ] || ln -sf $$WHERE $(PKG_SRC_DIR) ) - -pkgtarbz2: - cd ../.. && tar -ch --bzip2 -f $(SRC_PKG_TAR) \ - -X $(PKG_EXCLUDES) $(PKG_SRC_DIR) - -pkgzip: - cd ../.. && zip -rq $(SRC_PKG_ZIP) $(PKG_SRC_DIR) \ - -x@$(PKG_EXCLUDES) diff --git a/crawl-ref/source/makefile.obj b/crawl-ref/source/makefile.obj index c85450cd5f..03fe8f2bd3 100644 --- a/crawl-ref/source/makefile.obj +++ b/crawl-ref/source/makefile.obj @@ -79,6 +79,7 @@ l_mapmrk.o \ l_moninf.o \ l_mons.o \ l_option.o \ +l_travel.o \ l_view.o \ l_you.o \ lev-pand.o \ @@ -103,12 +104,13 @@ mon-behv.o \ mon-cast.o \ mon-gear.o \ mon-info.o \ +mon-iter.o \ mon-pick.o \ mon-util.o \ -monplace.o \ -monspeak.o \ +mon-place.o \ +mon-speak.o \ monster.o \ -monstuff.o \ +mon-stuff.o \ mt19937ar.o \ mtransit.o \ mutation.o \ diff --git a/crawl-ref/source/makeitem.cc b/crawl-ref/source/makeitem.cc index 332187dd4e..645685ac06 100644 --- a/crawl-ref/source/makeitem.cc +++ b/crawl-ref/source/makeitem.cc @@ -1437,6 +1437,9 @@ static brand_type _determine_weapon_brand(const item_def& item, int item_level) rc = SPWPN_VORPAL; else rc = SPWPN_SPEED; + if (item.sub_type == WPN_HAND_CROSSBOW || item.sub_type == WPN_CROSSBOW) + if (one_chance_in(5)) + rc = SPWPN_ELECTROCUTION; break; } @@ -1552,12 +1555,12 @@ bool is_weapon_brand_ok(int type, int brand) case SPWPN_VORPAL: case SPWPN_CHAOS: case SPWPN_REAPING: + case SPWPN_HOLY_WRATH: + case SPWPN_ELECTROCUTION: break; // Melee-only brands. case SPWPN_FLAMING: case SPWPN_FREEZING: - case SPWPN_HOLY_WRATH: - case SPWPN_ELECTROCUTION: case SPWPN_ORC_SLAYING: case SPWPN_DRAGON_SLAYING: case SPWPN_DRAINING: @@ -2246,12 +2249,9 @@ bool is_armour_brand_ok(int type, int brand) case SPARM_STEALTH: return (slot == EQ_BOOTS); - case SPARM_RESISTANCE: - if (slot == EQ_SHIELD) - return (true); case SPARM_ARCHMAGI: - if (type != ARM_ROBE) - return (false); + return (type == ARM_ROBE); + case SPARM_PONDEROUSNESS: return (slot == EQ_BODY_ARMOUR); @@ -2269,25 +2269,20 @@ bool is_armour_brand_ok(int type, int brand) return (slot == EQ_GLOVES); case SPARM_SEE_INVISIBLE: - if (type == ARM_WIZARD_HAT) - return (false); case SPARM_INTELLIGENCE: return (slot == EQ_HELMET); case SPARM_FIRE_RESISTANCE: case SPARM_COLD_RESISTANCE: - if (slot == EQ_BOOTS && type != ARM_BOOTS) // both bardings + case SPARM_RESISTANCE: + return (true); // in portal vaults, these can happen on every slot + + case SPARM_MAGIC_RESISTANCE: + if (type == ARM_WIZARD_HAT) return (true); case SPARM_POISON_RESISTANCE: - case SPARM_MAGIC_RESISTANCE: case SPARM_POSITIVE_ENERGY: - if (brand == SPARM_POISON_RESISTANCE && slot == EQ_CLOAK) - return (true); - if (brand == SPARM_MAGIC_RESISTANCE && slot == EQ_CLOAK) - return (true); - if (brand == SPARM_MAGIC_RESISTANCE && type == ARM_WIZARD_HAT) - return (true); - return (slot == EQ_BODY_ARMOUR || slot == EQ_SHIELD); + return (slot == EQ_BODY_ARMOUR || slot == EQ_SHIELD || slot == EQ_CLOAK); case SPARM_SPIRIT_SHIELD: return (type == ARM_CAP || slot == EQ_SHIELD); diff --git a/crawl-ref/source/mapdef.cc b/crawl-ref/source/mapdef.cc index a9bff3cf52..ebafae76e2 100644 --- a/crawl-ref/source/mapdef.cc +++ b/crawl-ref/source/mapdef.cc @@ -31,7 +31,7 @@ #include "maps.h" #include "misc.h" #include "mon-cast.h" -#include "monplace.h" +#include "mon-place.h" #include "mon-util.h" #include "place.h" #include "random.h" @@ -1784,6 +1784,78 @@ std::string map_def::rewrite_chunk_errors(const std::string &s) const return (res); } +std::string map_def::validate_temple_map() +{ + std::vector<coord_def> altars = find_glyph('B'); + + if (has_tag_prefix("temple_overflow_")) + { + std::vector<std::string> tag_list = get_tags(); + std::string temple_tag; + + for (unsigned int i = 0; i < tag_list.size(); i++) + { + if (starts_with(tag_list[i], "temple_overflow_")) + { + temple_tag = tag_list[i]; + break; + } + } + + if (temple_tag.empty()) + return make_stringf("Unkown temple tag."); + + temple_tag = strip_tag_prefix(temple_tag, "temple_overflow_"); + + if (temple_tag.empty()) + return ("Malformed temple_overflow_ tag"); + + int num = atoi(temple_tag.c_str()); + + if (num == 0) + { + temple_tag = replace_all(temple_tag, "_", " "); + + god_type god = string_to_god(temple_tag.c_str(), true); + + if (god == GOD_NO_GOD) + { + return make_stringf("Invalid god name '%s'", + temple_tag.c_str()); + } + + // Assume that specialized single-god temples are set up + // properly. + return(""); + } + else + { + if ( ( (unsigned long) num ) != altars.size() ) + { + return make_stringf("Temple should contain %lu altars, but " + "has %d.", altars.size(), num); + } + } + } + + if (altars.empty()) + return ("Temple vault must contain at least one altar."); + + // TODO: check for substitutions and shuffles + + keyed_mapspec *spec = mapspec_for_key('B'); + + if (spec != NULL && spec->feat.feats.size() > 0) + return ("Can't change feat 'B' in temple (KFEAT)"); + + std::vector<god_type> god_list = temple_god_list(); + + if (altars.size() > god_list.size()) + return ("Temple vault has too many altars"); + + return (""); +} + std::string map_def::validate_map_def() { std::string err = run_lua(true); @@ -1794,6 +1866,15 @@ std::string map_def::validate_map_def() resolve(); test_lua_validate(true); + if ((place.branch == BRANCH_ECUMENICAL_TEMPLE + && place.level_type == LEVEL_DUNGEON) + || has_tag_prefix("temple_overflow_")) + { + err = validate_temple_map(); + if (!err.empty()) + return err; + } + if (orient == MAP_FLOAT || is_minivault()) { if (map.width() > GXM - MAPGEN_BORDER * 2 @@ -2991,6 +3072,8 @@ static int str_to_ego(item_spec &spec, std::string ego_str) "archmagi", "preservation", "reflection", + "spirit shield", + "archery", NULL }; @@ -3015,6 +3098,8 @@ static int str_to_ego(item_spec &spec, std::string ego_str) "returning", "chaos", "confuse", // 20 + "penetration", + "reaping", NULL }; @@ -3293,6 +3378,20 @@ item_spec item_list::parse_single_spec(std::string s) } else if (ego == -1) { + error = make_stringf("Ego '%s' is invalid for item '%s'.", + ego_str.c_str(), s.c_str()); + return (result); + } + else if (result.sub_type == OBJ_RANDOM) + { + // it will be assigned among appropriate ones later + } + else if (result.base_type == OBJ_WEAPONS + && !is_weapon_brand_ok(result.sub_type, ego) + || result.base_type == OBJ_ARMOUR + && !is_armour_brand_ok(result.sub_type, ego)) + // no missile brands are disallowed yet + { error = make_stringf("Ego '%s' is incompatible with item '%s'.", ego_str.c_str(), s.c_str()); return (result); diff --git a/crawl-ref/source/mapdef.h b/crawl-ref/source/mapdef.h index c70c16cece..791a929b10 100644 --- a/crawl-ref/source/mapdef.h +++ b/crawl-ref/source/mapdef.h @@ -19,7 +19,7 @@ #include "dlua.h" #include "enum.h" #include "externs.h" -#include "fixary.h" +#include "matrix.h" #include "fprop.h" #include "makeitem.h" #include "stuff.h" @@ -759,6 +759,7 @@ public: bool test_lua_veto(); std::string validate_map_def(); + std::string validate_temple_map(); void add_prelude_line(int line, const std::string &s); void add_main_line(int line, const std::string &s); diff --git a/crawl-ref/source/maps.cc b/crawl-ref/source/maps.cc index 06a47f6100..cbe4922382 100644 --- a/crawl-ref/source/maps.cc +++ b/crawl-ref/source/maps.cc @@ -24,7 +24,7 @@ #include "message.h" #include "mapdef.h" #include "mon-util.h" -#include "monplace.h" +#include "mon-place.h" #include "random.h" #include "state.h" #include "terrain.h" @@ -507,6 +507,8 @@ bool map_selector::accept(const map_def &mapdef) const && mapdef.place == place && !mapdef.has_tag("layout") && !mapdef.has_tag("place_unique") + && (!mapdef.has_tag_prefix("temple_") + || mapdef.has_tag_prefix("uniq_altar_")) && map_matches_layout_type(mapdef) && vault_unforbidden(mapdef)); case DEPTH: @@ -522,6 +524,8 @@ bool map_selector::accept(const map_def &mapdef) const && !mapdef.has_tag("bazaar") && !mapdef.has_tag("layout") && !mapdef.has_tag("place_unique") + && (!mapdef.has_tag_prefix("temple_") + || mapdef.has_tag_prefix("uniq_altar_")) && (!check_layout || map_matches_layout_type(mapdef)) && vault_unforbidden(mapdef)); case TAG: diff --git a/crawl-ref/source/matrix.h b/crawl-ref/source/matrix.h new file mode 100644 index 0000000000..520711ca88 --- /dev/null +++ b/crawl-ref/source/matrix.h @@ -0,0 +1,59 @@ +/* + * File: matrix.h + * Summary: Two-dimensional array class. + */ + +#ifndef MATRIX_H +#define MATRIX_H + +template <typename Z> +class Matrix { +public: + Matrix(int width, int height, const Z &initial); + Matrix(int width, int height); + ~Matrix(); + + void init(const Z &initial); + Z &operator () (int x, int y) + { + return data[x + y * width]; + } + const Z &operator () (int x, int y) const + { + return data[x + y * width]; + } + +private: + Z *data; + int width, height, size; +}; + +template <typename Z> +Matrix<Z>::Matrix(int _width, int _height, const Z &initial) + : data(NULL), width(_width), height(_height), size(_width * _height) +{ + data = new Z [ size ]; + init(initial); +} + +template <typename Z> +Matrix<Z>::Matrix(int _width, int _height) + : data(NULL), width(_width), height(_height), size(_width * _height) +{ + data = new Z [ size ]; +} + +template <typename Z> +Matrix<Z>::~Matrix() +{ + delete [] data; +} + +template <typename Z> +void Matrix<Z>::init(const Z &initial) +{ + for (int i = 0; i < size; ++i) + data[i] = initial; +} + +#endif // MATRIX_H diff --git a/crawl-ref/source/menu.cc b/crawl-ref/source/menu.cc index 8cb98b8680..af1454f22f 100644 --- a/crawl-ref/source/menu.cc +++ b/crawl-ref/source/menu.cc @@ -20,7 +20,7 @@ #ifdef USE_TILE #include "coord.h" - #include "monstuff.h" + #include "mon-stuff.h" #include "mon-util.h" #include "newgame.h" #include "terrain.h" diff --git a/crawl-ref/source/message.cc b/crawl-ref/source/message.cc index e87a988682..77fb18d697 100644 --- a/crawl-ref/source/message.cc +++ b/crawl-ref/source/message.cc @@ -27,7 +27,7 @@ #include "libutil.h" #include "macro.h" #include "message.h" -#include "monstuff.h" +#include "mon-stuff.h" #include "notes.h" #include "random.h" #include "religion.h" diff --git a/crawl-ref/source/mgrow.cc b/crawl-ref/source/mgrow.cc index 3693e43dd4..7be571d541 100644 --- a/crawl-ref/source/mgrow.cc +++ b/crawl-ref/source/mgrow.cc @@ -9,8 +9,8 @@ #include "enum.h" #include "mgrow.h" #include "mon-util.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "random.h" // Base experience required by a monster to reach HD 1. diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc index 0c4d997d89..944cf6aa98 100644 --- a/crawl-ref/source/misc.cc +++ b/crawl-ref/source/misc.cc @@ -55,9 +55,10 @@ #include "makeitem.h" #include "mapmark.h" #include "message.h" -#include "monplace.h" +#include "mon-place.h" +#include "mon-iter.h" #include "mon-util.h" -#include "monstuff.h" +#include "mon-stuff.h" #include "ouch.h" #include "output.h" #include "overmap.h" @@ -2968,14 +2969,11 @@ static 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++) + for (monster_iterator mi(&you.get_los()); mi; ++mi) { - monster = &menv[it]; - - if (monster->alive() && mons_near(monster) && !monster->friendly()) + if (!mi->friendly()) { - const int xp = exper_value(monster); + const int xp = exper_value(*mi); const double log_xp = log((double)xp); sum += log_xp; if (xp > highest_xp) @@ -2983,7 +2981,7 @@ static void monster_threat_values(double *general, double *highest, highest_xp = xp; *highest = log_xp; } - if (!you.can_see(monster)) + if (!you.can_see(*mi)) *invis = true; } } @@ -3128,6 +3126,27 @@ void reveal_secret_door(const coord_def& p) : DNGN_OPEN_DOOR; viewwindow(false); learned_something_new(TUT_SEEN_SECRET_DOOR, p); + + // If a transparent secret door was forced open to preserve LOS, + // check if it had an opening prompt. + if (grd(p) == DNGN_OPEN_DOOR) + { + std::string door_open_prompt = + env.markers.property_at(p, MAT_ANY, "door_open_prompt"); + + if (!door_open_prompt.empty()) + { + mprf("That secret door had a prompt on it:", MSGCH_PROMPT); + mprf(MSGCH_PROMPT, "%s", door_open_prompt.c_str()); + + if (!is_exclude_root(p)) + { + if (yesno("Put travel exclusion on door? (Y/n)", true, 'y')) + // Zero radius exclusion right on top of door. + set_exclude(p, 0); + } + } + } } // A feeble attempt at Nethack-like completeness for cute messages. diff --git a/crawl-ref/source/misc/src-pkg-excludes.lst b/crawl-ref/source/misc/src-pkg-excludes.lst index 1d28c6f19f..95b38dac4e 100644 --- a/crawl-ref/source/misc/src-pkg-excludes.lst +++ b/crawl-ref/source/misc/src-pkg-excludes.lst @@ -1,3 +1,11 @@ -,svn -**/.svn/* -.* +^\. +/\. +git-hooks +contrib/freetype +contrib/libpng +contrib/lua +contrib/pcre +contrib/sdl +contrib/sdl-image +contrib/sqlite +contrib/zlib diff --git a/crawl-ref/source/mon-abil.cc b/crawl-ref/source/mon-abil.cc index 16bde8d4f4..9d53edc726 100644 --- a/crawl-ref/source/mon-abil.cc +++ b/crawl-ref/source/mon-abil.cc @@ -24,9 +24,10 @@ #include "mon-act.h" #include "mon-behv.h" #include "mon-cast.h" -#include "monplace.h" -#include "monspeak.h" -#include "monstuff.h" +#include "mon-iter.h" +#include "mon-place.h" +#include "mon-speak.h" +#include "mon-stuff.h" #include "random.h" #include "spl-mis.h" #include "spl-util.h" @@ -192,6 +193,7 @@ static bool _do_split(monsters *thing, coord_def & target) thing->behaviour, 0, 0, + 0, target, thing->foe, MG_FORCE_PLACE)); @@ -208,6 +210,8 @@ static bool _do_split(monsters *thing, coord_def & target) _split_ench_durations(thing, new_slime); new_slime->attitude = thing->attitude; new_slime->flags = thing->flags; + new_slime->props = thing->props; + // XXX copy summoner info if (you.can_see(thing)) mprf("%s splits.", thing->name(DESC_CAP_A).c_str()); @@ -546,7 +550,7 @@ static bool _silver_statue_effects(monsters *mons) mgen_data( summon_any_demon((coinflip() ? DEMON_COMMON : DEMON_LESSER)), - SAME_ATTITUDE(mons), 5, 0, foe->pos(), mons->foe)); + SAME_ATTITUDE(mons), mons, 5, 0, foe->pos(), mons->foe)); return (true); } return (false); @@ -591,44 +595,41 @@ static bool _orc_battle_cry(monsters *chief) const int boss_index = monster_index(chief); const int level = chief->hit_dice > 12? 2 : 1; std::vector<monsters*> seen_affected; - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi(chief); mi; ++mi) { - monsters *mon = &menv[i]; - if (mon != chief - && mon->alive() - && mons_species(mon->type) == MONS_ORC - && mons_aligned(boss_index, i) - && mon->hit_dice < chief->hit_dice - && !mon->berserk() - && !mon->has_ench(ENCH_MIGHT) - && !mon->cannot_move() - && !mon->confused() - && chief->can_see(mon)) + if (*mi != chief + && mons_species(mi->type) == MONS_ORC + && mons_aligned(boss_index, mi->mindex()) + && mi->hit_dice < chief->hit_dice + && !mi->berserk() + && !mi->has_ench(ENCH_MIGHT) + && !mi->cannot_move() + && !mi->confused()) { - mon_enchant ench = mon->get_ench(ENCH_BATTLE_FRENZY); + mon_enchant ench = mi->get_ench(ENCH_BATTLE_FRENZY); if (ench.ench == ENCH_NONE || ench.degree < level) { const int dur = - random_range(12, 20) * speed_to_duration(mon->speed); + random_range(12, 20) * speed_to_duration(mi->speed); if (ench.ench != ENCH_NONE) { ench.degree = level; ench.duration = std::max(ench.duration, dur); - mon->update_ench(ench); + mi->update_ench(ench); } else { - mon->add_ench(mon_enchant(ENCH_BATTLE_FRENZY, level, + mi->add_ench(mon_enchant(ENCH_BATTLE_FRENZY, level, KC_OTHER, dur)); } affected++; - if (you.can_see(mon)) - seen_affected.push_back(mon); + if (you.can_see(*mi)) + seen_affected.push_back(*mi); - if (mon->asleep()) - behaviour_event(mon, ME_DISTURB, MHITNOT, chief->pos()); + if (mi->asleep()) + behaviour_event(*mi, ME_DISTURB, MHITNOT, chief->pos()); } } } @@ -729,23 +730,20 @@ static bool _moth_incite_monsters(const monsters *mon) return false; int goaded = 0; - for (int i = 0; i < MAX_MONSTERS; ++i) + circle_def c(mon->pos(), 3, C_SQUARE); + for (monster_iterator mi(&c); mi; ++mi) { - monsters *targ = &menv[i]; - if (targ == mon || !targ->alive() || !targ->needs_berserk()) - continue; - - if (mon->pos().distance_from(targ->pos()) > 3) + if (*mi == mon || !mi->needs_berserk()) continue; - if (is_sanctuary(targ->pos())) + if (is_sanctuary(mi->pos())) continue; // Cannot goad other moths of wrath! - if (targ->type == MONS_MOTH_OF_WRATH) + if (mi->type == MONS_MOTH_OF_WRATH) continue; - if (_make_monster_angry(mon, targ) && !one_chance_in(3 * ++goaded)) + if (_make_monster_angry(mon, *mi) && !one_chance_in(3 * ++goaded)) return (true); } @@ -779,6 +777,7 @@ bool mon_special_ability(monsters *monster, bolt & beem) spell_type spell = SPELL_NO_SPELL; + circle_def c; switch (mclass) { case MONS_UGLY_THING: @@ -832,16 +831,9 @@ bool mon_special_ability(monsters *monster, bolt & beem) break; } - for (int i = 0; i < MAX_MONSTERS; i++) + c = circle_def(monster->pos(), 4, C_CIRCLE); + for (monster_iterator targ(&c); targ; ++targ) { - monsters *targ = &menv[i]; - - if (targ->type == MONS_NO_MONSTER) - continue; - - if (distance(monster->pos(), targ->pos()) >= 5) - continue; - if (mons_atts_aligned(monster->attitude, targ->attitude)) continue; @@ -1306,46 +1298,7 @@ void mon_nearby_ability(monsters *monster) return; } -#define MON_SPEAK_CHANCE 21 - - if (monster->is_patrolling() || mons_is_wandering(monster) - || monster->attitude == ATT_NEUTRAL) - { - // Very fast wandering/patrolling monsters might, in one monster turn, - // move into the player's LOS and then back out (or the player - // might move into their LOS and the monster move back out before - // the player's view has a chance to update) so prevent them - // from speaking. - ; - } - else if ((mons_class_flag(monster->type, M_SPEAKS) - || !monster->mname.empty()) - && one_chance_in(MON_SPEAK_CHANCE)) - { - mons_speaks(monster); - } - else if (get_mon_shape(monster) >= MON_SHAPE_QUADRUPED) - { - // Non-humanoid-ish monsters have a low chance of speaking - // without the M_SPEAKS flag, to give the dungeon some - // atmosphere/flavour. - int chance = MON_SPEAK_CHANCE * 4; - - // Band members are a lot less likely to speak, since there's - // a lot of them. - if (testbits(monster->flags, MF_BAND_MEMBER)) - chance *= 10; - - // However, confused and fleeing monsters are more interesting. - if (mons_is_fleeing(monster)) - chance /= 2; - if (monster->has_ench(ENCH_CONFUSION)) - chance /= 2; - - if (one_chance_in(chance)) - mons_speaks(monster); - } - // Okay then, don't speak. + maybe_mons_speaks(monster); if (monster_can_submerge(monster, grd(monster->pos())) && !monster->caught() // No submerging while caught. diff --git a/crawl-ref/source/mon-act.cc b/crawl-ref/source/mon-act.cc index 3c57266252..f699d7578e 100644 --- a/crawl-ref/source/mon-act.cc +++ b/crawl-ref/source/mon-act.cc @@ -31,8 +31,9 @@ #include "mon-abil.h" #include "mon-behv.h" #include "mon-cast.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-iter.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "mutation.h" #include "notes.h" #include "options.h" @@ -856,7 +857,8 @@ static bool _handle_scroll(monsters *monster) simple_monster_message(monster, " reads a scroll."); const int mon = create_monster( mgen_data(MONS_ABOMINATION_SMALL, SAME_ATTITUDE(monster), - 0, 0, monster->pos(), monster->foe, MG_FORCE_BEH)); + monster, 0, 0, monster->pos(), monster->foe, + MG_FORCE_BEH)); read = true; if (mon != -1) @@ -2077,20 +2079,18 @@ void handle_monsters() // them to move again. memset(immobile_monster, 0, sizeof immobile_monster); - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi; mi; ++mi) { - monsters *monster = &menv[i]; - - if (!monster->alive() || immobile_monster[i]) + if (immobile_monster[mi->mindex()]) continue; - const coord_def oldpos = monster->pos(); + const coord_def oldpos = mi->pos(); - monster->update_los(); - _handle_monster_move(monster); + mi->update_los(); + _handle_monster_move(*mi); - if (!invalid_monster(monster) && monster->pos() != oldpos) - immobile_monster[i] = true; + if (!invalid_monster(*mi) && mi->pos() != oldpos) + immobile_monster[mi->mindex()] = true; // If the player got banished, discard pending monster actions. if (you.banished) @@ -2129,18 +2129,10 @@ static bool _jelly_divide(monsters *parent) if ( num_spots == 0 ) return (false); - int k = 0; - // Now that we have a spot, find a monster slot {dlb}: - for (k = 0; k < MAX_MONSTERS; k++) - { - child = &menv[k]; - - if (child->type == -1) - break; - else if (k == MAX_MONSTERS - 1) - return (false); - } + child = get_free_monster(); + if (!child) + return (false); // Handle impact of split on parent {dlb}: parent->max_hit_points /= 2; @@ -2159,7 +2151,7 @@ static bool _jelly_divide(monsters *parent) child->speed_increment = 70 + random2(5); child->moveto(child_spot); - mgrd(child->pos()) = k; + mgrd(child->pos()) = child->mindex(); if (!simple_monster_message(parent, " splits in two!")) if (player_can_hear(parent->pos()) || player_can_hear(child->pos())) diff --git a/crawl-ref/source/mon-behv.cc b/crawl-ref/source/mon-behv.cc index 2954e65065..03ae622bb9 100644 --- a/crawl-ref/source/mon-behv.cc +++ b/crawl-ref/source/mon-behv.cc @@ -15,8 +15,9 @@ #include "fprop.h" #include "exclude.h" #include "los.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-iter.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "mon-util.h" #include "random.h" #include "state.h" @@ -914,13 +915,13 @@ static void _arena_set_foe(monsters *mons) int nearest_unseen = -1; int best_unseen_distance = -1; - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator other; other; ++other) { + int i = other->mindex(); if (mind == i) continue; - const monsters *other(&menv[i]); - if (!other->alive() || mons_aligned(mind, i)) + if (mons_aligned(mind, i)) continue; // Don't fight test spawners, since they're only pseudo-monsters @@ -934,7 +935,7 @@ static void _arena_set_foe(monsters *mons) } const int distance = grid_distance(mons->pos(), other->pos()); - const bool seen = mons->can_see(other); + const bool seen = mons->can_see(*other); if (seen) { @@ -954,7 +955,7 @@ static void _arena_set_foe(monsters *mons) } if ((best_distance == -1 || distance < best_distance) - && mons->can_see(other)) + && mons->can_see(*other)) { best_distance = distance; diff --git a/crawl-ref/source/mon-cast.cc b/crawl-ref/source/mon-cast.cc index 3464517da8..daf8520ac1 100644 --- a/crawl-ref/source/mon-cast.cc +++ b/crawl-ref/source/mon-cast.cc @@ -21,9 +21,10 @@ #include "los.h" #include "misc.h" #include "mon-behv.h" -#include "monplace.h" -#include "monspeak.h" -#include "monstuff.h" +#include "mon-iter.h" +#include "mon-place.h" +#include "mon-speak.h" +#include "mon-stuff.h" #include "mon-util.h" #include "random.h" #include "religion.h" @@ -148,22 +149,19 @@ static bool _set_allied_target(monsters * caster, bolt & pbolt) monster_type caster_genus = mons_genus(caster->type); - for (int i = 0; i < MAX_MONSTERS; i++) + for (monster_iterator targ(caster); targ; ++targ) { - monsters * targ = &menv[i]; - if (i != caster->mindex() - && targ->alive() - && caster->can_see(targ) + if (*targ != caster && mons_genus(targ->type) == caster_genus && mons_atts_aligned(targ->attitude, caster->attitude) && !targ->has_ench(ENCH_CHARM) - && _flavour_benefits_monster(pbolt.flavour, *targ)) + && _flavour_benefits_monster(pbolt.flavour, **targ)) { int targ_distance = grid_distance(targ->pos(), caster->pos()); if (targ_distance < min_distance && targ_distance < pbolt.range) { min_distance = targ_distance; - selected_target = targ; + selected_target = *targ; } } } @@ -273,8 +271,8 @@ bolt mons_spells( monsters *mons, spell_type spell_cast, int power, beam.flavour = BEAM_HASTE; break; - case SPELL_BACKLIGHT: - beam.flavour = BEAM_BACKLIGHT; + case SPELL_CORONA: + beam.flavour = BEAM_CORONA; beam.is_beam = true; break; @@ -283,6 +281,11 @@ bolt mons_spells( monsters *mons, spell_type spell_cast, int power, beam.is_beam = true; break; + case SPELL_HIBERNATION: + beam.flavour = BEAM_HIBERNATION; + beam.is_beam = true; + break; + case SPELL_SLEEP: beam.flavour = BEAM_SLEEP; beam.is_beam = true; @@ -732,6 +735,8 @@ bool setup_mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, if (spell_cast == SPELL_TELEPORT_SELF) pbolt.ench_power = 2000; + else if (spell_cast == SPELL_SLEEP) + pbolt.ench_power = 6 * monster->hit_dice; pbolt.beam_source = monster_index(monster); @@ -786,6 +791,7 @@ bool setup_mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, case SPELL_SUMMON_GREATER_DEMON: case SPELL_CANTRIP: case SPELL_BERSERKER_RAGE: + case SPELL_SWIFTNESS: case SPELL_WATER_ELEMENTALS: case SPELL_FIRE_ELEMENTALS: case SPELL_AIR_ELEMENTALS: @@ -846,35 +852,29 @@ bool setup_mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, } else if (spell_cast == SPELL_PORKALATOR && one_chance_in(3)) { - int target = -1; - int count = 0; + monsters* targ = NULL; + int count = 0; monster_type hog_type = MONS_HOG; - for (int i = 0; i < MAX_MONSTERS; i++) + for (monster_iterator mi(monster); mi; ++mi) { - monsters *targ = &menv[i]; - - if (!monster->can_see(targ)) - continue; - hog_type = MONS_HOG; - if (targ->holiness() == MH_DEMONIC) + if (mi->holiness() == MH_DEMONIC) hog_type = MONS_HELL_HOG; - else if (targ->holiness() != MH_NATURAL) + else if (mi->holiness() != MH_NATURAL) continue; - if (targ->type != hog_type - && mons_atts_aligned(monster->attitude, targ->attitude) - && mons_power(hog_type) + random2(4) >= mons_power(targ->type) - && (!targ->can_use_spells() || coinflip()) + if (mi->type != hog_type + && mons_atts_aligned(monster->attitude, mi->attitude) + && mons_power(hog_type) + random2(4) >= mons_power(mi->type) + && (!mi->can_use_spells() || coinflip()) && one_chance_in(++count)) { - target = i; + targ = *mi; } } - if (target != -1) + if (targ) { - monsters *targ = &menv[target]; pbolt.target = targ->pos(); #if DEBUG_DIAGNOSTICS mprf("Porkalator: targetting %s instead", @@ -1265,7 +1265,7 @@ bool handle_mon_spell(monsters *monster, bolt &beem) // Try to animate dead: if nothing rises, pretend we didn't cast it. if (spell_cast == SPELL_ANIMATE_DEAD && !animate_dead(monster, 100, SAME_ATTITUDE(monster), - monster->foe, god, false)) + monster->foe, monster, "", god, false)) { return (false); } @@ -1493,7 +1493,7 @@ static void _do_high_level_summon(monsters *monster, bool monsterNearby, continue; create_monster( - mgen_data(which_mons, SAME_ATTITUDE(monster), + mgen_data(which_mons, SAME_ATTITUDE(monster), monster, duration, spell_cast, target ? *target : monster->pos(), monster->foe, 0, god)); } @@ -1608,6 +1608,11 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, monster->go_berserk(true); return; + case SPELL_SWIFTNESS: + monster->add_ench(ENCH_SWIFT); + simple_monster_message(monster, " seems to move somewhat quicker."); + return; + case SPELL_SUMMON_SMALL_MAMMALS: case SPELL_VAMPIRE_SUMMON: if (spell_cast == SPELL_SUMMON_SMALL_MAMMALS) @@ -1626,7 +1631,7 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, const monster_type mon = (one_chance_in(3) ? MONS_GIANT_BAT : RANDOM_ELEMENT(rats)); create_monster( - mgen_data(mon, SAME_ATTITUDE(monster), + mgen_data(mon, SAME_ATTITUDE(monster), monster, 5, spell_cast, monster->pos(), monster->foe, 0, god)); } return; @@ -1640,7 +1645,7 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, for (sumcount = 0; sumcount < sumcount2; ++sumcount) { create_monster( - mgen_data(RANDOM_MONSTER, SAME_ATTITUDE(monster), + mgen_data(RANDOM_MONSTER, SAME_ATTITUDE(monster), monster, 5, spell_cast, monster->pos(), monster->foe, 0, god)); } return; @@ -1669,7 +1674,7 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, for (sumcount = 0; sumcount < sumcount2; sumcount++) { create_monster( - mgen_data(el_summon_type, SAME_ATTITUDE(monster), + mgen_data(el_summon_type, SAME_ATTITUDE(monster), monster, 3, spell_cast, monster->pos(), monster->foe, 0, god)); } return; @@ -1701,7 +1706,7 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, // being passed to summon_type), so I'm not sure what the // abjuration value (3) is doing there. (jpeg) if (create_monster( - mgen_data(MONS_KRAKEN_TENTACLE, SAME_ATTITUDE(monster), + mgen_data(MONS_KRAKEN_TENTACLE, SAME_ATTITUDE(monster), monster, 3, spell_cast, monster->pos(), monster->foe, 0, god, MONS_NO_MONSTER, kraken_index, monster->colour, you.your_level, PROX_CLOSE_TO_PLAYER, @@ -1722,7 +1727,7 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, for (sumcount = 0; sumcount < sumcount2; sumcount++) { create_monster( - mgen_data(MONS_RAKSHASA_FAKE, SAME_ATTITUDE(monster), + mgen_data(MONS_RAKSHASA_FAKE, SAME_ATTITUDE(monster), monster, 3, spell_cast, monster->pos(), monster->foe, 0, god)); } return; @@ -1738,7 +1743,7 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, { create_monster( mgen_data(summon_any_demon(DEMON_COMMON), - SAME_ATTITUDE(monster), duration, spell_cast, + SAME_ATTITUDE(monster), monster, duration, spell_cast, monster->pos(), monster->foe, 0, god)); } return; @@ -1757,16 +1762,16 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, : MONS_UGLY_THING); create_monster( - mgen_data(mon, SAME_ATTITUDE(monster), + mgen_data(mon, SAME_ATTITUDE(monster), monster, duration, spell_cast, monster->pos(), monster->foe, 0, god)); } return; case SPELL_ANIMATE_DEAD: - // see special handling in monstuff::handle_spell() {dlb} + // see special handling in mon-stuff::handle_spell() {dlb} animate_dead(monster, 5 + random2(5), SAME_ATTITUDE(monster), - monster->foe, god); + monster->foe, monster, "", god); return; case SPELL_CALL_IMP: // class 5 demons @@ -1777,7 +1782,7 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, { create_monster( mgen_data(summon_any_demon(DEMON_LESSER), - SAME_ATTITUDE(monster), + SAME_ATTITUDE(monster), monster, duration, spell_cast, monster->pos(), monster->foe, 0, god)); } @@ -1793,7 +1798,7 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, for (sumcount = 0; sumcount < sumcount2; ++sumcount) { create_monster( - mgen_data(MONS_SCORPION, SAME_ATTITUDE(monster), + mgen_data(MONS_SCORPION, SAME_ATTITUDE(monster), monster, duration, spell_cast, monster->pos(), monster->foe, 0, god)); } @@ -1807,7 +1812,7 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, for (sumcount = 0; sumcount < sumcount2; ++sumcount) { create_monster( - mgen_data(MONS_UFETUBUS, SAME_ATTITUDE(monster), + mgen_data(MONS_UFETUBUS, SAME_ATTITUDE(monster), monster, duration, spell_cast, monster->pos(), monster->foe, 0, god)); } @@ -1815,13 +1820,13 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, case SPELL_SUMMON_BEAST: // Geryon create_monster( - mgen_data(MONS_BEAST, SAME_ATTITUDE(monster), + mgen_data(MONS_BEAST, SAME_ATTITUDE(monster), monster, 4, spell_cast, monster->pos(), monster->foe, 0, god)); return; case SPELL_SUMMON_ICE_BEAST: create_monster( - mgen_data(MONS_ICE_BEAST, SAME_ATTITUDE(monster), + mgen_data(MONS_ICE_BEAST, SAME_ATTITUDE(monster), monster, 5, spell_cast, monster->pos(), monster->foe, 0, god)); return; @@ -1836,8 +1841,8 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, { create_monster( mgen_data(MONS_WANDERING_MUSHROOM, SAME_ATTITUDE(monster), - duration, spell_cast, monster->pos(), monster->foe, 0, - god)); + monster, duration, spell_cast, monster->pos(), + monster->foe, 0, god)); } return; @@ -1853,7 +1858,8 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, { create_monster( mgen_data(MONS_BALL_LIGHTNING, SAME_ATTITUDE(monster), - 2, spell_cast, monster->pos(), monster->foe, 0, god)); + monster, 2, spell_cast, monster->pos(), monster->foe, + 0, god)); } return; } @@ -1883,7 +1889,7 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, { create_monster( mgen_data(summon_any_demon(DEMON_GREATER), - SAME_ATTITUDE(monster), + SAME_ATTITUDE(monster), monster, duration, spell_cast, monster->pos(), monster->foe, 0, god)); } @@ -1921,7 +1927,7 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, for (int i = 0, size = monsters.size(); i < size; ++i) { create_monster( - mgen_data(monsters[i], SAME_ATTITUDE(monster), + mgen_data(monsters[i], SAME_ATTITUDE(monster), monster, duration, spell_cast, monster->pos(), monster->foe, 0, god)); } @@ -2108,7 +2114,7 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, 0)); create_monster( - mgen_data(mon, SAME_ATTITUDE(monster), duration, + mgen_data(mon, SAME_ATTITUDE(monster), monster, duration, spell_cast, monster->pos(), monster->foe, 0, god)); } return; diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h index 1360ed5987..dc677f3413 100644 --- a/crawl-ref/source/mon-data.h +++ b/crawl-ref/source/mon-data.h @@ -50,7 +50,7 @@ MH_NONLIVING - golems and other constructs MH_PLANT - plants - exp_mod: see give_adjusted_experience() in monstuff.cc + exp_mod: see give_adjusted_experience() in mon-stuff.cc - the experience given for killing this monster is calculated something like this: @@ -2725,7 +2725,7 @@ static monsterentry mondata[] = { { MONS_OKLOB_PLANT, 'P', LIGHTGREEN, "oklob plant", M_SPECIAL_ABILITY | M_STATIONARY, - MR_RES_POISON, + MR_RES_POISON | MR_RES_ACID, 0, 10, MONS_PLANT, MONS_OKLOB_PLANT, MH_PLANT, -3, { AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, { 10, 3, 5, 0 }, @@ -4443,11 +4443,11 @@ static monsterentry mondata[] = { MONS_GASTRONOK, 'j', LIGHTRED, "Gastronok", M_NO_SKELETON | M_UNIQUE | M_SPELLCASTER | M_ACTUAL_SPELLS | M_SEE_INVIS | M_SPEAKS | M_NO_WAND, - MR_RES_FIRE | MR_RES_COLD, - 700, 10, MONS_GIANT_SLUG, MONS_GIANT_SLUG, MH_NATURAL, -4, - { {AT_BITE, AF_PLAIN, 15}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, - { 12, 0, 0, 150 }, - 1, 2, MST_GASTRONOK, CE_POISONOUS, Z_NOZOMBIE, S_GURGLE, + MR_NO_FLAGS, + 1500, 10, MONS_GIANT_SLUG, MONS_ELEPHANT_SLUG, MH_NATURAL, -3, + { {AT_BITE, AF_PLAIN, 40}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, + { 20, 0, 0, 150 }, + 2, 1, MST_GASTRONOK, CE_POISONOUS, Z_NOZOMBIE, S_GURGLE, I_NORMAL, HT_AMPHIBIOUS_LAND, FL_NONE, 5, DEFAULT_ENERGY, MONUSE_STARTING_EQUIPMENT, MONEAT_FOOD, SIZE_LARGE }, diff --git a/crawl-ref/source/mon-gear.cc b/crawl-ref/source/mon-gear.cc index b1573d11a7..6680e3a27a 100644 --- a/crawl-ref/source/mon-gear.cc +++ b/crawl-ref/source/mon-gear.cc @@ -324,8 +324,8 @@ static item_make_species_type _give_weapon(monsters *mon, int level, item.base_type = OBJ_WEAPONS; item.sub_type = WPN_QUARTERSTAFF; set_item_ego_type(item, OBJ_WEAPONS, SPWPN_CHAOS); - item.plus += random2(5); - item.plus2 += random2(4); + item.plus += 2 + random2(3); + item.plus2 += 2 + random2(3); break; case MONS_ORC: diff --git a/crawl-ref/source/mon-info.cc b/crawl-ref/source/mon-info.cc index 12f64499dc..d32b8466d1 100644 --- a/crawl-ref/source/mon-info.cc +++ b/crawl-ref/source/mon-info.cc @@ -169,7 +169,7 @@ static std::string _verbose_info(const monsters* m) return (" (fleeing)"); if (m->asleep()) { - if (!m->can_sleep(true)) + if (!m->can_hibernate(true)) return (" (dormant)"); else return (" (sleeping)"); diff --git a/crawl-ref/source/mon-info.h b/crawl-ref/source/mon-info.h index c5d559d4e9..20618caf1a 100644 --- a/crawl-ref/source/mon-info.h +++ b/crawl-ref/source/mon-info.h @@ -1,7 +1,7 @@ #ifndef MON_INFO_H #define MON_INFO_H -#include "monstuff.h" +#include "mon-stuff.h" // Monster info used by the pane; precomputes some data // to help with sorting and rendering. diff --git a/crawl-ref/source/mon-iter.cc b/crawl-ref/source/mon-iter.cc new file mode 100644 index 0000000000..1158a9028d --- /dev/null +++ b/crawl-ref/source/mon-iter.cc @@ -0,0 +1,87 @@ +#include "AppHdr.h" + +#include "mon-iter.h" + +#include "actor.h" +#include "coord-circle.h" +#include "env.h" +#include "monster.h" + +monster_iterator::monster_iterator() + : restr(R_NONE), curr_mid(0) +{ + advance(true); +} + +monster_iterator::monster_iterator(const circle_def* circle_) + : restr(R_CIRC), curr_mid(0), circle(circle_) +{ + advance(true); +} + +monster_iterator::monster_iterator(const los_def* los_) + : restr(R_LOS), curr_mid(0), los(los_) +{ + advance(true); +} + +monster_iterator::monster_iterator(const actor* act_) + : restr(R_ACT), curr_mid(0), act(act_) +{ + advance(true); +} + +monster_iterator::operator bool() const +{ + return (curr_mid < MAX_MONSTERS); +} + +monsters* monster_iterator::operator*() const +{ + return (&env.mons[curr_mid]); +} + +monsters* monster_iterator::operator->() const +{ + return (&env.mons[curr_mid]); +} + +monster_iterator& monster_iterator::operator++() +{ + advance(); + return (*this); +} + +monster_iterator monster_iterator::operator++(int) +{ + monster_iterator copy = *this; + ++(*this); + return (copy); +} + +bool monster_iterator::valid(int mid) const +{ + monsters* mon = &env.mons[mid]; + if (!mon->alive()) + return (false); + switch (restr) + { + case R_CIRC: + return (circle->contains(mon->pos())); + case R_LOS: + return (los->see_cell(mon->pos())); + case R_ACT: + return (act->can_see(mon)); + default: + return (true); + } +} + +void monster_iterator::advance(bool may_stay) +{ + if (!may_stay) + ++curr_mid; + while (curr_mid < MAX_MONSTERS && !valid(curr_mid)) + ++curr_mid; +} + diff --git a/crawl-ref/source/mon-iter.h b/crawl-ref/source/mon-iter.h new file mode 100644 index 0000000000..7f31831c64 --- /dev/null +++ b/crawl-ref/source/mon-iter.h @@ -0,0 +1,49 @@ +/* + * Provide a way to iterator over all monsters, + * subject to a few common restrictions. + * + * TODO: + * - Iterate over actors? + */ + +#ifndef MON_ITER_H +#define MON_ITER_H + +enum restr_type +{ + R_NONE, + R_CIRC, + R_LOS, + R_ACT +}; + +class circle_def; +class los_def; +class actor; + +class monster_iterator +{ +public: + monster_iterator(); + monster_iterator(const circle_def* circle_); + monster_iterator(const los_def* los_); + monster_iterator(const actor* act_); + + operator bool() const; + monsters* operator*() const; + monsters* operator->() const; + monster_iterator& operator++(); + monster_iterator operator++(int); + +protected: + restr_type restr; + int curr_mid; + const circle_def* circle; + const los_def* los; + const actor* act; + + bool valid(int mid) const; + void advance(bool may_stay=false); +}; + +#endif diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/mon-place.cc index b0282aeaf1..dbf488e6a5 100644 --- a/crawl-ref/source/monplace.cc +++ b/crawl-ref/source/mon-place.cc @@ -8,7 +8,7 @@ #include <algorithm> -#include "monplace.h" +#include "mon-place.h" #include "arena.h" #include "branch.h" @@ -23,9 +23,10 @@ #include "message.h" #include "mon-behv.h" #include "mon-gear.h" +#include "mon-iter.h" #include "mon-pick.h" #include "mon-util.h" -#include "monstuff.h" +#include "mon-stuff.h" #include "player.h" #include "random.h" #include "religion.h" @@ -1000,23 +1001,26 @@ int place_monster(mgen_data mg, bool force_pos) return (id); } +monsters* get_free_monster() +{ + for (int i = 0; i < MAX_MONSTERS; ++i) + if (env.mons[i].type == MONS_NO_MONSTER) + { + env.mons[i].reset(); + return (&env.mons[i]); + } + return (NULL); +} + static int _place_monster_aux(const mgen_data &mg, bool first_band_member, bool force_pos) { - int id = -1; coord_def fpos; - // Gotta be able to pick an ID. - for (id = 0; id < MAX_MONSTERS; id++) - if (menv[id].type == MONS_NO_MONSTER) - break; - - // Too many monsters on level? - if (id == MAX_MONSTERS) + monsters* mon = get_free_monster(); + if (!mon) return (-1); - menv[id].reset(); - const monster_type montype = (mons_class_is_zombified(mg.cls) ? mg.base_type : mg.cls); @@ -1035,8 +1039,8 @@ static int _place_monster_aux(const mgen_data &mg, // We'll try 1000 times for a good spot. for (i = 0; i < 1000; ++i) { - fpos = mg.pos + coord_def( random_range(-3, 3), - random_range(-3, 3) ); + fpos = mg.pos + coord_def(random_range(-3, 3), + random_range(-3, 3)); if (_valid_monster_generation_location(mg, fpos)) break; @@ -1055,16 +1059,16 @@ static int _place_monster_aux(const mgen_data &mg, return (-1); } - monsters &mons(menv[id]); // Now, actually create the monster. (Wheeee!) - mons.type = mg.cls; - mons.base_monster = mg.base_type; - mons.number = mg.number; + mon->type = mg.cls; + mon->base_monster = mg.base_type; + mon->number = mg.number; - mons.moveto(fpos); + mon->moveto(fpos); // Link monster into monster grid. - mgrd(fpos) = id; + int id = mon->mindex(); + env.mgrid(fpos) = id; // Generate a brand shiny new monster, or zombie. if (mons_class_is_zombified(mg.cls)) @@ -1075,8 +1079,8 @@ static int _place_monster_aux(const mgen_data &mg, // Is it a god gift? if (mg.god != GOD_NO_GOD) { - mons.god = mg.god; - mons.flags |= MF_GOD_GIFT; + mon->god = mg.god; + mon->flags |= MF_GOD_GIFT; } // Not a god gift, give priestly monsters a god. else if (mons_class_flag(mg.cls, M_PRIEST)) @@ -1084,17 +1088,17 @@ static int _place_monster_aux(const mgen_data &mg, switch (mons_genus(mg.cls)) { case MONS_ORC: - mons.god = GOD_BEOGH; + mon->god = GOD_BEOGH; break; case MONS_JELLY: - mons.god = GOD_JIYVA; + mon->god = GOD_JIYVA; break; case MONS_MUMMY: case MONS_DRACONIAN: case MONS_ELF: // [ds] Vault defs can request priest monsters of unusual types. default: - mons.god = GOD_NAMELESS; + mon->god = GOD_NAMELESS; break; } } @@ -1102,34 +1106,34 @@ static int _place_monster_aux(const mgen_data &mg, else if (mons_genus(mg.cls) == MONS_ORC) { if (!one_chance_in(7)) - mons.god = GOD_BEOGH; + mon->god = GOD_BEOGH; } // The royal jelly belongs to Jiyva. else if (mg.cls == MONS_ROYAL_JELLY) - mons.god = GOD_JIYVA; + mon->god = GOD_JIYVA; // Angels and Daevas belong to TSO, but 1 out of 7 in the Abyss are // adopted by Xom. else if (mons_class_holiness(mg.cls) == MH_HOLY) { if (mg.level_type != LEVEL_ABYSS || !one_chance_in(7)) - mons.god = GOD_SHINING_ONE; + mon->god = GOD_SHINING_ONE; else - mons.god = GOD_XOM; + mon->god = GOD_XOM; } // 6 out of 7 demons in the Abyss belong to Lugonu. else if (mons_class_holiness(mg.cls) == MH_DEMONIC) { if (mg.level_type == LEVEL_ABYSS && !one_chance_in(7)) - mons.god = GOD_LUGONU; + mon->god = GOD_LUGONU; } // If the caller requested a specific colour for this monster, apply // it now. if (mg.colour != BLACK) - mons.colour = mg.colour; + mon->colour = mg.colour; if (mg.mname != "") - mons.mname = mg.mname; + mon->mname = mg.mname; // The return of Boris is now handled in monster_die(). Not setting // this for Boris here allows for multiple Borises in the dungeon at @@ -1138,16 +1142,16 @@ static int _place_monster_aux(const mgen_data &mg, you.unique_creatures[mg.cls] = true; if (mons_class_flag(mg.cls, M_INVIS)) - mons.add_ench(ENCH_INVIS); + mon->add_ench(ENCH_INVIS); if (mons_class_flag(mg.cls, M_CONFUSED)) - mons.add_ench(ENCH_CONFUSION); + mon->add_ench(ENCH_CONFUSION); if (mg.cls == MONS_SHAPESHIFTER) - mons.add_ench(ENCH_SHAPESHIFTER); + mon->add_ench(ENCH_SHAPESHIFTER); if (mg.cls == MONS_GLOWING_SHAPESHIFTER) - mons.add_ench(ENCH_GLOWING_SHAPESHIFTER); + mon->add_ench(ENCH_GLOWING_SHAPESHIFTER); if (mg.cls == MONS_TOADSTOOL) { @@ -1156,23 +1160,23 @@ static int _place_monster_aux(const mgen_data &mg, // spawning mushrooms in the same place over and over. Aside // from that, the value is slightly randomised to avoid // simultaneous die-offs of mushroom rings. - mons.add_ench(ENCH_SLOWLY_DYING); + mon->add_ench(ENCH_SLOWLY_DYING); } - if (monster_can_submerge(&mons, grd(fpos)) && !one_chance_in(5)) - mons.add_ench(ENCH_SUBMERGED); + if (monster_can_submerge(mon, grd(fpos)) && !one_chance_in(5)) + mon->add_ench(ENCH_SUBMERGED); - mons.flags |= MF_JUST_SUMMONED; + mon->flags |= MF_JUST_SUMMONED; // Don't leave shifters in their starting shape. if (mg.cls == MONS_SHAPESHIFTER || mg.cls == MONS_GLOWING_SHAPESHIFTER) { no_messages nm; - monster_polymorph(&mons, RANDOM_MONSTER); + monster_polymorph(mon, RANDOM_MONSTER); // It's not actually a known shapeshifter if it happened to be // placed in LOS of the player. - mons.flags &= ~MF_KNOWN_MIMIC; + mon->flags &= ~MF_KNOWN_MIMIC; } // dur should always be 1-6 for monsters that can be abjured. @@ -1185,16 +1189,16 @@ static int _place_monster_aux(const mgen_data &mg, // Dancing weapons *always* have a weapon. Fail to create them // otherwise. - const item_def* wpn = mons.mslot_item(MSLOT_WEAPON); + const item_def* wpn = mon->mslot_item(MSLOT_WEAPON); if (!wpn) { - mons.destroy_inventory(); - mons.reset(); + mon->destroy_inventory(); + mon->reset(); mgrd(fpos) = NON_MONSTER; return (-1); } else - mons.colour = wpn->colour; + mon->colour = wpn->colour; } else if (mons_class_itemuse(mg.cls) >= MONUSE_STARTING_EQUIPMENT) { @@ -1203,13 +1207,13 @@ static int _place_monster_aux(const mgen_data &mg, if (mons_class_wields_two_weapons(mg.cls)) give_item(id, mg.power, summoned); - unwind_var<int> save_speedinc(mons.speed_increment); - mons.wield_melee_weapon(false); + unwind_var<int> save_speedinc(mon->speed_increment); + mon->wield_melee_weapon(false); } // Give manticores 8 to 16 spike volleys. if (mg.cls == MONS_MANTICORE) - mons.number = 8 + random2(9); + mon->number = 8 + random2(9); if (mg.cls == MONS_SLIME_CREATURE) { @@ -1217,21 +1221,21 @@ static int _place_monster_aux(const mgen_data &mg, { // Boost HP to what it would have been if it had grown this // big by merging. - mons.hit_points *= mg.number; - mons.max_hit_points *= mg.number; + mon->hit_points *= mg.number; + mon->max_hit_points *= mg.number; } } // Set attitude, behaviour and target. - mons.attitude = ATT_HOSTILE; - mons.behaviour = mg.behaviour; + mon->attitude = ATT_HOSTILE; + mon->behaviour = mg.behaviour; // Statues cannot sleep (nor wander but it means they are a bit // more aware of the player than they'd be otherwise). if (mons_is_statue(mg.cls)) - mons.behaviour = BEH_WANDER; + mon->behaviour = BEH_WANDER; - mons.foe_memory = 0; + mon->foe_memory = 0; // Setting attitude will always make the monster wander... // If you want sleeping hostiles, use BEH_SLEEP since the default @@ -1239,66 +1243,102 @@ static int _place_monster_aux(const mgen_data &mg, if (mg.behaviour > NUM_BEHAVIOURS) { if (mg.behaviour == BEH_FRIENDLY) - mons.attitude = ATT_FRIENDLY; + mon->attitude = ATT_FRIENDLY; if (mg.behaviour == BEH_GOOD_NEUTRAL) - mons.attitude = ATT_GOOD_NEUTRAL; + mon->attitude = ATT_GOOD_NEUTRAL; if (mg.behaviour == BEH_NEUTRAL) - mons.attitude = ATT_NEUTRAL; + mon->attitude = ATT_NEUTRAL; if (mg.behaviour == BEH_STRICT_NEUTRAL) - mons.attitude = ATT_STRICT_NEUTRAL; + mon->attitude = ATT_STRICT_NEUTRAL; - mons.behaviour = BEH_WANDER; + mon->behaviour = BEH_WANDER; } if (summoned) { - mons.mark_summoned(mg.abjuration_duration, true, - mg.summon_type); + mon->mark_summoned(mg.abjuration_duration, true, + mg.summon_type); + } + mon->foe = mg.foe; + + if (!mg.non_actor_summoner.empty()) + { + CrawlStoreValue& blame = mon->props["blame"]; + + blame.new_vector(SV_STR, SFLAG_CONST_TYPE); + blame.get_vector().push_back(mg.non_actor_summoner); + } + else if (mg.summoner != NULL) + { + CrawlStoreValue& blame = mon->props["blame"]; + + blame.new_vector(SV_STR, SFLAG_CONST_TYPE); + + if (mg.summoner->atype() == ACT_PLAYER) + { + blame.get_vector().push_back("themselves"); + } + else + { + monsters* sum = &menv[mg.summoner->mindex()]; + + blame.get_vector().push_back(sum->full_name(DESC_NOCAP_A, true)); + + if (sum->props.exists("blame")) + { + CrawlVector& oldblame = sum->props["blame"].get_vector(); + + for (CrawlVector::iterator i = oldblame.begin(); + i != oldblame.end(); ++i) + { + blame.get_vector().push_back(*i); + } + } + } } - mons.foe = mg.foe; // Initialise (very) ugly things and pandemonium demons. - if (mons.type == MONS_UGLY_THING - || mons.type == MONS_VERY_UGLY_THING) + if (mon->type == MONS_UGLY_THING + || mon->type == MONS_VERY_UGLY_THING) { ghost_demon ghost; - ghost.init_ugly_thing(mons.type == MONS_VERY_UGLY_THING, false, + ghost.init_ugly_thing(mon->type == MONS_VERY_UGLY_THING, false, mg.colour); - mons.set_ghost(ghost, false); - mons.uglything_init(); + mon->set_ghost(ghost, false); + mon->uglything_init(); } - else if (mons.type == MONS_PANDEMONIUM_DEMON) + else if (mon->type == MONS_PANDEMONIUM_DEMON) { ghost_demon ghost; ghost.init_random_demon(); - mons.set_ghost(ghost); - mons.pandemon_init(); + mon->set_ghost(ghost); + mon->pandemon_init(); } - else if (mons.type == MONS_DANCING_WEAPON) + else if (mon->type == MONS_DANCING_WEAPON) { ghost_demon ghost; // We can't use monsters::weapon here because it wants to look // at attack types, which are in the ghost structure we're // building. - ASSERT( mons.mslot_item(MSLOT_WEAPON) ); + ASSERT(mon->mslot_item(MSLOT_WEAPON)); // Dancing weapons are placed at pretty high power. Remember, the // player is fighting them one-on-one, while he will often summon // several. - ghost.init_dancing_weapon(*(mons.mslot_item(MSLOT_WEAPON)), 180); - mons.set_ghost(ghost); - mons.dancing_weapon_init(); + ghost.init_dancing_weapon(*(mon->mslot_item(MSLOT_WEAPON)), 180); + mon->set_ghost(ghost); + mon->dancing_weapon_init(); } - mark_interesting_monst(&mons, mg.behaviour); + mark_interesting_monst(mon, mg.behaviour); - if (you.can_see(&mons)) - handle_seen_interrupt(&mons); + if (you.can_see(mon)) + handle_seen_interrupt(mon); if (crawl_state.arena) - arena_placed_monster(&mons); + arena_placed_monster(mon); return (id); } @@ -2398,6 +2438,11 @@ int mons_place(mgen_data mg) break; } + if (mg.behaviour == BEH_COPY) + mg.behaviour = mg.summoner == &you + ? BEH_FRIENDLY + : SAME_ATTITUDE((&menv[mg.summoner->mindex()])); + int mid = place_monster(mg); if (mid == -1) return (-1); diff --git a/crawl-ref/source/monplace.h b/crawl-ref/source/mon-place.h index 7e35108863..bf9cd64ec2 100644 --- a/crawl-ref/source/monplace.h +++ b/crawl-ref/source/mon-place.h @@ -1,5 +1,5 @@ /* - * File: monplace.h + * File: mon-place.h * Summary: Functions used when placing monsters in the dungeon. * Written by: Linley Henzell */ @@ -126,6 +126,10 @@ struct mgen_data // XXX: Could use splitting up these aspects. beh_type behaviour; + // Who summoned this monster? Important to know for death accounting + // and the summon cap, if and when it goes in. NULL is no summoner. + actor* summoner; + // For summoned monsters, this is a measure of how long the summon will // hang around, on a scale of 1-6, 6 being longest. Use 0 for monsters // that aren't summoned. @@ -190,8 +194,13 @@ struct mgen_data // XXX: Rather hackish. std::string mname; + // This is used to account for non-actor summoners. Blasted by an Ice + // Fiend ... summoned by the effects of Hell. + std::string non_actor_summoner; + mgen_data(monster_type mt = RANDOM_MONSTER, beh_type beh = BEH_HOSTILE, + actor* sner = 0, int abj = 0, int st = 0, const coord_def &p = coord_def(-1, -1), @@ -204,13 +213,14 @@ struct mgen_data int monpower = you.your_level, proximity_type prox = PROX_ANYWHERE, level_area_type ltype = you.level_type, - std::string monname = "") + std::string monname = "", + std::string nas = "") - : cls(mt), base_type(base), behaviour(beh), + : cls(mt), base_type(base), behaviour(beh), summoner(sner), abjuration_duration(abj), summon_type(st), pos(p), foe(mfoe), flags(monflags), god(which_god), number(monnumber), colour(moncolour), power(monpower), proximity(prox), level_type(ltype), map_mask(0), - mname(monname) + mname(monname), non_actor_summoner(nas) { ASSERT(summon_type == 0 || (abj >= 1 && abj <= 6) || mt == MONS_BALL_LIGHTNING); @@ -230,10 +240,11 @@ struct mgen_data const coord_def &where, unsigned flags = 0) { - return mgen_data(what, BEH_SLEEP, 0, 0, where, MHITNOT, flags); + return mgen_data(what, BEH_SLEEP, 0, 0, 0, where, MHITNOT, flags); } static mgen_data hostile_at(monster_type mt, + std::string summoner, bool alert = false, int abj = 0, int st = 0, @@ -243,9 +254,10 @@ struct mgen_data monster_type base = MONS_NO_MONSTER) { - return mgen_data(mt, BEH_HOSTILE, abj, st, p, + return mgen_data(mt, BEH_HOSTILE, 0, abj, st, p, alert ? MHITYOU : MHITNOT, - monflags, god, base); + monflags, god, base, 0, BLACK, you.your_level, + PROX_ANYWHERE, you.level_type, "", summoner); } }; @@ -335,6 +347,8 @@ void setup_vault_mon_list(); int mons_tracking_range(const monsters *mon); +monsters* get_free_monster(); + class monster_pathfind { public: diff --git a/crawl-ref/source/monspeak.cc b/crawl-ref/source/mon-speak.cc index 8f66ebb025..3f21434520 100644 --- a/crawl-ref/source/monspeak.cc +++ b/crawl-ref/source/mon-speak.cc @@ -1,11 +1,11 @@ /* - * File: monspeak.cc + * File: mon-speak.cc * Summary: Functions to handle speaking monsters */ #include "AppHdr.h" -#include "monspeak.h" +#include "mon-speak.h" #include <stdlib.h> #include <string.h> @@ -23,7 +23,7 @@ #include "debug.h" #include "ghost.h" #include "message.h" -#include "monstuff.h" +#include "mon-stuff.h" #include "mon-util.h" #include "jobs.h" #include "player.h" @@ -355,6 +355,60 @@ static bool _polyd_can_speak(const monsters* monster) return (shape >= MON_SHAPE_HUMANOID && shape <= MON_SHAPE_NAGA); } +// Returns true if the monster did speak, false otherwise. +// Maybe monsters will speak! +void maybe_mons_speaks (monsters *monster) +{ +#define MON_SPEAK_CHANCE 21 + + if (monster->is_patrolling() || mons_is_wandering(monster) + || monster->attitude == ATT_NEUTRAL) + { + // Very fast wandering/patrolling monsters might, in one monster turn, + // move into the player's LOS and then back out (or the player + // might move into their LOS and the monster move back out before + // the player's view has a chance to update) so prevent them + // from speaking. + ; + } + else if ((mons_class_flag(monster->type, M_SPEAKS) + || !monster->mname.empty()) + && one_chance_in(MON_SPEAK_CHANCE)) + { + mons_speaks(monster); + } + else if (monster->type == MONS_CRAZY_YIUF + && one_chance_in(MON_SPEAK_CHANCE / 3)) + { + // Yiuf gets an extra chance to speak! + mons_speaks(monster); + } + else if (get_mon_shape(monster) >= MON_SHAPE_QUADRUPED) + { + // Non-humanoid-ish monsters have a low chance of speaking + // without the M_SPEAKS flag, to give the dungeon some + // atmosphere/flavour. + int chance = MON_SPEAK_CHANCE * 4; + + // Band members are a lot less likely to speak, since there's + // a lot of them. Except for uniques. + if (testbits(monster->flags, MF_BAND_MEMBER) + && !mons_is_unique(monster->type)) + chance *= 10; + + // However, confused and fleeing monsters are more interesting. + if (mons_is_fleeing(monster)) + chance /= 2; + if (monster->has_ench(ENCH_CONFUSION)) + chance /= 2; + + if (one_chance_in(chance)) + mons_speaks(monster); + } + // Okay then, don't speak. +} + + // Returns true if something is said. bool mons_speaks(monsters *monster) { diff --git a/crawl-ref/source/monspeak.h b/crawl-ref/source/mon-speak.h index 674aaa1257..e0e65b24ff 100644 --- a/crawl-ref/source/monspeak.h +++ b/crawl-ref/source/mon-speak.h @@ -1,5 +1,5 @@ /* - * File: monspeak.h + * File: mon-speak.h * Summary: Functions to handle speaking monsters */ @@ -8,6 +8,7 @@ #include "externs.h" +void maybe_mons_speaks(monsters *monster); bool mons_speaks(monsters *monster); bool mons_speaks_msg(monsters *monster, const std::string &msg, const msg_channel_type def_chan = MSGCH_TALK, diff --git a/crawl-ref/source/mon-spll.h b/crawl-ref/source/mon-spll.h index 52d6f152a7..9989ddcd21 100644 --- a/crawl-ref/source/mon-spll.h +++ b/crawl-ref/source/mon-spll.h @@ -1080,7 +1080,7 @@ SPELL_SLOW, SPELL_SUMMON_UGLY_THING, SPELL_PORKALATOR, - SPELL_BACKLIGHT, + SPELL_CORONA, SPELL_INVISIBILITY } }, @@ -1088,7 +1088,7 @@ { MST_DOWAN, { SPELL_THROW_FROST, - SPELL_BACKLIGHT, + SPELL_CORONA, SPELL_BLINK, SPELL_THROW_FLAME, SPELL_HASTE_OTHER, @@ -1100,7 +1100,7 @@ { SPELL_AIRSTRIKE, SPELL_SLOW, - SPELL_AIRSTRIKE, + SPELL_SWIFTNESS, SPELL_SUMMON_SMALL_MAMMALS, SPELL_CANTRIP, SPELL_AIRSTRIKE, diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/mon-stuff.cc index d94598974c..0e8a3b436f 100644 --- a/crawl-ref/source/monstuff.cc +++ b/crawl-ref/source/mon-stuff.cc @@ -1,11 +1,11 @@ /* - * File: monstuff.cc + * File: mon-stuff.cc * Summary: Misc monster related functions. * Written by: Linley Henzell */ #include "AppHdr.h" -#include "monstuff.h" +#include "mon-stuff.h" //#include <stdlib.h> //#include <string.h> @@ -35,8 +35,9 @@ #include "misc.h" #include "mon-abil.h" #include "mon-behv.h" -#include "monplace.h" -#include "monspeak.h" +#include "mon-iter.h" +#include "mon-place.h" +#include "mon-speak.h" #include "notes.h" #include "options.h" #include "player.h" @@ -334,11 +335,16 @@ monster_type fill_out_corpse(const monsters* monster, item_def& corpse, corpse.colour = monster->colour; if (!monster->mname.empty()) + { corpse.props[CORPSE_NAME_KEY] = monster->mname; + corpse.props[CORPSE_NAME_TYPE_KEY] + = (long) (monster->flags & MF_NAME_MASK); + } else if (mons_is_unique(monster->type)) { corpse.props[CORPSE_NAME_KEY] = mons_type_name(monster->type, DESC_PLAIN); + corpse.props[CORPSE_NAME_TYPE_KEY] = (long) 0; } return (corpse_class); @@ -1213,44 +1219,57 @@ static void _elven_twin_died(monsters* twin) bool found_dowan = false; monsters *monster; - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi; mi; ++mi) { - monster = &menv[i]; - if (monster->alive() && monster->type == MONS_DUVESSA) + if (mi->type == MONS_DUVESSA) { + monster = *mi; found_duvessa = true; break; } - else if (monster->alive() && monster->type == MONS_DOWAN) + else if (mi->type == MONS_DOWAN) { + monster = *mi; found_dowan = true; break; } } - if ((found_duvessa || found_dowan) && mons_near(monster)) - { - // Will generate strings such as 'Duvessa_Duvessa_dies' or, alternately - // 'Dowan_Dowan_dies', but as neither will match, these can safely be - // ignored. - std::string key = "_" + monster->name(DESC_CAP_THE, true) + "_" - + twin->name(DESC_CAP_THE) + "_dies_"; + if (!found_duvessa && !found_dowan) + return; - if (!monster->observable()) - key += "invisible_"; + // If you've stabbed one of them, the other one is likely asleep still. + if (monster->asleep()) + behaviour_event(monster, ME_DISTURB, MHITNOT, monster->pos()); - std::string death_message = getSpeakString(key); + // Will generate strings such as 'Duvessa_Duvessa_dies' or, alternately + // 'Dowan_Dowan_dies', but as neither will match, these can safely be + // ignored. + std::string key = "_" + monster->name(DESC_CAP_THE, true) + "_" + + twin->name(DESC_CAP_THE) + "_dies_"; - if (!death_message.empty()) - mons_speaks_msg(monster, death_message, MSGCH_TALK, silenced(you.pos())); - } + if (mons_near(monster) && !monster->observable()) + key += "invisible_"; + else if (!mons_near(monster)) + key += "distance_"; - if (found_duvessa && mons_near(monster)) + std::string death_message = getSpeakString(key); + + if (mons_near(monster) && !death_message.empty()) + mons_speaks_msg(monster, death_message, MSGCH_TALK, silenced(you.pos())); + else + mprf("%s", death_message.c_str()); + + if (found_duvessa) { - // Provides its own flavour message. - monster->go_berserk(true); + if (mons_near(monster)) + // Provides its own flavour message. + monster->go_berserk(true); + else + // She'll go berserk the next time she sees you + monster->flags |= MF_GOING_BERSERK; } - else if (found_dowan && mons_near(monster)) + else if (found_dowan) { // Doesn't provide any message, so needs one, but only if visible. if (monster->observable()) @@ -1267,18 +1286,17 @@ void pikel_band_neutralise () // with MF_BAND_MEMBER are Pikel's band members. bool message_made = false; - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi; mi; ++mi) { - monsters *monster = &menv[i]; - if (monster->alive() && monster->type == MONS_HUMAN - && testbits(monster->flags, MF_BAND_MEMBER)) + if (mi->type == MONS_HUMAN + && testbits(mi->flags, MF_BAND_MEMBER)) { - if (monster->observable() && !message_made) + if (mi->observable() && !message_made) { mpr("Pikel's slaves thank you for their freedom."); message_made = true; } - mons_pacify(monster); + mons_pacify(*mi); } } } @@ -1294,60 +1312,87 @@ static void _hogs_to_humans() // porkalator spell, they should be handled specially... int any = 0, human = 0; - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi; mi; ++mi) { - monsters *monster = &menv[i]; - if (monster->alive() && monster->type == MONS_HOG) + if (mi->type != MONS_HOG) + continue; + + // Shapeshifters will stop being a hog when they feel like it. + if (mi->is_shapeshifter()) + continue; + + const bool could_see = you.can_see(*mi); + + monsters _orig; + monsters* orig; + + if (mi->props.exists(ORIG_MONSTER_KEY)) { - const bool could_see = you.can_see(monster); + orig = &(mi->props[ORIG_MONSTER_KEY].get_monster()); + } + else + { + orig = &_orig; + orig->type = MONS_HUMAN; + define_monster(*orig); + } - // XXX: This resets the size of slime creatures, the number - // of heads a hydra has, and the number of spikes a manticore - // has. Plus it also changes the colour of a draconian which - // has a sub-type. And it re-rolls the spellbook the monster - // has. - if (monster->number == 0) - monster->type = MONS_HUMAN; - else - monster->type = (monster_type) (monster->number - 1); + // Preserve relative HP. + const float hp + = (float) mi->hit_points / (float) mi->max_hit_points; + // Preserve some flags. + const unsigned long preserve_flags = + mi->flags & ~(MF_JUST_SUMMONED | MF_WAS_IN_VIEW); - monster->number = 0; - define_monster(*monster); + // Preserve enchantments. + mon_enchant_list enchantments = mi->enchantments; - const bool can_see = you.can_see(monster); + // Restore original monster. + **mi = *orig; - // A monster changing factions while in the arena messes up - // arena book-keeping. - if (!crawl_state.arena) + mi->enchantments = enchantments; + mi->hit_points = std::max(1, (int) (mi->max_hit_points * hp)); + mi->flags = mi->flags | preserve_flags; + + // Allow ORIG_MONSTER_KEY to be chained. + if (orig->props.exists(ORIG_MONSTER_KEY)) + mi->props[ORIG_MONSTER_KEY] = orig->props[ORIG_MONSTER_KEY]; + else + mi->props.erase(ORIG_MONSTER_KEY); + + const bool can_see = you.can_see(*mi); + + // A monster changing factions while in the arena messes up + // arena book-keeping. + if (!crawl_state.arena) + { + // * A monster's attitude shouldn't downgrade from friendly + // or good-neutral because you helped it. It'd suck to + // lose a permanent ally that way. + // + // * A monster has to be smart enough to realize that you + // helped it. + if (mi->attitude == ATT_HOSTILE + && mons_intel(*mi) >= I_NORMAL) { - // * A monster's attitude shouldn't downgrade from friendly - // or good-neutral because you helped it. It'd suck to - // lose a permanent ally that way. - // - // * A monster has to be smart enough to realize that you - // helped it. - if (monster->attitude == ATT_HOSTILE - && mons_intel(monster) >= I_NORMAL) - { - monster->attitude = ATT_GOOD_NEUTRAL; - monster->flags |= MF_WAS_NEUTRAL; - } + mi->attitude = ATT_GOOD_NEUTRAL; + mi->flags |= MF_WAS_NEUTRAL; } + } - behaviour_event(monster, ME_EVAL); + behaviour_event(*mi, ME_EVAL); - if (could_see && can_see) - { - any++; - if (monster->type == MONS_HUMAN) - human++; - } - else if (could_see && !can_see) - mpr("The hog vanishes!"); - else if (!could_see && can_see) - mprf("%s appears from out of thin air!", - monster->name(DESC_CAP_A).c_str()); + if (could_see && can_see) + { + any++; + if (mi->type == MONS_HUMAN) + human++; } + else if (could_see && !can_see) + mpr("The hog vanishes!"); + else if (!could_see && can_see) + mprf("%s appears from out of thin air!", + mi->name(DESC_CAP_A).c_str()); } if (any == 1) @@ -1391,14 +1436,13 @@ void mons_relocated(monsters *monster) if (invalid_monster_index(headnum)) return; - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi; mi; ++mi) { - monsters *tentacle = &menv[i]; - if (tentacle->type == MONS_KRAKEN_TENTACLE - && (int)tentacle->number == headnum - && _tentacle_too_far(monster, tentacle)) + if (mi->type == MONS_KRAKEN_TENTACLE + && (int)mi->number == headnum + && _tentacle_too_far(monster, *mi)) { - monster_die(tentacle, KILL_RESET, -1, true, false); + monster_die(*mi, KILL_RESET, -1, true, false); } } } @@ -1421,15 +1465,14 @@ static int _destroy_tentacles(monsters *head) if (invalid_monster_index(headnum)) return 0; - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi; mi; ++mi) { - monsters *monster = &menv[i]; - if (monster->type == MONS_KRAKEN_TENTACLE - && (int)monster->number == headnum) + if (mi->type == MONS_KRAKEN_TENTACLE + && (int)mi->number == headnum) { - if (mons_near(monster)) + if (mons_near(*mi)) tent++; - monster->hurt(monster, INSTANT_DEATH); + mi->hurt(*mi, INSTANT_DEATH); } } return tent; @@ -1793,7 +1836,7 @@ int monster_die(monsters *monster, killer_type killer, { const int spectre = create_monster( - mgen_data(MONS_SPECTRAL_THING, BEH_FRIENDLY, + mgen_data(MONS_SPECTRAL_THING, BEH_FRIENDLY, &you, 0, 0, monster->pos(), MHITYOU, 0, static_cast<god_type>(you.attribute[ATTR_DIVINE_DEATH_CHANNEL]), spectre_type, monster->number)); @@ -2200,9 +2243,9 @@ void monster_cleanup(monsters *monster) unsigned int monster_killed = monster_index(monster); monster->reset(); - for (int dmi = 0; dmi < MAX_MONSTERS; dmi++) - if (menv[dmi].foe == monster_killed) - menv[dmi].foe = MHITNOT; + for (monster_iterator mi; mi; ++mi) + if (mi->foe == monster_killed) + mi->foe = MHITNOT; if (you.pet_target == monster_killed) you.pet_target = MHITNOT; @@ -2211,24 +2254,14 @@ void monster_cleanup(monsters *monster) // If you're invis and throw/zap whatever, alerts menv to your position. void alert_nearby_monsters(void) { - monsters *monster = 0; // NULL {dlb} - - for (int it = 0; it < MAX_MONSTERS; it++) - { - monster = &menv[it]; - - // Judging from the above comment, this function isn't - // intended to wake up monsters, so we're only going to - // alert monsters that aren't sleeping. For cases where an - // event should wake up monsters and alert them, I'd suggest - // calling noisy() before calling this function. -- bwr - if (monster->alive() - && mons_near(monster) - && !monster->asleep()) - { - behaviour_event(monster, ME_ALERT, MHITYOU); - } - } + // Judging from the above comment, this function isn't + // intended to wake up monsters, so we're only going to + // alert monsters that aren't sleeping. For cases where an + // event should wake up monsters and alert them, I'd suggest + // calling noisy() before calling this function. -- bwr + for (monster_iterator mi(&you.get_los()); mi; ++mi) + if (!mi->asleep()) + behaviour_event(*mi, ME_ALERT, MHITYOU); } static bool _valid_morph(monsters *monster, monster_type new_mclass) @@ -3621,15 +3654,14 @@ int dismiss_monsters(std::string pattern) { // Dismiss by regex text_pattern tpat(pattern); int ndismissed = 0; - for (int mon = 0; mon < MAX_MONSTERS; mon++) + for (monster_iterator mi; mi; ++mi) { - monsters *monster = &menv[mon]; - if (monster->alive() && - (tpat.empty() || tpat.matches(monster->name(DESC_PLAIN, true)))) + if (mi->alive() && + (tpat.empty() || tpat.matches(mi->name(DESC_PLAIN, true)))) { if (!keep_item) - _vanish_orig_eq(monster); - monster_die(monster, KILL_DISMISSED, NON_MONSTER, false, true); + _vanish_orig_eq(*mi); + monster_die(*mi, KILL_DISMISSED, NON_MONSTER, false, true); ++ndismissed; } } @@ -3846,15 +3878,9 @@ int clone_mons(const monsters* orig, bool quiet, bool* obvious, coord_def pos) { // Is there an open slot in menv? - int midx = NON_MONSTER; - for (int i = 0; i < MAX_MONSTERS; i++) - if (menv[i].type == MONS_NO_MONSTER) - { - midx = i; - break; - } + monsters* mons = get_free_monster(); - if (midx == NON_MONSTER) + if (!mons) return (NON_MONSTER); if (!in_bounds(pos)) @@ -3880,11 +3906,9 @@ int clone_mons(const monsters* orig, bool quiet, bool* obvious, ASSERT( !actor_at(pos) ); - monsters &mon(menv[midx]); - - mon = *orig; - mon.set_position(pos); - mgrd(pos) = midx; + *mons = *orig; + mons->set_position(pos); + mgrd(pos) = mons->mindex(); // Duplicate objects, or unequip them if they can't be duplicated. for (int i = 0; i < NUM_MONSTER_SLOTS; i++) @@ -3897,14 +3921,14 @@ int clone_mons(const monsters* orig, bool quiet, bool* obvious, const int new_index = get_item_slot(0); if (new_index == NON_ITEM) { - mon.unequip(mitm[old_index], i, 0, true); - mon.inv[i] = NON_ITEM; + mons->unequip(mitm[old_index], i, 0, true); + mons->inv[i] = NON_ITEM; continue; } - mon.inv[i] = new_index; + mons->inv[i] = new_index; mitm[new_index] = mitm[old_index]; - mitm[new_index].set_holding_monster(midx); + mitm[new_index].set_holding_monster(mons->mindex()); } bool _obvious; @@ -3912,24 +3936,24 @@ int clone_mons(const monsters* orig, bool quiet, bool* obvious, obvious = &_obvious; *obvious = false; - if (you.can_see(orig) && you.can_see(&mon)) + if (you.can_see(orig) && you.can_see(mons)) { if (!quiet) simple_monster_message(orig, " is duplicated!"); *obvious = true; } - mark_interesting_monst(&mon, mon.behaviour); - if (you.can_see(&mon)) + mark_interesting_monst(mons, mons->behaviour); + if (you.can_see(mons)) { - handle_seen_interrupt(&mon); + handle_seen_interrupt(mons); viewwindow(false); } if (crawl_state.arena) - arena_placed_monster(&mon); + arena_placed_monster(mons); - return (midx); + return (mons->mindex()); } std::string summoned_poof_msg(const monsters* monster, bool plural) diff --git a/crawl-ref/source/monstuff.h b/crawl-ref/source/mon-stuff.h index 75656c73a1..4f1bb73a78 100644 --- a/crawl-ref/source/monstuff.h +++ b/crawl-ref/source/mon-stuff.h @@ -1,5 +1,5 @@ /* - * File: monstuff.h + * File: mon-stuff.h * Summary: Misc monster related functions. * Written by: Linley Henzell */ @@ -10,6 +10,8 @@ #include "mon-util.h" +#define ORIG_MONSTER_KEY "orig_monster_key" + enum mon_dam_level_type { MDAM_OKAY, diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc index b0a831e167..d891ed2b50 100644 --- a/crawl-ref/source/mon-util.cc +++ b/crawl-ref/source/mon-util.cc @@ -23,8 +23,8 @@ #include "kills.h" #include "los.h" #include "mon-behv.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "options.h" #include "random.h" #include "religion.h" @@ -1360,8 +1360,8 @@ monster_type random_draconian_monster_species() // Note: For consistent behavior in player_will_anger_monster(), all // spellbooks a given monster can get here should produce the same -// return values in is_holy_spell(), is_evil_spell(), and -// is_chaotic_spell(). +// return values in is_holy_spell(), (is_unholy_spell() || +// is_evil_spell()), and is_chaotic_spell(). // // FIXME: This is not true for one set of spellbooks; MST_WIZARD_IV // contains the evil Banishment spell, but the other MST_WIZARD-type @@ -2209,6 +2209,7 @@ bool ms_useful_fleeing_out_of_sight( const monsters *mon, spell_type monspell ) switch (monspell) { case SPELL_HASTE: + case SPELL_SWIFTNESS: case SPELL_INVISIBILITY: case SPELL_MINOR_HEALING: case SPELL_MAJOR_HEALING: @@ -2355,7 +2356,7 @@ bool ms_waste_of_time( const monsters *mon, spell_type monspell ) ret = (!foe || foe->holiness() != MH_UNDEAD); break; - case SPELL_BACKLIGHT: + case SPELL_CORONA: ret = (!foe || foe->backlit()); break; @@ -2369,6 +2370,11 @@ bool ms_waste_of_time( const monsters *mon, spell_type monspell ) ret = true; break; + case SPELL_SWIFTNESS: + if (mon->has_ench(ENCH_SWIFT)) + ret = true; + break; + case SPELL_INVISIBILITY: if (mon->has_ench(ENCH_INVIS) || mon->friendly() && !you.can_see_invisible(false)) @@ -2410,8 +2416,9 @@ bool ms_waste_of_time( const monsters *mon, spell_type monspell ) case SPELL_DISINTEGRATE: case SPELL_PARALYSE: case SPELL_SLEEP: + case SPELL_HIBERNATION: { - if (monspell == SPELL_SLEEP && (!foe || foe->asleep())) + if (monspell == SPELL_HIBERNATION && (!foe || foe->asleep())) { ret = true; break; @@ -2522,6 +2529,7 @@ static bool _ms_ranged_spell(spell_type monspell, bool attack_only = false, case SPELL_INVISIBILITY: case SPELL_BLINK: case SPELL_BERSERKER_RAGE: + case SPELL_SWIFTNESS: return (false); // The animation spells don't work through transparent walls and thus @@ -2533,6 +2541,7 @@ static bool _ms_ranged_spell(spell_type monspell, bool attack_only = false, case SPELL_CONFUSE: case SPELL_SLOW: case SPELL_PARALYSE: + case SPELL_SLEEP: case SPELL_TELEPORT_OTHER: return (ench_too); diff --git a/crawl-ref/source/monster.cc b/crawl-ref/source/monster.cc index 4b706d8a47..869e65ce68 100644 --- a/crawl-ref/source/monster.cc +++ b/crawl-ref/source/monster.cc @@ -19,8 +19,8 @@ #include "misc.h" #include "mon-abil.h" #include "mon-behv.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "mtransit.h" #include "random.h" #include "religion.h" @@ -52,7 +52,7 @@ monsters::monsters() inv(NON_ITEM), spells(), attitude(ATT_HOSTILE), behaviour(BEH_WANDER), foe(MHITYOU), enchantments(), flags(0L), experience(0), number(0), colour(BLACK), foe_memory(0), shield_blocks(0), god(GOD_NO_GOD), ghost(), - seen_context("") + seen_context(""), props() { travel_path.clear(); } @@ -105,6 +105,7 @@ void monsters::reset() travel_path.clear(); ghost.reset(NULL); seen_context = ""; + props.clear(); } void monsters::init_with(const monsters &mon) @@ -136,6 +137,7 @@ void monsters::init_with(const monsters &mon) colour = mon.colour; foe_memory = mon.foe_memory; god = mon.god; + props = mon.props; if (mon.ghost.get()) ghost.reset(new ghost_demon(*mon.ghost)); @@ -1199,6 +1201,8 @@ static bool _compatible_launcher_ammo_brands(item_def *launcher, return (bow_brand != SPWPN_FLAME && bow_brand != SPWPN_FROST); case SPMSL_CHAOS: return (bow_brand != SPWPN_CHAOS); + case SPMSL_REAPING: + return (bow_brand != SPWPN_HOLY_WRATH); default: return (true); } @@ -1758,7 +1762,7 @@ bool monsters::pickup_misc(item_def &item, int near) return (pickup(item, MSLOT_MISCELLANY, near)); } -// Eaten items are handled elsewhere, in _handle_pickup() in monstuff.cc. +// Eaten items are handled elsewhere, in _handle_pickup() in mon-stuff.cc. bool monsters::pickup_item(item_def &item, int near, bool force) { // Equipping stuff can be forced when initially equipping monsters. @@ -2850,7 +2854,7 @@ bool monsters::asleep() const bool monsters::backlit(bool check_haloed) const { - return (has_ench(ENCH_BACKLIGHT) + return (has_ench(ENCH_CORONA) || ((check_haloed) ? haloed() : false)); } @@ -3508,7 +3512,7 @@ bool monsters::rot(actor *agent, int amount, int immediate, bool quiet) int monsters::hurt(const actor *agent, int amount, beam_type flavour, bool cleanup_dead) { - if (hit_points > 0 && type != -1) + if (alive()) { if (amount == INSTANT_DEATH) amount = hit_points; @@ -4208,6 +4212,11 @@ void monsters::remove_enchantment_effect(const mon_enchant &me, bool quiet) simple_monster_message(this, " is no longer moving quickly."); break; + case ENCH_SWIFT: + if (!quiet) + simple_monster_message(this, " is no longer moving somewhat quickly."); + break; + case ENCH_MIGHT: if (!quiet) simple_monster_message(this, " no longer looks unusually strong."); @@ -4322,7 +4331,7 @@ void monsters::remove_enchantment_effect(const mon_enchant &me, bool quiet) behaviour_event(this, ME_EVAL); break; - case ENCH_BACKLIGHT: + case ENCH_CORONA: if (!quiet) { if (visible_to(&you)) @@ -4515,12 +4524,12 @@ void monsters::timeout_enchantments(int levels) { switch (i->first) { - case ENCH_POISON: case ENCH_ROT: case ENCH_BACKLIGHT: + case ENCH_POISON: case ENCH_ROT: case ENCH_CORONA: case ENCH_STICKY_FLAME: case ENCH_ABJ: case ENCH_SHORT_LIVED: case ENCH_SLOW: case ENCH_HASTE: case ENCH_MIGHT: case ENCH_FEAR: case ENCH_INVIS: case ENCH_CHARM: case ENCH_SLEEP_WARY: case ENCH_SICK: case ENCH_SLEEPY: case ENCH_PARALYSIS: - case ENCH_PETRIFYING: case ENCH_PETRIFIED: + case ENCH_PETRIFYING: case ENCH_PETRIFIED: case ENCH_SWIFT: case ENCH_BATTLE_FRENZY: case ENCH_NEUTRAL: case ENCH_LOWERED_MR: case ENCH_SOUL_RIPE: lose_ench_levels(i->second, levels); @@ -4654,6 +4663,7 @@ void monsters::apply_enchantment(const mon_enchant &me) case ENCH_SLOW: case ENCH_HASTE: + case ENCH_SWIFT: case ENCH_MIGHT: case ENCH_FEAR: case ENCH_PARALYSIS: @@ -4661,7 +4671,7 @@ void monsters::apply_enchantment(const mon_enchant &me) case ENCH_PETRIFYING: case ENCH_PETRIFIED: case ENCH_SICK: - case ENCH_BACKLIGHT: + case ENCH_CORONA: case ENCH_ABJ: case ENCH_CHARM: case ENCH_SLEEP_WARY: @@ -5001,6 +5011,7 @@ void monsters::apply_enchantment(const mon_enchant &me) int rc = create_monster(mgen_data(MONS_GIANT_SPORE, created_behavior, + this, 0, 0, adjacent, @@ -5576,7 +5587,7 @@ bool monsters::do_shaft() return (reveal); } -bool monsters::can_sleep(bool holi_only) const +bool monsters::can_hibernate(bool holi_only) const { // Undead, nonliving, and plants don't sleep. const mon_holy_type holi = holiness(); @@ -5601,9 +5612,9 @@ bool monsters::can_sleep(bool holi_only) const return (true); } -void monsters::put_to_sleep(int) +void monsters::hibernate(int) { - if (!can_sleep()) + if (!can_hibernate()) return; behaviour = BEH_SLEEP; @@ -5624,12 +5635,14 @@ const monsterentry *monsters::find_monsterentry() const int monsters::action_energy(energy_use_type et) const { + bool swift = has_ench(ENCH_SWIFT); + if (const monsterentry *me = find_monsterentry()) { const mon_energy_usage &mu = me->energy_usage; switch (et) { - case EUT_MOVE: return mu.move; + case EUT_MOVE: return mu.move - (swift ? 2 : 0); case EUT_SWIM: // [ds] Amphibious monsters get a significant speed boost // when swimming, as discussed with dpeg. We do not @@ -5638,9 +5651,9 @@ int monsters::action_energy(energy_use_type et) const // favour water (HT_AMPHIBIOUS_WATER, such as merfolk), but // that's something we can think about. if (mons_amphibious(this)) - return div_rand_round(mu.swim * 7, 10); + return div_rand_round(mu.swim * 7, 10) - (swift ? 2 : 0); else - return mu.swim; + return mu.swim - (swift ? 2 : 0); case EUT_MISSILE: return mu.missile; case EUT_ITEM: return mu.item; case EUT_SPECIAL: return mu.special; @@ -5835,7 +5848,7 @@ void monsters::react_to_damage(int damage, beam_type flavour, kill_category whos continue; const int nmons = mons_place( - mgen_data(jelly, beha, 0, 0, + mgen_data(jelly, beha, this, 0, 0, jpos, foe, 0, god)); if (nmons != -1 && nmons != NON_MONSTER) @@ -5893,7 +5906,7 @@ static const char *enchant_names[] = "short-lived", "paralysis", "sick", "sleep", "fatigue", "held", "blood-lust", "neutral", "petrifying", "petrified", "magic-vulnerable", "soul-ripe", "decay", "hungry", "flopping", "spore-producing", - "downtrodden", "bug" + "downtrodden", "swift", "bug" }; static const char *_mons_enchantment_name(enchant_type ench) @@ -5994,6 +6007,7 @@ int mon_enchant::calc_duration(const monsters *mons, switch (ench) { case ENCH_HASTE: + case ENCH_SWIFT: case ENCH_MIGHT: case ENCH_INVIS: cturn = 1000 / _mod_speed(25, mons->speed); @@ -6030,7 +6044,7 @@ int mon_enchant::calc_duration(const monsters *mons, cturn = 1000 * (deg - 1) / _mod_speed(333, mons->speed); cturn += 1000 / _mod_speed(250, mons->speed); break; - case ENCH_BACKLIGHT: + case ENCH_CORONA: if (deg > 1) cturn = 1000 * (deg - 1) / _mod_speed(200, mons->speed); cturn += 1000 / _mod_speed(100, mons->speed); diff --git a/crawl-ref/source/monster.h b/crawl-ref/source/monster.h index 26b266ee37..8725688d01 100644 --- a/crawl-ref/source/monster.h +++ b/crawl-ref/source/monster.h @@ -60,6 +60,7 @@ public: void reset(); public: + // Possibly some of these should be moved into the hash table std::string mname; monster_type type; @@ -102,6 +103,8 @@ public: std::string seen_context; // Non-standard context for // AI_SEE_MONSTER + CrawlHashTable props; + public: mon_attitude_type temp_attitude() const; @@ -377,8 +380,8 @@ public: void blink(bool allow_partial_control = true); void teleport(bool right_now = false, bool abyss_shift = false); - bool can_sleep(bool holi_only = false) const; - void put_to_sleep(int power = 0); + bool can_hibernate(bool holi_only = false) const; + void hibernate(int power = 0); void check_awaken(int disturbance); int stat_hp() const { return hit_points; } diff --git a/crawl-ref/source/mtransit.cc b/crawl-ref/source/mtransit.cc index a743278398..e9bf292df2 100644 --- a/crawl-ref/source/mtransit.cc +++ b/crawl-ref/source/mtransit.cc @@ -13,7 +13,7 @@ #include "artefact.h" #include "dungeon.h" #include "items.h" -#include "monplace.h" +#include "mon-place.h" #include "mon-util.h" #include "random.h" diff --git a/crawl-ref/source/newgame.cc b/crawl-ref/source/newgame.cc index 4223ef6c0e..b0760bc6de 100644 --- a/crawl-ref/source/newgame.cc +++ b/crawl-ref/source/newgame.cc @@ -893,6 +893,7 @@ game_start: Generated_Levels.clear(); initialise_branch_depths(); + initialise_temples(); init_level_connectivity(); // Generate the second name of Jiyva @@ -1645,7 +1646,7 @@ static void _give_basic_spells(job_type which_job) which_spell = SPELL_PAIN; break; case JOB_ENCHANTER: - which_spell = SPELL_BACKLIGHT; + which_spell = SPELL_CORONA; break; case JOB_FIRE_ELEMENTALIST: which_spell = SPELL_FLAME_TONGUE; @@ -2426,7 +2427,7 @@ static void _give_wanderer_spell(skill_type skill) break; case SK_ENCHANTMENTS: - spell = SPELL_BACKLIGHT; + spell = SPELL_CORONA; break; } diff --git a/crawl-ref/source/ng-init.cc b/crawl-ref/source/ng-init.cc index 446c95af1a..588d42b505 100644 --- a/crawl-ref/source/ng-init.cc +++ b/crawl-ref/source/ng-init.cc @@ -10,9 +10,17 @@ #include "branch.h" #include "describe.h" +#include "dungeon.h" #include "itemname.h" +#include "maps.h" #include "player.h" #include "random.h" +#include "religion.h" +#include "store.h" + +#ifdef DEBUG_DIAGNOSTICS +#define DEBUG_TEMPLES 1 +#endif static unsigned char _random_potion_description() { @@ -64,6 +72,125 @@ void initialise_branch_depths() branches[BRANCH_TOMB].startdepth = random_range(2, 3); } +#define MAX_OVERFLOW_LEVEL 9 + +// Determine which altars go into the Ecumenical Temple, which go into +// overflow temples, and on what level the overflow temples are. +void initialise_temples() +{ + ////////////////////////////////////////// + // First determine main temple map to use. + level_id ecumenical(BRANCH_ECUMENICAL_TEMPLE, 1); + + map_def *main_temple = NULL; + for (int i = 0; i < 10; i++) + { + main_temple + = const_cast<map_def*>(random_map_for_place(ecumenical, false)); + + if (main_temple == NULL) + end (1, false, "No temples?!"); + + // Without all this find_glyph() returns 0. + std::string err; + main_temple->load(); + main_temple->reinit(); + err = main_temple->run_lua(true); + + if (!err.empty()) + { + mprf(MSGCH_ERROR, "Temple %s: %s", main_temple->name.c_str(), + err.c_str()); + main_temple = NULL; + continue; + } + + main_temple->fixup(); + err = main_temple->resolve(); + + if (!err.empty()) + { + mprf(MSGCH_ERROR, "Temple %s: %s", main_temple->name.c_str(), + err.c_str()); + main_temple = NULL; + continue; + } + break; + } + + if (main_temple == NULL) + end(1, false, "No valid temples."); + + you.props[TEMPLE_MAP_KEY] = main_temple->name; + + const std::vector<coord_def> altar_coords + = main_temple->find_glyph('B'); + const unsigned int main_temple_size = altar_coords.size(); + + if (main_temple_size == 0) + { + end(1, false, "Main temple '%s' has no altars", + main_temple->name.c_str()); + } + +#ifdef DEBUG_TEMPLES + mprf(MSGCH_DIAGNOSTICS, "Chose main temple %s, size %lu", + main_temple->name.c_str(), main_temple_size); +#endif + + /////////////////////////////////// + // Now set up the overflow temples. + + std::vector<god_type> god_list = temple_god_list(); + + std::random_shuffle(god_list.begin(), god_list.end()); + + std::vector<god_type> overflow_gods; + + while (god_list.size() > main_temple_size) + { + overflow_gods.push_back(god_list.back()); + god_list.pop_back(); + } + +#ifdef DEBUG_TEMPLES + mprf(MSGCH_DIAGNOSTICS, "%lu overflow altars", overflow_gods.size()); +#endif + + CrawlVector &temple_gods + = you.props[TEMPLE_GODS_KEY].new_vector(SV_BYTE); + + for (unsigned int i = 0; i < god_list.size(); i++) + temple_gods.push_back( (char) god_list[i] ); + + CrawlVector &overflow_temples + = you.props[OVERFLOW_TEMPLES_KEY].new_vector(SV_VEC); + overflow_temples.resize(MAX_OVERFLOW_LEVEL); + + // NOTE: The overflow temples don't have to contain only one + // altar; they can contain any number of altars, so long as there's + // at least one vault definition with the tag "overflow_temple_num" + // (where "num" is the number of altars). + for (unsigned int i = 0; i < overflow_gods.size(); i++) + { + const unsigned int level = random_range(2, MAX_OVERFLOW_LEVEL); + + // List of overflow temples on this level. + CrawlVector &level_temples + = overflow_temples[level - 1].get_vector(); + + CrawlHashTable temple; + + CrawlVector &gods + = temple[TEMPLE_GODS_KEY].new_vector(SV_BYTE); + + // Only single-altar overflow temples for now. + gods.push_back( (char) overflow_gods[i] ); + + level_temples.push_back(temple); + } +} + static int _get_random_porridge_desc() { return PDESCQ(PDQ_GLUGGY, one_chance_in(3) ? PDC_BROWN diff --git a/crawl-ref/source/ng-init.h b/crawl-ref/source/ng-init.h index 58fdce4514..dc41e8168d 100644 --- a/crawl-ref/source/ng-init.h +++ b/crawl-ref/source/ng-init.h @@ -3,6 +3,7 @@ void fix_up_jiyva_name(); void initialise_branch_depths(); +void initialise_temples(); void initialise_item_descriptions(); #endif diff --git a/crawl-ref/source/ouch.cc b/crawl-ref/source/ouch.cc index e4230464af..b3912a3e1f 100644 --- a/crawl-ref/source/ouch.cc +++ b/crawl-ref/source/ouch.cc @@ -51,8 +51,8 @@ #include "message.h" #include "misc.h" #include "mon-util.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "notes.h" #include "output.h" #include "player.h" @@ -947,7 +947,7 @@ static void _maybe_spawn_jellies(int dam, const char* aux, int count_created = 0; for (int i = 0; i < how_many; ++i) { - mgen_data mg(mon, BEH_STRICT_NEUTRAL, 0, 0, you.pos(), + mgen_data mg(mon, BEH_STRICT_NEUTRAL, &you, 0, 0, you.pos(), MHITNOT, 0, GOD_JIYVA); if (create_monster(mg) != -1) @@ -1218,34 +1218,9 @@ static std::string morgue_name(time_t when_crawl_got_even) #endif // SHORT_FILE_NAMES } -void end_game( scorefile_entry &se ) +// Delete save files on game end. +static void delete_files() { - bool dead = true; - - for (int i = 0; i < ENDOFPACK; i++) - set_ident_flags( you.inv[i], ISFLAG_IDENT_MASK ); - - for (int i = 0; i < ENDOFPACK; i++) - { - if (you.inv[i].base_type != 0) - set_ident_type( you.inv[i], ID_KNOWN_TYPE ); - } - - if (!dump_char( morgue_name(se.death_time), !dead, true, &se )) - { - mpr("Char dump unsuccessful! Sorry about that."); - if (!crawl_state.seen_hups) - more(); - clrscr(); - } - - if (se.death_type == KILLED_BY_LEAVING - || se.death_type == KILLED_BY_QUITTING - || se.death_type == KILLED_BY_WINNING) - { - dead = false; - } - // clean all levels that we think we have ever visited for (level_id_set::const_iterator i = Generated_Levels.begin(); i != Generated_Levels.end(); ++i) @@ -1289,6 +1264,37 @@ void end_game( scorefile_entry &se ) std::string tmpname = basename + suffixes[i]; unlink( tmpname.c_str() ); } +} + +void end_game(scorefile_entry &se) +{ + bool dead = true; + + for (int i = 0; i < ENDOFPACK; i++) + set_ident_flags( you.inv[i], ISFLAG_IDENT_MASK ); + + for (int i = 0; i < ENDOFPACK; i++) + { + if (you.inv[i].base_type != 0) + set_ident_type( you.inv[i], ID_KNOWN_TYPE ); + } + + delete_files(); + + if (!dump_char( morgue_name(se.death_time), !dead, true, &se )) + { + mpr("Char dump unsuccessful! Sorry about that."); + if (!crawl_state.seen_hups) + more(); + clrscr(); + } + + if (se.death_type == KILLED_BY_LEAVING + || se.death_type == KILLED_BY_QUITTING + || se.death_type == KILLED_BY_WINNING) + { + dead = false; + } // death message if (dead) diff --git a/crawl-ref/source/output.cc b/crawl-ref/source/output.cc index 9e6978bb87..a1494fe726 100644 --- a/crawl-ref/source/output.cc +++ b/crawl-ref/source/output.cc @@ -34,7 +34,7 @@ #include "item_use.h" #include "menu.h" #include "message.h" -#include "monstuff.h" +#include "mon-stuff.h" #include "mon-info.h" #include "mon-util.h" #include "newgame.h" diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc index b3d7218db1..19b8758dd2 100644 --- a/crawl-ref/source/player.cc +++ b/crawl-ref/source/player.cc @@ -6895,7 +6895,7 @@ bool player::visible_to(const actor *looker) const bool player::backlit(bool check_haloed) const { - return (get_contamination_level() > 0 || duration[DUR_BACKLIGHT] + return (get_contamination_level() > 0 || duration[DUR_CORONA] || (check_haloed ? haloed() : false)); } @@ -6904,22 +6904,22 @@ void player::backlight() { if (!this->duration[DUR_INVIS]) { - if (this->duration[DUR_BACKLIGHT]) + if (this->duration[DUR_CORONA]) mpr("You glow brighter."); else mpr("You are outlined in light."); - this->duration[DUR_BACKLIGHT] += random_range(15, 35); - if (this->duration[DUR_BACKLIGHT] > 250) - this->duration[DUR_BACKLIGHT] = 250; + this->duration[DUR_CORONA] += random_range(15, 35); + if (this->duration[DUR_CORONA] > 250) + this->duration[DUR_CORONA] = 250; } else { mpr("You feel strangely conspicuous."); - this->duration[DUR_BACKLIGHT] += random_range(3, 5); - if (this->duration[DUR_BACKLIGHT] > 250) - this->duration[DUR_BACKLIGHT] = 250; + this->duration[DUR_CORONA] += random_range(3, 5); + if (this->duration[DUR_CORONA] > 250) + this->duration[DUR_CORONA] = 250; } } @@ -7038,7 +7038,7 @@ bool player::can_throw_large_rocks() const return (player_genus(GENPC_OGRE) || species == SP_TROLL); } -bool player::can_sleep(bool holi_only) const +bool player::can_hibernate(bool holi_only) const { // Undead, nonliving, and plants don't sleep. const mon_holy_type holi = holiness(); @@ -7059,11 +7059,11 @@ bool player::can_sleep(bool holi_only) const return (true); } -void player::put_to_sleep(int) +void player::hibernate(int) { ASSERT(!crawl_state.arena); - if (!can_sleep()) + if (!can_hibernate()) { mpr("You feel weary for a moment."); return; @@ -7079,6 +7079,23 @@ void player::put_to_sleep(int) duration[DUR_SLEEP] = 3 + random2avg(5, 2); } +void player::put_to_sleep(int power) +{ + ASSERT(!crawl_state.arena); + + if (duration[DUR_SLEEP]) + return; + + mpr("You fall asleep!"); + + stop_delay(); + flash_colour = DARKGREY; + viewwindow(false); + + // As above, do this after redraw. + duration[DUR_SLEEP] = 5 + random2avg(power / 10, 5); +} + void player::awake() { ASSERT(!crawl_state.arena); diff --git a/crawl-ref/source/player.h b/crawl-ref/source/player.h index 900d6bb52f..430307a982 100644 --- a/crawl-ref/source/player.h +++ b/crawl-ref/source/player.h @@ -473,7 +473,8 @@ public: bool petrified() const; bool asleep() const; - bool can_sleep(bool holi_only = false) const; + bool can_hibernate(bool holi_only = false) const; + void hibernate(int power = 0); void put_to_sleep(int power = 0); void awake(); void check_awaken(int disturbance); diff --git a/crawl-ref/source/religion.cc b/crawl-ref/source/religion.cc index 6a4c05fee1..76a4c5af79 100644 --- a/crawl-ref/source/religion.cc +++ b/crawl-ref/source/religion.cc @@ -52,9 +52,10 @@ #include "message.h" #include "misc.h" #include "mon-behv.h" +#include "mon-iter.h" #include "mon-util.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "mutation.h" #include "newgame.h" #include "notes.h" @@ -1120,7 +1121,11 @@ int yred_random_servants(int threshold, bool force_hostile) how_many = 2 + random2(4); mgen_data mg(mon_type, !force_hostile ? BEH_FRIENDLY : BEH_HOSTILE, - 0, 0, you.pos(), MHITYOU, 0, GOD_YREDELEMNUL); + !force_hostile ? &you : 0, 0, 0, you.pos(), MHITYOU, 0, + GOD_YREDELEMNUL); + + if (force_hostile) + mg.non_actor_summoner = "the anger of Yredelemnul"; int created = 0; if (force_hostile) @@ -1421,13 +1426,9 @@ bool _has_jelly() { ASSERT(you.religion == GOD_JIYVA); - for (int i = 0; i < MAX_MONSTERS; ++i) - { - monsters *monster = &menv[i]; - if (mons_is_god_gift(monster, GOD_JIYVA)) + for (monster_iterator mi; mi; ++mi) + if (mons_is_god_gift(*mi, GOD_JIYVA)) return (true); - } - return (false); } @@ -1579,8 +1580,8 @@ static bool _tso_blessing_holy_wpn(monsters* mon) const int wpn_brand = get_weapon_brand(wpn); - // Only brand melee weapons, and only override certain brands. - if (is_artefact(wpn) || is_range_weapon(wpn) + // Only brand weapons, and only override certain brands. + if (is_artefact(wpn) || (wpn_brand != SPWPN_NORMAL && wpn_brand != SPWPN_DRAINING && wpn_brand != SPWPN_PAIN && wpn_brand != SPWPN_VAMPIRICISM && wpn_brand != SPWPN_REAPING && wpn_brand != SPWPN_CHAOS @@ -1733,7 +1734,7 @@ static void _beogh_blessing_reinforcements() follower_type = RANDOM_ELEMENT(followers); _delayed_monster( - mgen_data(follower_type, BEH_FRIENDLY, 0, 0, + mgen_data(follower_type, BEH_FRIENDLY, &you, 0, 0, you.pos(), MHITYOU, 0, GOD_BEOGH), _beogh_reinf_callback); } @@ -2140,9 +2141,11 @@ static void _do_god_gift(bool prayed_for) int count_created = 0; for (; jelly_count > 0; --jelly_count) { - mgen_data mg(MONS_JELLY, BEH_STRICT_NEUTRAL, 0, 0, + mgen_data mg(MONS_JELLY, BEH_STRICT_NEUTRAL, 0, 0, 0, you.pos(), MHITNOT, 0, GOD_JIYVA); + mg.non_actor_summoner = "Jiyva"; + if (create_monster(mg) != -1) count_created++; @@ -4212,7 +4215,7 @@ static bool _bless_weapon(god_type god, brand_type brand, int colour) item_def& wpn = *you.weapon(); // Only bless non-artefact melee weapons. - if (is_artefact(wpn) || is_range_weapon(wpn)) + if (is_artefact(wpn) || (is_range_weapon(wpn) && brand != SPWPN_HOLY_WRATH)) return (false); std::string prompt = "Do you wish to have your weapon "; @@ -5049,8 +5052,8 @@ void god_pitch(god_type which_god) if (!_has_jelly()) { monster_type mon = MONS_JELLY; - mgen_data mg(mon, BEH_STRICT_NEUTRAL, 0, 0, you.pos(), MHITNOT, 0, - GOD_JIYVA); + mgen_data mg(mon, BEH_STRICT_NEUTRAL, &you, 0, 0, you.pos(), + MHITNOT, 0, GOD_JIYVA); _delayed_monster(mg); simple_god_message(" grants you a jelly!"); @@ -5446,10 +5449,8 @@ int get_tension(god_type god, bool count_travelling) int total = 0; bool nearby_monster = false; - for (int midx = 0; midx < MAX_MONSTERS; ++midx) + for (monster_iterator mons; mons; ++mons) { - const monsters* mons = &menv[midx]; - if (!mons->alive()) continue; @@ -5479,14 +5480,14 @@ int get_tension(god_type god, bool count_travelling) continue; } - const mon_attitude_type att = mons_attitude(mons); + const mon_attitude_type att = mons_attitude(*mons); if (att == ATT_GOOD_NEUTRAL || att == ATT_NEUTRAL) continue; - if (mons->cannot_act() || mons->asleep() || mons_is_fleeing(mons)) + if (mons->cannot_act() || mons->asleep() || mons_is_fleeing(*mons)) continue; - int exper = exper_value(mons); + int exper = exper_value(*mons); if (exper <= 0) continue; @@ -5494,7 +5495,7 @@ int get_tension(god_type god, bool count_travelling) exper *= mons->hit_points; exper /= mons->max_hit_points; - const bool gift = mons_is_god_gift(mons, god); + const bool gift = mons_is_god_gift(*mons, god); if (att == ATT_HOSTILE) { @@ -5517,7 +5518,7 @@ int get_tension(god_type god, bool count_travelling) if (att != ATT_FRIENDLY) { - if (!you.visible_to(mons)) + if (!you.visible_to(*mons)) exper /= 2; if (!mons->visible_to(&you)) exper *= 2; @@ -5719,3 +5720,29 @@ static void _place_delayed_monsters() _delayed_success.clear(); _delayed_failure.clear(); } + +std::vector<god_type> temple_god_list() +{ + std::vector<god_type> god_list; + + for (int i = 0; i < NUM_GODS; i++) + { + god_type god = (god_type) i; + + // These never appear in any temples. + switch(god) + { + case GOD_NO_GOD: + case GOD_LUGONU: + case GOD_BEOGH: + case GOD_JIYVA: + continue; + + default: + break; + } + + god_list.push_back(god); + } + return god_list; +} diff --git a/crawl-ref/source/religion.h b/crawl-ref/source/religion.h index 82b1a5f731..5ecc6ce34c 100644 --- a/crawl-ref/source/religion.h +++ b/crawl-ref/source/religion.h @@ -134,4 +134,6 @@ void religion_turn_start(); void religion_turn_end(); int get_tension(god_type god = you.religion, bool count_travelling = true); + +std::vector<god_type> temple_god_list(); #endif diff --git a/crawl-ref/source/rltiles/dc-player.txt b/crawl-ref/source/rltiles/dc-player.txt index 06fa9a62bd..98c4e62156 100644 --- a/crawl-ref/source/rltiles/dc-player.txt +++ b/crawl-ref/source/rltiles/dc-player.txt @@ -418,6 +418,7 @@ knife_of_accuracy KNIFE_OF_ACCURACY vampires_tooth VAMPIRES_TOOTH dire_lajatang DIRE_LAJATANG spriggans_knife SPRIGGANS_KNIFE +cutlass CUTLASS ## blunt wucad_mu WUCAD_MU mace_of_variability MACE_OF_VARIABILITY diff --git a/crawl-ref/source/rltiles/dc-unrand.txt b/crawl-ref/source/rltiles/dc-unrand.txt index 69d9cc4c54..356a53ad39 100644 --- a/crawl-ref/source/rltiles/dc-unrand.txt +++ b/crawl-ref/source/rltiles/dc-unrand.txt @@ -2,13 +2,6 @@ # util/art-data.pl. Do not directly edit this file, but rather change # art-data.txt. -%sdir item/amulet/artefact -urand_air UNRAND_AIR -urand_cekugob UNRAND_CEKUGOB -urand_four_winds UNRAND_FOUR_WINDS -urand_bloodlust UNRAND_BLOODLUST -urand_brooch_of_shielding UNRAND_SHIELDING - %sdir item/armour/artefact urand_ignorance UNRAND_IGNORANCE urand_augmentation UNRAND_AUGMENTATION @@ -34,12 +27,6 @@ urand_fencer UNRAND_FENCERS_GLOVES urand_starlight UNRAND_STARLIGHT urand_ratskin_cloak UNRAND_RATSKIN_CLOAK -%sdir item/ring/artefact -urand_shadows UNRAND_SHADOWS -urand_shaolin UNRAND_SHAOLIN -urand_robustness UNRAND_ROBUSTNESS -urand_mage UNRAND_MAGE - %sdir item/weapon/artefact spwpn_singing_sword UNRAND_SINGING_SWORD spwpn_wrath_of_trog UNRAND_TROG @@ -73,6 +60,8 @@ urand_piercer UNRAND_PIERCER urand_plutonium UNRAND_PLUTONIUM_SWORD urand_undeadhunter UNRAND_UNDEADHUNTER urand_crystal_spear UNRAND_CRYSTAL_SPEAR +urand_cutlass UNRAND_CAPTAINS_CUTLASS +urand_storm_bow UNRAND_STORM_BOW %rim 1 spwpn_sword_of_power UNRAND_POWER spwpn_sceptre_of_torment UNRAND_TORMENT @@ -87,3 +76,16 @@ urand_serpent_scourge UNRAND_SERPENT_SCOURGE urand_knife_of_accuracy UNRAND_ACCURACY %rim 0 +%sdir item/amulet/artefact +urand_air UNRAND_AIR +urand_cekugob UNRAND_CEKUGOB +urand_four_winds UNRAND_FOUR_WINDS +urand_bloodlust UNRAND_BLOODLUST +urand_brooch_of_shielding UNRAND_SHIELDING + +%sdir item/ring/artefact +urand_shadows UNRAND_SHADOWS +urand_shaolin UNRAND_SHAOLIN +urand_robustness UNRAND_ROBUSTNESS +urand_mage UNRAND_MAGE + diff --git a/crawl-ref/source/rltiles/item/weapon/artefact/urand_cutlass.png b/crawl-ref/source/rltiles/item/weapon/artefact/urand_cutlass.png Binary files differnew file mode 100644 index 0000000000..cbaab9e3af --- /dev/null +++ b/crawl-ref/source/rltiles/item/weapon/artefact/urand_cutlass.png diff --git a/crawl-ref/source/rltiles/item/weapon/artefact/urand_storm_bow.png b/crawl-ref/source/rltiles/item/weapon/artefact/urand_storm_bow.png Binary files differnew file mode 100644 index 0000000000..a1ee1e2e7d --- /dev/null +++ b/crawl-ref/source/rltiles/item/weapon/artefact/urand_storm_bow.png diff --git a/crawl-ref/source/rltiles/player/hand1/artefact/cutlass.png b/crawl-ref/source/rltiles/player/hand1/artefact/cutlass.png Binary files differnew file mode 100644 index 0000000000..73cb6cc1d3 --- /dev/null +++ b/crawl-ref/source/rltiles/player/hand1/artefact/cutlass.png diff --git a/crawl-ref/source/rltiles/tiledef-unrand.cc b/crawl-ref/source/rltiles/tiledef-unrand.cc index 077d23577f..558e0fa69f 100644 --- a/crawl-ref/source/rltiles/tiledef-unrand.cc +++ b/crawl-ref/source/rltiles/tiledef-unrand.cc @@ -58,6 +58,8 @@ int unrandart_to_tile(int unrand) case UNRAND_SERPENT_SCOURGE: return TILE_UNRAND_SERPENT_SCOURGE; case UNRAND_ACCURACY: return TILE_UNRAND_ACCURACY; case UNRAND_CRYSTAL_SPEAR: return TILE_UNRAND_CRYSTAL_SPEAR; + case UNRAND_CAPTAINS_CUTLASS: return TILE_UNRAND_CAPTAINS_CUTLASS; + case UNRAND_STORM_BOW: return TILE_UNRAND_STORM_BOW; case UNRAND_IGNORANCE: return TILE_UNRAND_IGNORANCE; case UNRAND_AUGMENTATION: return TILE_UNRAND_AUGMENTATION; case UNRAND_THIEF: return TILE_UNRAND_THIEF; @@ -162,6 +164,8 @@ int unrandart_to_doll_tile(int unrand) case UNRAND_SERPENT_SCOURGE: return TILEP_HAND1_SERPENT_SCOURGE; case UNRAND_ACCURACY: return TILEP_HAND1_KNIFE_OF_ACCURACY; case UNRAND_CRYSTAL_SPEAR: return TILEP_HAND1_CRYSTAL_SPEAR; + case UNRAND_CAPTAINS_CUTLASS: return TILEP_HAND1_CUTLASS; + case UNRAND_STORM_BOW: return TILEP_HAND1_BOW_BLUE; // HAND2 case UNRAND_IGNORANCE: return TILEP_HAND2_SHIELD_OF_IGNORANCE; case UNRAND_BULLSEYE: return TILEP_HAND2_BULLSEYE; diff --git a/crawl-ref/source/rng.cc b/crawl-ref/source/rng.cc index 409f0975c9..8c856e7229 100644 --- a/crawl-ref/source/rng.cc +++ b/crawl-ref/source/rng.cc @@ -28,12 +28,18 @@ void seed_rng(unsigned long* seed_key, size_t num_keys) { // MT19937 -- see mt19937ar.cc for details/licence init_by_array(seed_key, num_keys); + + // for std::random_shuffle() + srand(seed_key[0]); } void seed_rng(long seed) { // MT19937 -- see mt19937ar.cc for details/licence init_genrand(seed); + + // for std::random_shuffle() + srand(seed); } void seed_rng() diff --git a/crawl-ref/source/shout.cc b/crawl-ref/source/shout.cc index 1ecc0600f5..d9dea1473c 100644 --- a/crawl-ref/source/shout.cc +++ b/crawl-ref/source/shout.cc @@ -15,9 +15,10 @@ #include "message.h" #include "misc.h" #include "mon-behv.h" -#include "monplace.h" +#include "mon-iter.h" +#include "mon-place.h" #include "monster.h" -#include "monstuff.h" +#include "mon-stuff.h" #include "options.h" #include "player.h" #include "random.h" @@ -378,34 +379,32 @@ bool noisy(int loudness, const coord_def& where, const char *msg, int who, ret = true; } - for (int p = 0; p < MAX_MONSTERS; p++) + for (monster_iterator mi; mi; ++mi) { - monsters* monster = &menv[p]; - - if (!monster->alive()) + if (!mi->alive()) continue; // Monsters arent' affected by their own noise. We don't check - // where == monster->pos() since it might be caused by the + // where == mi->pos() since it might be caused by the // Projected Noise spell. - if (p == who) + if (mi->mindex() == who) continue; - if (distance(monster->pos(), where) <= dist - && !silenced(monster->pos())) + if (distance(mi->pos(), where) <= dist + && !silenced(mi->pos())) { // If the noise came from the character, any nearby monster // will be jumping on top of them. if (where == you.pos()) - behaviour_event( monster, ME_ALERT, MHITYOU, you.pos() ); - else if (mermaid && mons_primary_habitat(monster) == HT_WATER - && !monster->friendly()) + behaviour_event(*mi, ME_ALERT, MHITYOU, you.pos()); + else if (mermaid && mons_primary_habitat(*mi) == HT_WATER + && !mi->friendly()) { // Mermaids/sirens call (hostile) aquatic monsters. - behaviour_event( monster, ME_ALERT, MHITNOT, where ); + behaviour_event(*mi, ME_ALERT, MHITNOT, where); } else - behaviour_event( monster, ME_DISTURB, MHITNOT, where ); + behaviour_event(*mi, ME_DISTURB, MHITNOT, where); } } @@ -434,10 +433,8 @@ static const char* _player_vampire_smells_blood(int dist) return ""; } -void blood_smell( int strength, const coord_def& where ) +void blood_smell(int strength, const coord_def& where) { - monsters *monster = NULL; - const int range = strength * strength; #ifdef DEBUG_DIAGNOSTICS mprf(MSGCH_DIAGNOSTICS, @@ -454,7 +451,7 @@ void blood_smell( int strength, const coord_def& where ) { int vamp_range = vamp_strength * vamp_strength; - const int player_distance = distance( you.pos(), where ); + const int player_distance = distance(you.pos(), where); if (player_distance <= vamp_range) { @@ -474,73 +471,66 @@ void blood_smell( int strength, const coord_def& where ) } } - for (int p = 0; p < MAX_MONSTERS; p++) + circle_def c(where, range, C_CIRCLE); + for (monster_iterator mi(&c); mi; ++mi) { - monster = &menv[p]; - - if (monster->type < 0) + if (!mons_class_flag(mi->type, M_BLOOD_SCENT)) continue; - if (!mons_class_flag(monster->type, M_BLOOD_SCENT)) - continue; - - if (distance(monster->pos(), where) <= range) + // Let sleeping hounds lie. + if (mi->asleep() + && mons_species(mi->type) != MONS_VAMPIRE + && mi->type != MONS_SHARK) { - // Let sleeping hounds lie. - if (monster->asleep() - && mons_species(monster->type) != MONS_VAMPIRE - && monster->type != MONS_SHARK) + // 33% chance of sleeping on + // 33% of being disturbed (start BEH_WANDER) + // 33% of being alerted (start BEH_SEEK) + if (!one_chance_in(3)) { - // 33% chance of sleeping on - // 33% of being disturbed (start BEH_WANDER) - // 33% of being alerted (start BEH_SEEK) - if (!one_chance_in(3)) + if (coinflip()) { - if (coinflip()) - { #ifdef DEBUG_DIAGNOSTICS - mprf(MSGCH_DIAGNOSTICS, "disturbing %s (%d, %d)", - monster->name(DESC_PLAIN).c_str(), - monster->pos().x, monster->pos().y); + mprf(MSGCH_DIAGNOSTICS, "disturbing %s (%d, %d)", + mi->name(DESC_PLAIN).c_str(), + mi->pos().x, mi->pos().y); #endif - behaviour_event(monster, ME_DISTURB, MHITNOT, where); - } - continue; + behaviour_event(*mi, ME_DISTURB, MHITNOT, where); } + continue; } + } #ifdef DEBUG_DIAGNOSTICS - mprf(MSGCH_DIAGNOSTICS, "alerting %s (%d, %d)", - monster->name(DESC_PLAIN).c_str(), - monster->pos().x, monster->pos().y); + mprf(MSGCH_DIAGNOSTICS, "alerting %s (%d, %d)", + mi->name(DESC_PLAIN).c_str(), + mi->pos().x, mi->pos().y); #endif - behaviour_event( monster, ME_ALERT, MHITNOT, where ); + behaviour_event(*mi, ME_ALERT, MHITNOT, where); - if (monster->type == MONS_SHARK) + if (mi->type == MONS_SHARK) + { + // Sharks go into a battle frenzy if they smell blood. + monster_pathfind mp; + if (mp.init_pathfind(*mi, where)) { - // Sharks go into a battle frenzy if they smell blood. - monster_pathfind mp; - if (mp.init_pathfind(monster, where)) + mon_enchant ench = mi->get_ench(ENCH_BATTLE_FRENZY); + const int dist = 15 - (mi->pos() - where).rdist(); + const int dur = random_range(dist, dist*2) + * speed_to_duration(mi->speed); + + if (ench.ench != ENCH_NONE) + { + int level = ench.degree; + if (level < 4 && one_chance_in(2*level)) + ench.degree++; + ench.duration = std::max(ench.duration, dur); + mi->update_ench(ench); + } + else { - mon_enchant ench = monster->get_ench(ENCH_BATTLE_FRENZY); - const int dist = 15 - (monster->pos() - where).rdist(); - const int dur = random_range(dist, dist*2) - * speed_to_duration(monster->speed); - - if (ench.ench != ENCH_NONE) - { - int level = ench.degree; - if (level < 4 && one_chance_in(2*level)) - ench.degree++; - ench.duration = std::max(ench.duration, dur); - monster->update_ench(ench); - } - else - { - monster->add_ench(mon_enchant(ENCH_BATTLE_FRENZY, 1, - KC_OTHER, dur)); - simple_monster_message(monster, " is consumed with " - "blood-lust!"); - } + mi->add_ench(mon_enchant(ENCH_BATTLE_FRENZY, 1, + KC_OTHER, dur)); + simple_monster_message(*mi, " is consumed with " + "blood-lust!"); } } } diff --git a/crawl-ref/source/spells1.cc b/crawl-ref/source/spells1.cc index 1b2e1b14df..9ba939477d 100644 --- a/crawl-ref/source/spells1.cc +++ b/crawl-ref/source/spells1.cc @@ -33,7 +33,8 @@ #include "los.h" #include "message.h" #include "misc.h" -#include "monstuff.h" +#include "mon-iter.h" +#include "mon-stuff.h" #include "mon-util.h" #include "options.h" #include "player.h" @@ -372,14 +373,12 @@ void cast_chain_lightning(int pow, const actor *caster) target.x = -1; target.y = -1; - for (int i = 0; i < MAX_MONSTERS; i++) + for (monster_iterator mi; mi; ++mi) { - monsters *monster = &menv[i]; - - if (invalid_monster(monster)) + if (invalid_monster(*mi)) continue; - dist = grid_distance(source, monster->pos()); + dist = grid_distance(source, mi->pos()); // check for the source of this arc if (!dist) @@ -392,7 +391,7 @@ void cast_chain_lightning(int pow, const actor *caster) if (dist > min_dist) continue; - if (!_lightning_los(source, monster->pos())) + if (!_lightning_los(source, mi->pos())) continue; count++; @@ -403,14 +402,14 @@ void cast_chain_lightning(int pow, const actor *caster) if (!one_chance_in(10)) { min_dist = dist; - target = monster->pos(); + target = mi->pos(); count = 0; } } else if (target.x == -1 || one_chance_in(count)) { // either first target, or new selected target at min_dist - target = monster->pos(); + target = mi->pos(); // need to set min_dist for first target case dist = std::max(dist, min_dist); @@ -1132,30 +1131,25 @@ void abjuration(int pow) // Scale power into something comparable to summon lifetime. const int abjdur = pow * 12; - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mon(&you.get_los()); mon; ++mon) { - monsters* const monster = &menv[i]; - - if (monster->type == MONS_NO_MONSTER || !mons_near(monster)) - continue; - - if (monster->wont_attack()) + if (mon->wont_attack()) continue; int duration; - if (monster->is_summoned(&duration)) + if (mon->is_summoned(&duration)) { int sockage = std::max(fuzz_value(abjdur, 60, 30), 40); #ifdef DEBUG_DIAGNOSTICS mprf(MSGCH_DIAGNOSTICS, "%s abj: dur: %d, abj: %d", - monster->name(DESC_PLAIN).c_str(), duration, sockage); + mon->name(DESC_PLAIN).c_str(), duration, sockage); #endif bool shielded = false; // TSO and Trog's abjuration protection. - if (mons_is_god_gift(monster, GOD_SHINING_ONE)) + if (mons_is_god_gift(*mon, GOD_SHINING_ONE)) { - sockage = sockage * (30 - monster->hit_dice) / 45; + sockage = sockage * (30 - mon->hit_dice) / 45; if (sockage < duration) { simple_god_message(" protects a fellow warrior from your evil magic!", @@ -1163,7 +1157,7 @@ void abjuration(int pow) shielded = true; } } - else if (mons_is_god_gift(monster, GOD_TROG)) + else if (mons_is_god_gift(*mon, GOD_TROG)) { sockage = sockage * 8 / 15; if (sockage < duration) @@ -1174,9 +1168,9 @@ void abjuration(int pow) } } - mon_enchant abj = monster->get_ench(ENCH_ABJ); - if (!monster->lose_ench_duration(abj, sockage) && !shielded) - simple_monster_message(monster, " shudders."); + mon_enchant abj = mon->get_ench(ENCH_ABJ); + if (!mon->lose_ench_duration(abj, sockage) && !shielded) + simple_monster_message(*mon, " shudders."); } } } diff --git a/crawl-ref/source/spells2.cc b/crawl-ref/source/spells2.cc index 57293bf40d..e0378e81f4 100644 --- a/crawl-ref/source/spells2.cc +++ b/crawl-ref/source/spells2.cc @@ -33,8 +33,9 @@ #include "message.h" #include "misc.h" #include "mon-behv.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-iter.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "mon-util.h" #include "ouch.h" #include "player.h" @@ -531,31 +532,29 @@ void cast_toxic_radiance() counted_monster_list affected_monsters; // determine which monsters are hit by the radiance: {dlb} - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi(&you.get_los()); mi; ++mi) { - monsters* const monster = &menv[i]; - - if (monster->alive() && mons_near(monster) && !monster->submerged()) + if (!mi->submerged()) { // Monsters affected by corona are still invisible in that // radiation passes through them without affecting them. Therefore, // this check should not be !monster->invisible(). - if (!monster->has_ench(ENCH_INVIS)) + if (!mi->has_ench(ENCH_INVIS)) { bool affected = - poison_monster(monster, KC_YOU, 1, false, false); + poison_monster(*mi, KC_YOU, 1, false, false); - if (coinflip() && poison_monster(monster, KC_YOU, false, false)) + if (coinflip() && poison_monster(*mi, KC_YOU, false, false)) affected = true; if (affected) - _record_monster_by_name(affected_monsters, monster); + _record_monster_by_name(affected_monsters, *mi); } else if (you.can_see_invisible()) { // message player re:"miss" where appropriate {dlb} mprf("The light passes through %s.", - monster->name(DESC_NOCAP_THE).c_str()); + mi->name(DESC_NOCAP_THE).c_str()); } } } @@ -606,12 +605,8 @@ void cast_refrigeration(int pow) // First build the message. counted_monster_list affected_monsters; - for (int i = 0; i < MAX_MONSTERS; i++) - { - const monsters* const monster = &menv[i]; - if (monster->alive() && you.can_see(monster)) - _record_monster_by_name(affected_monsters, monster); - } + for (monster_iterator mi(&you); mi; ++mi) + _record_monster_by_name(affected_monsters, *mi); if (!affected_monsters.empty()) { @@ -636,25 +631,22 @@ void cast_refrigeration(int pow) beam.flavour = BEAM_COLD; beam.thrower = KILL_YOU; - for (int i = 0; i < MAX_MONSTERS; i++) + for (monster_iterator mi(&you.get_los()); mi; ++mi) { - monsters* const monster = &menv[i]; // Note that we *do* hurt monsters which you can't see // (submerged, invisible) even though you get no information // about it. - if (monster->alive() && mons_near(monster)) + + // Calculate damage and apply. + int hurt = mons_adjust_flavoured(*mi, beam, dam_dice.roll()); + mi->hurt(&you, hurt, BEAM_COLD); + + // Cold-blooded creatures can be slowed. + if (mi->alive() + && mons_class_flag(mi->type, M_COLD_BLOOD) + && coinflip()) { - // Calculate damage and apply. - int hurt = mons_adjust_flavoured(monster, beam, dam_dice.roll()); - monster->hurt(&you, hurt, BEAM_COLD); - - // Cold-blooded creatures can be slowed. - if (monster->alive() - && mons_class_flag(monster->type, M_COLD_BLOOD) - && coinflip()) - { - monster->add_ench(ENCH_SLOW); - } + mi->add_ench(ENCH_SLOW); } } } @@ -675,32 +667,26 @@ void drain_life(int pow) int hp_gain = 0; - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi(&you.get_los()); mi; ++mi) { - monsters* monster = &menv[i]; - - if (!monster->alive() - || monster->holiness() != MH_NATURAL - || monster->res_negative_energy()) + if (mi->holiness() != MH_NATURAL + || mi->res_negative_energy()) { continue; } - if (mons_near(monster)) - { - mprf("You draw life from %s.", - monster->name(DESC_NOCAP_THE).c_str()); + mprf("You draw life from %s.", + mi->name(DESC_NOCAP_THE).c_str()); - const int hurted = 3 + random2(7) + random2(pow); - behaviour_event(monster, ME_WHACK, MHITYOU, you.pos()); - if (!monster->is_summoned()) - hp_gain += hurted; + const int hurted = 3 + random2(7) + random2(pow); + behaviour_event(*mi, ME_WHACK, MHITYOU, you.pos()); + if (!mi->is_summoned()) + hp_gain += hurted; - monster->hurt(&you, hurted); + mi->hurt(&you, hurted); - if (monster->alive()) - print_wounds(monster); - } + if (mi->alive()) + print_wounds(*mi); } hp_gain /= 2; @@ -898,7 +884,7 @@ bool summon_animals(int pow) if (create_monster( mgen_data(mon, - friendly ? BEH_FRIENDLY : BEH_HOSTILE, + friendly ? BEH_FRIENDLY : BEH_HOSTILE, &you, 4, 0, you.pos(), MHITYOU)) != -1) { success = true; @@ -917,7 +903,7 @@ bool cast_summon_butterflies(int pow, god_type god) for (int i = 0; i < how_many; ++i) { if (create_monster( - mgen_data(MONS_BUTTERFLY, BEH_FRIENDLY, + mgen_data(MONS_BUTTERFLY, BEH_FRIENDLY, &you, 3, SPELL_SUMMON_BUTTERFLIES, you.pos(), MHITYOU, 0, god)) != -1) @@ -952,7 +938,7 @@ bool cast_summon_small_mammals(int pow, god_type god) } if (create_monster( - mgen_data(mon, BEH_FRIENDLY, + mgen_data(mon, BEH_FRIENDLY, &you, 3, SPELL_SUMMON_SMALL_MAMMALS, you.pos(), MHITYOU, 0, god)) != -1) @@ -1010,7 +996,7 @@ bool cast_sticks_to_snakes(int pow, god_type god) mon = MONS_SMALL_SNAKE; if (create_monster( - mgen_data(mon, beha, + mgen_data(mon, beha, &you, dur, SPELL_STICKS_TO_SNAKES, you.pos(), MHITYOU, 0, god)) != -1) @@ -1057,7 +1043,7 @@ bool cast_sticks_to_snakes(int pow, god_type god) mon = MONS_GREY_SNAKE; if (create_monster( - mgen_data(mon, beha, + mgen_data(mon, beha, &you, dur, SPELL_STICKS_TO_SNAKES, you.pos(), MHITYOU, 0, god)) != -1) @@ -1096,7 +1082,7 @@ bool cast_summon_scorpions(int pow, god_type god) if (create_monster( mgen_data(MONS_SCORPION, - friendly ? BEH_FRIENDLY : BEH_HOSTILE, + friendly ? BEH_FRIENDLY : BEH_HOSTILE, &you, 3, SPELL_SUMMON_SCORPIONS, you.pos(), MHITYOU, 0, god)) != -1) @@ -1137,7 +1123,7 @@ bool cast_summon_swarm(int pow, god_type god, if (create_monster( mgen_data(mon, - friendly ? BEH_FRIENDLY : BEH_HOSTILE, + friendly ? BEH_FRIENDLY : BEH_HOSTILE, &you, dur, !permanent ? SPELL_SUMMON_SWARM : 0, you.pos(), MHITYOU, @@ -1194,7 +1180,7 @@ bool cast_call_canine_familiar(int pow, god_type god) const int dur = std::min(2 + (random2(pow) / 4), 6); if (create_monster( - mgen_data(mon, BEH_FRIENDLY, + mgen_data(mon, BEH_FRIENDLY, &you, dur, SPELL_CALL_CANINE_FAMILIAR, you.pos(), MHITYOU, @@ -1331,7 +1317,7 @@ bool cast_summon_elemental(int pow, god_type god, if (create_monster( mgen_data(mon, - friendly ? BEH_FRIENDLY : BEH_HOSTILE, + friendly ? BEH_FRIENDLY : BEH_HOSTILE, &you, dur, SPELL_SUMMON_ELEMENTAL, targ, MHITYOU, @@ -1356,7 +1342,7 @@ bool cast_summon_ice_beast(int pow, god_type god) const int dur = std::min(2 + (random2(pow) / 4), 6); if (create_monster( - mgen_data(mon, BEH_FRIENDLY, + mgen_data(mon, BEH_FRIENDLY, &you, dur, SPELL_SUMMON_ICE_BEAST, you.pos(), MHITYOU, 0, god)) != -1) @@ -1381,7 +1367,7 @@ bool cast_summon_ugly_thing(int pow, god_type god) if (create_monster( mgen_data(mon, - friendly ? BEH_FRIENDLY : BEH_HOSTILE, + friendly ? BEH_FRIENDLY : BEH_HOSTILE, &you, dur, SPELL_SUMMON_UGLY_THING, you.pos(), MHITYOU, @@ -1411,7 +1397,7 @@ bool cast_summon_dragon(int pow, god_type god) if (create_monster( mgen_data(MONS_DRAGON, - friendly ? BEH_FRIENDLY : BEH_HOSTILE, + friendly ? BEH_FRIENDLY : BEH_HOSTILE, &you, 3, SPELL_SUMMON_DRAGON, you.pos(), MHITYOU, @@ -1476,11 +1462,15 @@ bool summon_berserker(int pow, god_type god, int spell, mon = (coinflip()) ? MONS_HILL_GIANT : MONS_STONE_GIANT; } + mgen_data mg(mon, !force_hostile ? BEH_FRIENDLY : BEH_HOSTILE, + !force_hostile ? &you : 0, dur, spell, you.pos(), + MHITYOU, 0, god); + + if (force_hostile) + mg.non_actor_summoner = "the rage of " + god_name(god, false); + int monster = - create_monster( - mgen_data(mon, - !force_hostile ? BEH_FRIENDLY : BEH_HOSTILE, - dur, spell, you.pos(), MHITYOU, 0, god)); + create_monster(mg); if (monster == -1) return (false); @@ -1510,14 +1500,18 @@ static bool _summon_holy_being_wrapper(int pow, god_type god, int spell, { UNUSED(pow); - const int monster = - create_monster( - mgen_data(mon, - friendly ? BEH_FRIENDLY : BEH_HOSTILE, - dur, spell, - you.pos(), - MHITYOU, - MG_FORCE_BEH, god)); + mgen_data mg(mon, + friendly ? BEH_FRIENDLY : BEH_HOSTILE, + friendly ? &you : 0, + dur, spell, + you.pos(), + MHITYOU, + MG_FORCE_BEH, god); + + if (!friendly) + mg.non_actor_summoner = god_name(god, false); + + const int monster = create_monster(mg); if (monster == -1) return (false); @@ -1598,14 +1592,18 @@ bool cast_tukimas_dance(int pow, god_type god, bool force_hostile) // Cursed weapons become hostile. const bool friendly = (!force_hostile && !item_cursed(you.inv[wpn])); - monster = - create_monster( - mgen_data(MONS_DANCING_WEAPON, - friendly ? BEH_FRIENDLY : BEH_HOSTILE, - dur, SPELL_TUKIMAS_DANCE, - you.pos(), - MHITYOU, - 0, god)); + mgen_data mg(MONS_DANCING_WEAPON, + friendly ? BEH_FRIENDLY : BEH_HOSTILE, + force_hostile ? 0 : &you, + dur, SPELL_TUKIMAS_DANCE, + you.pos(), + MHITYOU, + 0, god); + + if (force_hostile) + mg.non_actor_summoner = god_name(god, false); + + monster = create_monster(mg); if (monster == -1) { @@ -1694,7 +1692,7 @@ bool cast_conjure_ball_lightning(int pow, god_type god) int monster = mons_place( - mgen_data(MONS_BALL_LIGHTNING, BEH_FRIENDLY, + mgen_data(MONS_BALL_LIGHTNING, BEH_FRIENDLY, &you, 0, SPELL_CONJURE_BALL_LIGHTNING, target, MHITNOT, 0, god)); diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc index f235c04520..17b33ead54 100644 --- a/crawl-ref/source/spells3.cc +++ b/crawl-ref/source/spells3.cc @@ -35,8 +35,9 @@ #include "message.h" #include "misc.h" #include "mon-behv.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-iter.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "mon-util.h" #include "player.h" #include "quiver.h" @@ -426,7 +427,7 @@ bool cast_call_imp(int pow, god_type god) const int monster = create_monster( - mgen_data(mon, BEH_FRIENDLY, dur, SPELL_CALL_IMP, + mgen_data(mon, BEH_FRIENDLY, &you, dur, SPELL_CALL_IMP, you.pos(), MHITYOU, MG_FORCE_BEH, god)); if (monster != -1) @@ -455,7 +456,7 @@ static bool _summon_demon_wrapper(int pow, god_type god, int spell, create_monster( mgen_data(mon, friendly ? BEH_FRIENDLY : - charmed ? BEH_CHARMED : BEH_HOSTILE, + charmed ? BEH_CHARMED : BEH_HOSTILE, &you, dur, spell, you.pos(), MHITYOU, MG_FORCE_BEH, god)); if (monster != -1) @@ -565,7 +566,7 @@ bool cast_shadow_creatures(god_type god) const int monster = create_monster( - mgen_data(RANDOM_MONSTER, BEH_FRIENDLY, + mgen_data(RANDOM_MONSTER, BEH_FRIENDLY, &you, 2, SPELL_SHADOW_CREATURES, you.pos(), MHITYOU, MG_FORCE_BEH, god), false); @@ -612,7 +613,7 @@ bool cast_summon_horrible_things(int pow, god_type god) { const int monster = create_monster( - mgen_data(MONS_TENTACLED_MONSTROSITY, BEH_FRIENDLY, + mgen_data(MONS_TENTACLED_MONSTROSITY, BEH_FRIENDLY, &you, 6, SPELL_SUMMON_HORRIBLE_THINGS, you.pos(), MHITYOU, MG_FORCE_BEH, god)); @@ -628,7 +629,7 @@ bool cast_summon_horrible_things(int pow, god_type god) { const int monster = create_monster( - mgen_data(MONS_ABOMINATION_LARGE, BEH_FRIENDLY, + mgen_data(MONS_ABOMINATION_LARGE, BEH_FRIENDLY, &you, 6, SPELL_SUMMON_HORRIBLE_THINGS, you.pos(), MHITYOU, MG_FORCE_BEH, god)); @@ -925,8 +926,9 @@ void equip_undead(const coord_def &a, int corps, int monster, int monnum) } static bool _raise_remains(const coord_def &pos, int corps, beh_type beha, - unsigned short hitting, god_type god, bool actual, - bool force_beh, int* mon_index) + unsigned short hitting, actor *as, std::string nas, + god_type god, bool actual, bool force_beh, + int* mon_index) { if (mon_index != NULL) *mon_index = -1; @@ -969,11 +971,12 @@ static bool _raise_remains(const coord_def &pos, int corps, beh_type beha, : MONS_SKELETON_LARGE; } - int monster = create_monster( - mgen_data(mon, beha, - 0, 0, pos, hitting, - MG_FORCE_BEH, god, - zombie_type, number)); + mgen_data mg(mon, beha, as, 0, 0, pos, hitting, MG_FORCE_BEH, god, + zombie_type, number); + + mg.non_actor_summoner = nas; + + int monster = create_monster(mg); if (mon_index != NULL) *mon_index = monster; @@ -984,7 +987,13 @@ static bool _raise_remains(const coord_def &pos, int corps, beh_type beha, const int monnum = item.orig_monnum - 1; if (is_named_corpse(item)) - name_zombie(&menv[monster], monnum, get_corpse_name(item)); + { + unsigned long name_type; + std::string name = get_corpse_name(item, &name_type); + + if (name_type == 0 || name_type == MF_NAME_REPLACE) + name_zombie(&menv[monster], monnum, name); + } equip_undead(pos, corps, monster, monnum); @@ -1000,6 +1009,7 @@ static bool _raise_remains(const coord_def &pos, int corps, beh_type beha, // you are butchering being animated. int animate_remains(const coord_def &a, corpse_type class_allowed, beh_type beha, unsigned short hitting, + actor *as, std::string nas, god_type god, bool actual, bool quiet, bool force_beh, int* mon_index) @@ -1024,8 +1034,8 @@ int animate_remains(const coord_def &a, corpse_type class_allowed, const bool was_butchering = is_being_butchered(*si); - success = _raise_remains(a, si.link(), beha, hitting, god, actual, - force_beh, mon_index); + success = _raise_remains(a, si.link(), beha, hitting, as, nas, + god, actual, force_beh, mon_index); if (actual && success) { @@ -1058,7 +1068,7 @@ int animate_remains(const coord_def &a, corpse_type class_allowed, } int animate_dead(actor *caster, int pow, beh_type beha, unsigned short hitting, - god_type god, bool actual) + actor *as, std::string nas, god_type god, bool actual) { UNUSED(pow); @@ -1073,7 +1083,7 @@ int animate_dead(actor *caster, int pow, beh_type beha, unsigned short hitting, { // This will produce a message if the corpse you are butchering // is raised. - if (animate_remains(*ri, CORPSE_BODY, beha, hitting, god, + if (animate_remains(*ri, CORPSE_BODY, beha, hitting, as, nas, god, actual, true) > 0) { number_raised++; @@ -1126,7 +1136,7 @@ bool cast_simulacrum(int pow, god_type god) { const int monster = create_monster( - mgen_data(sim_type, BEH_FRIENDLY, + mgen_data(sim_type, BEH_FRIENDLY, &you, 6, SPELL_SIMULACRUM, you.pos(), MHITYOU, MG_FORCE_BEH, god, type)); @@ -1217,7 +1227,7 @@ bool cast_twisted_resurrection(int pow, god_type god) const int monster = create_monster( - mgen_data(mon, BEH_FRIENDLY, + mgen_data(mon, BEH_FRIENDLY, &you, 0, 0, you.pos(), MHITYOU, MG_FORCE_BEH, god, @@ -1299,7 +1309,7 @@ bool cast_haunt(int pow, const coord_def& where, god_type god) const int monster = create_monster( mgen_data(mon, - BEH_FRIENDLY, + BEH_FRIENDLY, &you, 5, SPELL_HAUNT, where, mi, MG_FORCE_BEH, god)); @@ -1761,12 +1771,8 @@ bool remove_sanctuary(bool did_attack) // Now that the sanctuary is gone, monsters aren't afraid of it // anymore. - for (int i = 0; i < MAX_MONSTERS; ++i) - { - monsters *mon = &menv[i]; - if (mon->alive()) - mons_stop_fleeing_from_sanctuary(mon); - } + for (monster_iterator mi; mi; ++mi) + mons_stop_fleeing_from_sanctuary(*mi); if (is_resting()) stop_running(); diff --git a/crawl-ref/source/spells3.h b/crawl-ref/source/spells3.h index 0aac012c80..7656213bcb 100644 --- a/crawl-ref/source/spells3.h +++ b/crawl-ref/source/spells3.h @@ -51,11 +51,13 @@ 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, + actor *as = NULL, std::string nas = "", god_type god = GOD_NO_GOD, bool actual = true, bool quiet = false, bool force_beh = false, int* mon_index = NULL); int animate_dead(actor *caster, int pow, beh_type beha, unsigned short hitting, + actor *as = NULL, std::string nas = "", god_type god = GOD_NO_GOD, bool actual = true); bool cast_simulacrum(int pow, god_type god = GOD_NO_GOD); diff --git a/crawl-ref/source/spells4.cc b/crawl-ref/source/spells4.cc index 027359417e..86d344f25d 100644 --- a/crawl-ref/source/spells4.cc +++ b/crawl-ref/source/spells4.cc @@ -33,8 +33,8 @@ #include "message.h" #include "misc.h" #include "mon-behv.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "mon-util.h" #include "ouch.h" #include "player.h" @@ -397,7 +397,7 @@ static int _sleep_monsters(coord_def where, int pow, int, actor *) if (!monster) return (0); - if (!monster->can_sleep(true)) + if (!monster->can_hibernate(true)) return (0); if (monster->check_res_magic(pow)) @@ -410,7 +410,7 @@ static int _sleep_monsters(coord_def where, int pow, int, actor *) if (monster->has_ench(ENCH_SLEEP_WARY) && !one_chance_in(3)) return (0); - monster->put_to_sleep(); + monster->hibernate(); monster->expose_to_element(BEAM_COLD, 2); return (1); } @@ -1036,22 +1036,22 @@ bool backlight_monsters(coord_def where, int pow, int garbage) if (mons_class_flag(monster->type, M_GLOWS)) return (false); - mon_enchant bklt = monster->get_ench(ENCH_BACKLIGHT); + mon_enchant bklt = monster->get_ench(ENCH_CORONA); const int lvl = bklt.degree; // This enchantment overrides invisibility (neat). if (monster->has_ench(ENCH_INVIS)) { - if (!monster->has_ench(ENCH_BACKLIGHT)) + if (!monster->has_ench(ENCH_CORONA)) { monster->add_ench( - mon_enchant(ENCH_BACKLIGHT, 1, KC_OTHER, random_range(30, 50))); + mon_enchant(ENCH_CORONA, 1, KC_OTHER, random_range(30, 50))); simple_monster_message(monster, " is lined in light."); } return (true); } - monster->add_ench(mon_enchant(ENCH_BACKLIGHT, 1)); + monster->add_ench(mon_enchant(ENCH_CORONA, 1)); if (lvl == 0) simple_monster_message(monster, " is outlined in light."); diff --git a/crawl-ref/source/spl-book.cc b/crawl-ref/source/spl-book.cc index 8845464757..989e5db899 100644 --- a/crawl-ref/source/spl-book.cc +++ b/crawl-ref/source/spl-book.cc @@ -156,12 +156,12 @@ static spell_type spellbook_template_array[][SPELLBOOK_SIZE] = // 9 - Book of Ice {SPELL_FREEZING_AURA, - SPELL_SLEEP, + SPELL_HIBERNATION, SPELL_CONDENSATION_SHIELD, SPELL_OZOCUBUS_REFRIGERATION, SPELL_BOLT_OF_COLD, SPELL_SIMULACRUM, - SPELL_MASS_SLEEP, + SPELL_ENGLACIATION, SPELL_NO_SPELL, }, @@ -320,9 +320,9 @@ static spell_type spellbook_template_array[][SPELLBOOK_SIZE] = }, // 24 - Book of Charms - {SPELL_BACKLIGHT, + {SPELL_CORONA, SPELL_REPEL_MISSILES, - SPELL_SLEEP, + SPELL_HIBERNATION, SPELL_CONFUSE, SPELL_ENSLAVEMENT, SPELL_SILENCE, @@ -402,7 +402,7 @@ static spell_type spellbook_template_array[][SPELLBOOK_SIZE] = SPELL_TAME_BEASTS, SPELL_MASS_CONFUSION, SPELL_CONTROL_UNDEAD, - SPELL_MASS_SLEEP, + SPELL_ENGLACIATION, SPELL_NO_SPELL, SPELL_NO_SPELL, }, diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc index 9a48b2ad31..8d96fb7f82 100644 --- a/crawl-ref/source/spl-cast.cc +++ b/crawl-ref/source/spl-cast.cc @@ -34,7 +34,8 @@ #include "misc.h" #include "message.h" #include "mon-cast.h" -#include "monstuff.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "mutation.h" #include "ouch.h" #include "player.h" @@ -1039,13 +1040,8 @@ static void _try_monster_cast(spell_type spell, int powc, return; } - int midx; - - for (midx = 0; midx < MAX_MONSTERS; midx++) - if (menv[midx].type == MONS_NO_MONSTER) - break; - - if (midx == MAX_MONSTERS) + monsters* mon = get_free_monster(); + if (!mon) { mpr("Couldn't try casting monster spell because there is " "no empty monster slot."); @@ -1054,8 +1050,6 @@ static void _try_monster_cast(spell_type spell, int powc, mpr("Invalid player spell, attempting to cast it as monster spell."); - monsters* mon = &menv[midx]; - mon->mname = "Dummy Monster"; mon->type = MONS_HUMAN; mon->behaviour = BEH_SEEK; @@ -1079,7 +1073,7 @@ static void _try_monster_cast(spell_type spell, int powc, else mon->foe = mgrd(spd.target); - mgrd(you.pos()) = midx; + mgrd(you.pos()) = mon->mindex(); mons_cast(mon, beam, spell); @@ -1711,7 +1705,7 @@ spret_type your_spells(spell_type spell, int powc, bool allow_fail) mpr("You attempt to give life to the dead..."); if (animate_remains(you.pos(), CORPSE_SKELETON, BEH_FRIENDLY, - MHITYOU, god) < 0) + MHITYOU, &you, "", god) < 0) { mpr("There is no skeleton here to animate!"); } @@ -1720,7 +1714,7 @@ spret_type your_spells(spell_type spell, int powc, bool allow_fail) case SPELL_ANIMATE_DEAD: mpr("You call on the dead to walk for you..."); - animate_dead(&you, powc + 1, BEH_FRIENDLY, MHITYOU, god); + animate_dead(&you, powc + 1, BEH_FRIENDLY, MHITYOU, &you, "", god); break; case SPELL_SIMULACRUM: @@ -1744,8 +1738,8 @@ spret_type your_spells(spell_type spell, int powc, bool allow_fail) cast_confusing_touch(powc); break; - case SPELL_BACKLIGHT: - if (!zapping(ZAP_BACKLIGHT, powc + 10, beam, true)) + case SPELL_CORONA: + if (!zapping(ZAP_CORONA, powc + 10, beam, true)) return (SPRET_ABORT); break; @@ -1772,7 +1766,7 @@ spret_type your_spells(spell_type spell, int powc, bool allow_fail) cast_tame_beasts(powc); break; - case SPELL_SLEEP: + case SPELL_HIBERNATION: { const int sleep_power = stepdown_value(powc * 9 / 10, 5, 35, 45, 50); @@ -1780,11 +1774,16 @@ spret_type your_spells(spell_type spell, int powc, bool allow_fail) mprf(MSGCH_DIAGNOSTICS, "Sleep power stepdown: %d -> %d", powc, sleep_power); #endif - if (!zapping(ZAP_SLEEP, sleep_power, beam, true)) + if (!zapping(ZAP_HIBERNATION, sleep_power, beam, true)) return (SPRET_ABORT); break; } + case SPELL_SLEEP: + if (!zapping(ZAP_SLEEP, powc, beam, true)) + return (SPRET_ABORT); + break; + case SPELL_PARALYSE: if (!zapping(ZAP_PARALYSIS, powc, beam, true)) return (SPRET_ABORT); @@ -1813,7 +1812,7 @@ spret_type your_spells(spell_type spell, int powc, bool allow_fail) mass_enchantment(ENCH_CONFUSION, powc, MHITYOU); break; - case SPELL_MASS_SLEEP: + case SPELL_ENGLACIATION: cast_mass_sleep(powc); break; diff --git a/crawl-ref/source/spl-data.h b/crawl-ref/source/spl-data.h index 724d627fd9..e8d212591e 100644 --- a/crawl-ref/source/spl-data.h +++ b/crawl-ref/source/spl-data.h @@ -1664,7 +1664,7 @@ }, { - SPELL_SLEEP, "Ensorcelled Hibernation", + SPELL_HIBERNATION, "Ensorcelled Hibernation", SPTYP_ENCHANTMENT | SPTYP_ICE, SPFLAG_DIR_OR_TARGET | SPFLAG_NOT_SELF, 2, @@ -1677,7 +1677,7 @@ }, { - SPELL_MASS_SLEEP, "Metabolic Englaciation", + SPELL_ENGLACIATION, "Metabolic Englaciation", SPTYP_ENCHANTMENT | SPTYP_ICE, SPFLAG_AREA, 7, @@ -1807,7 +1807,7 @@ }, { - SPELL_BACKLIGHT, "Corona", + SPELL_CORONA, "Corona", SPTYP_ENCHANTMENT, SPFLAG_DIR_OR_TARGET | SPFLAG_NOT_SELF, 1, @@ -2434,6 +2434,19 @@ }, { + SPELL_SLEEP, "Sleep", + SPTYP_ENCHANTMENT, + SPFLAG_DIR_OR_TARGET | SPFLAG_NOT_SELF, + 5, + 200, + LOS_RADIUS, LOS_RADIUS, + 0, + NULL, + true, + false +}, + +{ SPELL_NO_SPELL, "nonexistent spell", 0, SPFLAG_TESTING, diff --git a/crawl-ref/source/spl-mis.cc b/crawl-ref/source/spl-mis.cc index bbab3c230a..511426ec09 100644 --- a/crawl-ref/source/spl-mis.cc +++ b/crawl-ref/source/spl-mis.cc @@ -18,8 +18,8 @@ #include "it_use2.h" #include "kills.h" #include "misc.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "mon-util.h" #include "mutation.h" #include "player.h" @@ -630,7 +630,7 @@ void MiscastEffect::_potion_effect(int pot_eff, int pot_pow) // There's no levitation enchantment for monsters, and, // anyway, it's not nearly as inconvenient for monsters as // for the player, so backlight them instead. - mon_target->add_ench(mon_enchant(ENCH_BACKLIGHT, pot_pow, kc)); + mon_target->add_ench(mon_enchant(ENCH_CORONA, pot_pow, kc)); break; case POT_BERSERK_RAGE: if (target->can_go_berserk()) @@ -707,7 +707,9 @@ bool MiscastEffect::_create_monster(monster_type what, int abj_deg, (crawl_state.is_god_acting()) ? crawl_state.which_god_acting() : GOD_NO_GOD; - mgen_data data = mgen_data::hostile_at(what, alert, + if (cause.empty()) + cause = get_default_cause(); + mgen_data data = mgen_data::hostile_at(what, cause, alert, abj_deg, 0, target->pos(), 0, god); // hostile_at() assumes the monster is hostile to the player, diff --git a/crawl-ref/source/stash.cc b/crawl-ref/source/stash.cc index 283d022339..7b861de749 100644 --- a/crawl-ref/source/stash.cc +++ b/crawl-ref/source/stash.cc @@ -26,7 +26,7 @@ #include "message.h" #include "misc.h" #include "mon-util.h" -#include "monstuff.h" +#include "mon-stuff.h" #include "notes.h" #include "options.h" #include "place.h" diff --git a/crawl-ref/source/store.cc b/crawl-ref/source/store.cc index 25c50ed763..f52a97d510 100644 --- a/crawl-ref/source/store.cc +++ b/crawl-ref/source/store.cc @@ -9,7 +9,9 @@ #include "store.h" +#include "dlua.h" #include "externs.h" +#include "monster.h" #include "tags.h" #include "travel.h" @@ -105,6 +107,22 @@ CrawlStoreValue::CrawlStoreValue(const CrawlStoreValue &other) break; } + case SV_MONST: + { + monsters* mon; + mon = new monsters(*static_cast<monsters*>(other.val.ptr)); + val.ptr = static_cast<void*>(mon); + break; + } + + case SV_LUA: + { + dlua_chunk* chunk; + chunk = new dlua_chunk(*static_cast<dlua_chunk*>(other.val.ptr)); + val.ptr = static_cast<void*>(chunk); + break; + } + case NUM_STORE_VAL_TYPES: ASSERT(false); } @@ -208,6 +226,20 @@ CrawlStoreValue::CrawlStoreValue(const level_pos &_val) get_level_pos() = _val; } +CrawlStoreValue::CrawlStoreValue(const monsters &_val) + : type(SV_MONST), flags(SFLAG_UNSET) +{ + val.ptr = NULL; + get_monster() = _val; +} + +CrawlStoreValue::CrawlStoreValue(const dlua_chunk &_val) + : type(SV_LUA), flags(SFLAG_UNSET) +{ + val.ptr = NULL; + get_lua() = _val; +} + CrawlStoreValue::~CrawlStoreValue() { unset(true); @@ -301,6 +333,22 @@ void CrawlStoreValue::unset(bool force) break; } + case SV_MONST: + { + monsters* mon = static_cast<monsters*>(val.ptr); + delete mon; + val.ptr = NULL; + break; + } + + case SV_LUA: + { + dlua_chunk* chunk = static_cast<dlua_chunk*>(val.ptr); + delete chunk; + val.ptr = NULL; + break; + } + case SV_NONE: DEBUGSTR("CrawlStoreValue::unset: unsetting nothing"); break; @@ -413,7 +461,8 @@ store_val_type CrawlStoreValue::get_type() const // Read/write from/to savefile void CrawlStoreValue::write(writer &th) const { - ASSERT(!(flags & SFLAG_UNSET)); + ASSERT(type != SV_NONE || (flags & SFLAG_UNSET)); + ASSERT(!(flags & SFLAG_UNSET) || (type == SV_NONE)); marshallByte(th, (char) type); marshallByte(th, (char) flags); @@ -489,8 +538,22 @@ void CrawlStoreValue::write(writer &th) const break; } + case SV_MONST: + { + monsters* mon = static_cast<monsters*>(val.ptr); + marshallMonster(th, *mon); + break; + } + + case SV_LUA: + { + dlua_chunk* chunk = static_cast<dlua_chunk*>(val.ptr); + chunk->write(th); + break; + } + case SV_NONE: - ASSERT(false); + break; case NUM_STORE_VAL_TYPES: ASSERT(false); @@ -502,7 +565,8 @@ void CrawlStoreValue::read(reader &th) type = static_cast<store_val_type>(unmarshallByte(th)); flags = (store_flags) unmarshallByte(th); - ASSERT(!(flags & SFLAG_UNSET)); + ASSERT(type != SV_NONE || (flags & SFLAG_UNSET)); + ASSERT(!(flags & SFLAG_UNSET) || (type == SV_NONE)); switch (type) { @@ -587,8 +651,26 @@ void CrawlStoreValue::read(reader &th) break; } + case SV_MONST: + { + monsters mon; + unmarshallMonster(th, mon); + val.ptr = (void*) new monsters(mon); + + break; + } + + case SV_LUA: + { + dlua_chunk chunk; + chunk.read(th); + val.ptr = (void*) new dlua_chunk(chunk); + + break; + } + case SV_NONE: - ASSERT(false); + break; case NUM_STORE_VAL_TYPES: ASSERT(false); @@ -757,6 +839,15 @@ level_pos &CrawlStoreValue::get_level_pos() GET_VAL_PTR(SV_LEV_POS, level_pos*, new level_pos()); } +monsters &CrawlStoreValue::get_monster() +{ + GET_VAL_PTR(SV_MONST, monsters*, new monsters()); +} + +dlua_chunk &CrawlStoreValue::get_lua() +{ + GET_VAL_PTR(SV_LUA, dlua_chunk*, new dlua_chunk()); +} CrawlStoreValue &CrawlStoreValue::operator [] (const std::string &key) { @@ -861,18 +952,20 @@ const CrawlStoreValue &CrawlStoreValue::operator ///////////////////// // Typecast operators #ifdef TARGET_COMPILER_VC -CrawlStoreValue::operator bool&() { return get_bool(); } -CrawlStoreValue::operator char&() { return get_byte(); } -CrawlStoreValue::operator short&() { return get_short(); } -CrawlStoreValue::operator float&() { return get_float(); } -CrawlStoreValue::operator long&() { return get_long(); } -CrawlStoreValue::operator std::string&() { return get_string(); } -CrawlStoreValue::operator coord_def&() { return get_coord(); } -CrawlStoreValue::operator CrawlHashTable&() { return get_table(); } -CrawlStoreValue::operator CrawlVector&() { return get_vector(); } -CrawlStoreValue::operator item_def&() { return get_item(); } -CrawlStoreValue::operator level_id&() { return get_level_id(); } -CrawlStoreValue::operator level_pos&() { return get_level_pos(); } +CrawlStoreValue::operator bool&() { return get_bool(); } +CrawlStoreValue::operator char&() { return get_byte(); } +CrawlStoreValue::operator short&() { return get_short(); } +CrawlStoreValue::operator float&() { return get_float(); } +CrawlStoreValue::operator long&() { return get_long(); } +CrawlStoreValue::operator std::string&() { return get_string(); } +CrawlStoreValue::operator coord_def&() { return get_coord(); } +CrawlStoreValue::operator CrawlHashTable&() { return get_table(); } +CrawlStoreValue::operator CrawlVector&() { return get_vector(); } +CrawlStoreValue::operator item_def&() { return get_item(); } +CrawlStoreValue::operator level_id&() { return get_level_id(); } +CrawlStoreValue::operator level_pos&() { return get_level_pos(); } +CrawlStoreValue::operator monster&() { return get_monster(); } +CrawlStoreValue::operator dlua_chunk&() { return get_dlua_chunk(); } #else &CrawlStoreValue::operator bool() { @@ -933,6 +1026,16 @@ CrawlStoreValue::operator level_pos&() { return get_level_pos(); } { return get_level_pos(); } + +&CrawlStoreValue::operator monsters() +{ + return get_monster(); +} + +&CrawlStoreValue::operator dlua_chunk() +{ + return get_lua(); +} #endif /////////////////////////// @@ -1076,6 +1179,18 @@ CrawlStoreValue &CrawlStoreValue::operator = (const level_pos &_val) return (*this); } +CrawlStoreValue &CrawlStoreValue::operator = (const monsters &_val) +{ + get_monster() = _val; + return (*this); +} + +CrawlStoreValue &CrawlStoreValue::operator = (const dlua_chunk &_val) +{ + get_lua() = _val; + return (*this); +} + /////////////////////////////////////////////////// // Non-assignment operators which affect the lvalue #define INT_OPERATOR_UNARY(op) \ @@ -1493,9 +1608,7 @@ void CrawlVector::write(writer &th) const for (vec_size i = 0; i < size(); i++) { CrawlStoreValue val = vector[i]; - ASSERT(val.type != SV_NONE); - ASSERT(!(val.flags & SFLAG_UNSET)); - val.write(th); + val.write(th); } assert_validity(); diff --git a/crawl-ref/source/store.h b/crawl-ref/source/store.h index e23e6056be..79b9454c97 100644 --- a/crawl-ref/source/store.h +++ b/crawl-ref/source/store.h @@ -20,7 +20,9 @@ class CrawlVector; struct item_def; struct coord_def; struct level_pos; -class level_id; +class level_id; +class dlua_chunk; +class monsters; typedef unsigned char hash_size; typedef unsigned char vec_size; @@ -46,6 +48,8 @@ enum store_val_type SV_VEC, SV_LEV_ID, SV_LEV_POS, + SV_MONST, + SV_LUA, NUM_STORE_VAL_TYPES }; @@ -94,8 +98,9 @@ public: CrawlStoreValue(const CrawlVector &val); CrawlStoreValue(const level_id &val); CrawlStoreValue(const level_pos &val); + CrawlStoreValue(const monsters &val); + CrawlStoreValue(const dlua_chunk &val); - // Only needed for doing some assertion checking. CrawlStoreValue &operator = (const CrawlStoreValue &other); protected: @@ -128,6 +133,8 @@ public: item_def &get_item(); level_id &get_level_id(); level_pos &get_level_pos(); + monsters &get_monster(); + dlua_chunk &get_lua(); bool get_bool() const; char get_byte() const; @@ -142,6 +149,8 @@ public: const CrawlHashTable& get_table() const; const CrawlVector& get_vector() const; const item_def& get_item() const; + const monsters& get_monster() const; + const dlua_chunk& get_lua() const; #if 0 // These don't actually exist @@ -188,6 +197,8 @@ public: operator item_def&(); operator level_id&(); operator level_pos&(); + operator monsters&(); + operator dlua_chunk&(); #else &operator bool(); &operator char(); @@ -201,6 +212,8 @@ public: &operator item_def(); &operator level_id(); &operator level_pos(); + &operator monsters(); + &operator dlua_chunk(); #endif operator bool() const; @@ -227,6 +240,8 @@ public: CrawlStoreValue &operator = (const item_def &val); CrawlStoreValue &operator = (const level_id &val); CrawlStoreValue &operator = (const level_pos &val); + CrawlStoreValue &operator = (const monsters &val); + CrawlStoreValue &operator = (const dlua_chunk &val); // Misc operators std::string &operator += (const std::string &val); diff --git a/crawl-ref/source/stuff.cc b/crawl-ref/source/stuff.cc index d7f211bdea..92e670a644 100644 --- a/crawl-ref/source/stuff.cc +++ b/crawl-ref/source/stuff.cc @@ -14,7 +14,7 @@ #include "los.h" #include "message.h" #include "misc.h" -#include "monplace.h" +#include "mon-place.h" #include "state.h" #include "stuff.h" #include "view.h" @@ -53,7 +53,7 @@ #include "items.h" #include "macro.h" #include "misc.h" -#include "monstuff.h" +#include "mon-stuff.h" #include "mon-util.h" #include "notes.h" #include "output.h" @@ -885,27 +885,21 @@ bool is_trap_square(dungeon_feature_type grid) // Does the equivalent of KILL_RESET on all monsters in LOS. Should only be // applied to new games. -void zap_los_monsters() +void zap_los_monsters(bool items_also) { - calc_show_los(); + // Not using player LOS since clouds might temporarily + // block monsters. + los_def los(you.pos(), opc_fullyopaque); + los.update(); - for (rectangle_iterator ri(crawl_view.vlos1, crawl_view.vlos2); ri; ++ri ) + for (radius_iterator ri(you.pos(), LOS_RADIUS, true, false); ri; ++ri) { - if (!in_vlos(*ri)) + if (!you.see_cell(*ri)) continue; - const coord_def g = view2grid(*ri); - - if (!map_bounds(g)) - continue; - - if (g == you.pos()) - continue; - - // At tutorial beginning disallow items in line of sight. - if (Options.tutorial_events[TUT_SEEN_FIRST_OBJECT]) + if (items_also) { - int item = igrd(g); + int item = igrd(*ri); if (item != NON_ITEM && mitm[item].is_valid() ) destroy_item(item); @@ -913,11 +907,8 @@ void zap_los_monsters() // If we ever allow starting with a friendly monster, // we'll have to check here. - monsters *mon = monster_at(g); - if (mon == NULL) - continue; - - if (mons_class_flag( mon->type, M_NO_EXP_GAIN )) + monsters *mon = monster_at(*ri); + if (mon == NULL || mons_class_flag(mon->type, M_NO_EXP_GAIN)) continue; #ifdef DEBUG_DIAGNOSTICS diff --git a/crawl-ref/source/stuff.h b/crawl-ref/source/stuff.h index 4a7fab6c11..976bb8fddb 100644 --- a/crawl-ref/source/stuff.h +++ b/crawl-ref/source/stuff.h @@ -93,7 +93,7 @@ template <typename Z> inline Z sgn(Z x) } bool is_trap_square(dungeon_feature_type grid); -void zap_los_monsters(); +void zap_los_monsters(bool items_also); int integer_sqrt(int value); diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc index 4b5ab14ae8..fabf242086 100644 --- a/crawl-ref/source/tags.cc +++ b/crawl-ref/source/tags.cc @@ -202,9 +202,6 @@ static void unmarshallResists(reader &th, mon_resist_def &res, static void marshallSpells(writer &, const monster_spells &); static void unmarshallSpells(reader &, monster_spells &); -static void marshall_monster(writer &th, const monsters &m); -static void unmarshall_monster(reader &th, monsters &m); - template<typename T, typename T_iter, typename T_marshal> static void marshall_iterator(writer &th, T_iter beg, T_iter end, T_marshal marshal); @@ -1161,14 +1158,14 @@ static void tag_construct_you_dungeon(writer &th) static void marshall_follower(writer &th, const follower &f) { - marshall_monster(th, f.mons); + marshallMonster(th, f.mons); for (int i = 0; i < NUM_MONSTER_SLOTS; ++i) marshallItem(th, f.items[i]); } static void unmarshall_follower(reader &th, follower &f) { - unmarshall_monster(th, f.mons); + unmarshallMonster(th, f.mons); for (int i = 0; i < NUM_MONSTER_SLOTS; ++i) unmarshallItem(th, f.items[i]); } @@ -1876,7 +1873,7 @@ static mon_enchant unmarshall_mon_enchant(reader &th) return (me); } -static void marshall_monster(writer &th, const monsters &m) +void marshallMonster(writer &th, const monsters &m) { marshallString(th, m.mname); marshallByte(th, m.ac); @@ -1928,6 +1925,8 @@ static void marshall_monster(writer &th, const monsters &m) ASSERT(m.ghost.get()); marshallGhost(th, *m.ghost); } + + m.props.write(th); } static void tag_construct_level_monsters(writer &th) @@ -1963,7 +1962,7 @@ static void tag_construct_level_monsters(writer &th) } } #endif - marshall_monster(th, m); + marshallMonster(th, m); } } @@ -2186,7 +2185,7 @@ static void tag_read_level_items(reader &th, char minorVersion) #endif } -static void unmarshall_monster(reader &th, monsters &m) +void unmarshallMonster(reader &th, monsters &m) { m.reset(); @@ -2246,6 +2245,12 @@ static void unmarshall_monster(reader &th, monsters &m) if (mons_is_ghost_demon(m.type)) m.set_ghost(unmarshallGhost(th, _tag_minor_version)); + if (_tag_minor_version >= TAG_MINOR_MON_PROP) + { + m.props.clear(); + m.props.read(th); + } + m.check_speed(); } @@ -2270,7 +2275,7 @@ static void tag_read_level_monsters(reader &th, char minorVersion) for (i = 0; i < count; i++) { monsters &m = menv[i]; - unmarshall_monster(th, m); + unmarshallMonster(th, m); // place monster if (m.type != MONS_NO_MONSTER) diff --git a/crawl-ref/source/tags.h b/crawl-ref/source/tags.h index b843a55329..773c686b49 100644 --- a/crawl-ref/source/tags.h +++ b/crawl-ref/source/tags.h @@ -61,7 +61,8 @@ enum tag_minor_version TAG_MINOR_DSTRAITS = 9, // Pre-calculate demonspawn mutations TAG_MINOR_YOU_PROP = 10, // Player class has CrawlHashTable TAG_MINOR_SMALL_HASH = 11, // Reduced RAM size of CrawlHashTable - TAG_MINOR_VERSION = 11 // Current version. (Keep equal to max.) + TAG_MINOR_MON_PROP = 12, // Monster class has CrawlHashTable + TAG_MINOR_VERSION = 12 // Current version. (Keep equal to max.) }; @@ -95,6 +96,7 @@ void marshallString (writer &, const std::string &, int maxSize = 0); void marshallString4 (writer &, const std::string &); void marshallCoord (writer &, const coord_def &); void marshallItem (writer &, const item_def &); +void marshallMonster (writer &, const monsters &); void marshallShowtype (writer &, const show_type &); /* *********************************************************************** @@ -133,6 +135,7 @@ std::string unmarshallString (reader &, int maxSize = 1000); void unmarshallString4 (reader &, std::string&); void unmarshallCoord (reader &, coord_def &c); void unmarshallItem (reader &, item_def &item); +void unmarshallMonster (reader &, monsters &item); show_type unmarshallShowtype (reader &); /* *********************************************************************** diff --git a/crawl-ref/source/terrain.cc b/crawl-ref/source/terrain.cc index 16b7db05b7..45ea54fafe 100644 --- a/crawl-ref/source/terrain.cc +++ b/crawl-ref/source/terrain.cc @@ -23,8 +23,8 @@ #include "los.h" #include "message.h" #include "misc.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "mon-util.h" #include "ouch.h" #include "overmap.h" diff --git a/crawl-ref/source/tilepick.cc b/crawl-ref/source/tilepick.cc index e0b76d4b87..561d790dd1 100644 --- a/crawl-ref/source/tilepick.cc +++ b/crawl-ref/source/tilepick.cc @@ -24,7 +24,7 @@ #include "kills.h" #include "los.h" #include "macro.h" -#include "monstuff.h" +#include "mon-stuff.h" #include "mon-util.h" #include "player.h" #include "shopping.h" @@ -2794,14 +2794,14 @@ int tileidx_spell(spell_type spell) case SPELL_FREEZE: return TILEG_FREEZE; case SPELL_THROW_FROST: return TILEG_THROW_FROST; case SPELL_FREEZING_AURA: return TILEG_FREEZING_AURA; - case SPELL_SLEEP: return TILEG_ENSORCELLED_HIBERNATION; + case SPELL_HIBERNATION: return TILEG_ENSORCELLED_HIBERNATION; case SPELL_OZOCUBUS_ARMOUR: return TILEG_OZOCUBUS_ARMOUR; case SPELL_THROW_ICICLE: return TILEG_THROW_ICICLE; case SPELL_CONDENSATION_SHIELD: return TILEG_CONDENSATION_SHIELD; case SPELL_OZOCUBUS_REFRIGERATION: return TILEG_OZOCUBUS_REFRIGERATION; case SPELL_BOLT_OF_COLD: return TILEG_BOLT_OF_COLD; case SPELL_FREEZING_CLOUD: return TILEG_FREEZING_CLOUD; - case SPELL_MASS_SLEEP: return TILEG_METABOLIC_ENGLACIATION; + case SPELL_ENGLACIATION: return TILEG_METABOLIC_ENGLACIATION; case SPELL_SIMULACRUM: return TILEG_SIMULACRUM; case SPELL_ICE_STORM: return TILEG_ICE_STORM; @@ -2819,7 +2819,7 @@ int tileidx_spell(spell_type spell) // Enchantment case SPELL_CONFUSING_TOUCH: return TILEG_CONFUSING_TOUCH; - case SPELL_BACKLIGHT: return TILEG_CORONA; + case SPELL_CORONA: return TILEG_CORONA; case SPELL_PROJECTED_NOISE: return TILEG_PROJECTED_NOISE; case SPELL_SURE_BLADE: return TILEG_SURE_BLADE; case SPELL_TUKIMAS_VORPAL_BLADE: return TILEG_TUKIMAS_VORPAL_BLADE; diff --git a/crawl-ref/source/tilereg.cc b/crawl-ref/source/tilereg.cc index 14d53e03e1..4ddabc8b67 100644 --- a/crawl-ref/source/tilereg.cc +++ b/crawl-ref/source/tilereg.cc @@ -226,10 +226,9 @@ TileRegion::TileRegion(ImageManager* im, FTFont *tag_font, int tile_x, int tile_ dx = tile_x; dy = tile_y; m_tag_font = tag_font; -#if 0 - // Not needed? (jpeg) + + // To quite Valgrind m_dirty = true; -#endif } TileRegion::~TileRegion() diff --git a/crawl-ref/source/tilereg.h b/crawl-ref/source/tilereg.h index c157148c68..74fbb18f60 100644 --- a/crawl-ref/source/tilereg.h +++ b/crawl-ref/source/tilereg.h @@ -295,7 +295,6 @@ protected: TileBuffer m_buf_dngn; TileBuffer m_buf_doll; TileBuffer m_buf_main; - bool m_dirty; struct tile_overlay { diff --git a/crawl-ref/source/traps.cc b/crawl-ref/source/traps.cc index 40410f8362..47b245f71d 100644 --- a/crawl-ref/source/traps.cc +++ b/crawl-ref/source/traps.cc @@ -27,7 +27,7 @@ #include "message.h" #include "misc.h" #include "mon-util.h" -#include "monstuff.h" +#include "mon-stuff.h" #include "mtransit.h" #include "ouch.h" #include "player.h" diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc index 0046863591..51848b200e 100644 --- a/crawl-ref/source/travel.cc +++ b/crawl-ref/source/travel.cc @@ -32,7 +32,7 @@ #include "message.h" #include "misc.h" #include "mon-util.h" -#include "monstuff.h" +#include "mon-stuff.h" #include "options.h" #ifdef USE_TILE #include "output.h" diff --git a/crawl-ref/source/tutorial.cc b/crawl-ref/source/tutorial.cc index 5585875576..a770cc1956 100644 --- a/crawl-ref/source/tutorial.cc +++ b/crawl-ref/source/tutorial.cc @@ -3256,7 +3256,6 @@ void learned_something_new(tutorial_event_type seen_what, coord_def gc) text << "That "; #ifdef USE_TILE // need to highlight monster - const coord_def gc = m->pos(); tiles.place_cursor(CURSOR_TUTORIAL, gc); tiles.add_text_tag(TAG_TUTORIAL, m); diff --git a/crawl-ref/source/util/art-data.pl b/crawl-ref/source/util/art-data.pl index 05f6dcdf9b..67a4dfe476 100755 --- a/crawl-ref/source/util/art-data.pl +++ b/crawl-ref/source/util/art-data.pl @@ -589,12 +589,10 @@ sub write_data ENDofTEXT my $artefact; - my $art_num = 1; foreach $artefact (@all_artefacts) { - print HEADER "/* $art_num: UNRAND_$artefact->{_ENUM} */\n"; + print HEADER "/* UNRAND_$artefact->{_ENUM} */\n"; print HEADER art_to_str($artefact); - $art_num++; } close(HEADER); diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc index fc9c6cf271..648141b7a3 100644 --- a/crawl-ref/source/view.cc +++ b/crawl-ref/source/view.cc @@ -31,6 +31,7 @@ #include "attitude-change.h" #include "branch.h" #include "cio.h" +#include "cloud.h" #include "clua.h" #include "colour.h" #include "database.h" @@ -48,8 +49,9 @@ #include "message.h" #include "misc.h" #include "mon-behv.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-iter.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "mon-util.h" #include "newgame.h" #include "options.h" @@ -122,34 +124,39 @@ void flush_comes_into_view() void monster_grid_updates() { - for (int s = 0; s < MAX_MONSTERS; ++s) + for (monster_iterator mi(&you.get_los()); mi; ++mi) { - monsters *monster = &menv[s]; - - if (monster->alive() && mons_near(monster)) + if ((mi->asleep() || mons_is_wandering(*mi)) + && check_awaken(*mi)) { - if ((monster->asleep() || mons_is_wandering(monster)) - && check_awaken(monster)) - { - behaviour_event(monster, ME_ALERT, MHITYOU, you.pos(), false); - handle_monster_shouts(monster); - } + behaviour_event(*mi, ME_ALERT, MHITYOU, you.pos(), false); + handle_monster_shouts(*mi); + } fedhas_neutralise(monster); - if (!monster->visible_to(&you)) - continue; + if (!mi->visible_to(&you)) + continue; good_god_follower_attitude_change(monster); beogh_follower_convert(monster); slime_convert(monster); + // XXX: Probably quite hackish. Allows for monsters going berserk when + // they see the player. Currently only used for Duvessa, see the + // function _elven_twin_dies in mon-stuff.cc. + if (mi->flags & MF_GOING_BERSERK) + { + mi->flags &= ~MF_GOING_BERSERK; + mi->go_berserk(true); } } } -static void _check_monster_pos(const monsters* monster, int s) +static void _check_monster_pos(const monsters* monster) { + int s = monster->mindex(); ASSERT(mgrd(monster->pos()) == s); + // [rob] The following in case asserts aren't enabled. // [enne] - It's possible that mgrd and monster->x/y are out of // sync because they are updated separately. If we can see this // monster, then make sure that the mgrd is set correctly. @@ -169,20 +176,15 @@ static void _check_monster_pos(const monsters* monster, int s) void monster_grid() { - for (int s = 0; s < MAX_MONSTERS; ++s) + for (monster_iterator mi(&you.get_los()); mi; ++mi) { - monsters *monster = &menv[s]; - - if (monster->alive() && mons_near(monster)) - { - _check_monster_pos(monster, s); - env.show.update_monster(monster); + _check_monster_pos(*mi); + env.show.update_monster(*mi); #ifdef USE_TILE - if (monster->visible_to(&you)) - tile_place_monster(monster->pos().x, monster->pos().y, s, true); + if (mi->visible_to(&you)) + tile_place_monster(mi->pos().x, mi->pos().y, mi->mindex(), true); #endif - } } } @@ -190,39 +192,34 @@ void update_monsters_in_view() { unsigned int num_hostile = 0; - for (int s = 0; s < MAX_MONSTERS; s++) + for (monster_iterator mi; mi; ++mi) { - monsters *monster = &menv[s]; - - if (!monster->alive()) - continue; - - if (mons_near(monster)) + if (mons_near(*mi)) { - if (monster->attitude == ATT_HOSTILE) + if (mi->attitude == ATT_HOSTILE) num_hostile++; - if (mons_is_unknown_mimic(monster)) + if (mons_is_unknown_mimic(*mi)) { // For unknown mimics, don't mark as seen, // but do mark it as in view for later messaging. // FIXME: is this correct? - monster->flags |= MF_WAS_IN_VIEW; + mi->flags |= MF_WAS_IN_VIEW; } - else if (monster->visible_to(&you)) + else if (mi->visible_to(&you)) { - handle_seen_interrupt(monster); - seen_monster(monster); + handle_seen_interrupt(*mi); + seen_monster(*mi); } else - monster->flags &= ~MF_WAS_IN_VIEW; + mi->flags &= ~MF_WAS_IN_VIEW; } else - monster->flags &= ~MF_WAS_IN_VIEW; + mi->flags &= ~MF_WAS_IN_VIEW; // If the monster hasn't been seen by the time that the player // gets control back then seen_context is out of date. - monster->seen_context.clear(); + mi->seen_context.clear(); } // Xom thinks it's hilarious the way the player picks up an ever @@ -767,8 +764,30 @@ void viewwindow(bool do_updates) const coord_def ep = view2show(grid2view(gc)); if (in_bounds(gc) && you.see_cell(gc)) + { maybe_remove_autoexclusion(gc); + // Set excludes in a radius of 1 around harmful clouds genereated + // by neither monsters nor the player. + const int cloudidx = env.cgrid(gc); + if (cloudidx != EMPTY_CLOUD) + { + cloud_struct &cl = env.cloud[cloudidx]; + cloud_type ctype = cl.type; + + if (!is_harmless_cloud(ctype) + && cl.whose == KC_OTHER + && cl.killer == KILL_MISC) + { + for (adjacent_iterator ai(gc, false); ai; ++ai) + { + if (!cell_is_solid(*ai) && !is_exclude_root(*ai)) + set_exclude(*ai, 0); + } + } + } + } + // Print tutorial messages for features in LOS. if (Options.tutorial_left && in_bounds(gc) diff --git a/crawl-ref/source/viewmap.cc b/crawl-ref/source/viewmap.cc index 98603fc959..3369147e66 100644 --- a/crawl-ref/source/viewmap.cc +++ b/crawl-ref/source/viewmap.cc @@ -741,6 +741,17 @@ void show_map( level_pos &spec_place, bool travel_mode, bool allow_esc ) _reset_travel_colours(features, on_level); break; +#ifdef WIZARD + case CMD_MAP_EXCLUDE_RADIUS: + { + const coord_def p(start_x + curs_x - 1, start_y + curs_y - 1); + set_exclude(p, getchm() - '0'); + + _reset_travel_colours(features, on_level); + break; + } +#endif + case CMD_MAP_MOVE_DOWN_LEFT: move_x = -1; move_y = 1; diff --git a/crawl-ref/source/wiz-dgn.cc b/crawl-ref/source/wiz-dgn.cc index 5d178d02c1..69f5e1ec2a 100644 --- a/crawl-ref/source/wiz-dgn.cc +++ b/crawl-ref/source/wiz-dgn.cc @@ -25,6 +25,7 @@ #include "options.h" #include "place.h" #include "player.h" +#include "religion.h" #include "stuff.h" #include "terrain.h" #include "traps.h" @@ -366,6 +367,49 @@ void wizard_list_branches() "this game", i, branches[i].longname); } } + + if (!you.props.exists(OVERFLOW_TEMPLES_KEY)) + return; + + mpr("----", MSGCH_DIAGNOSTICS); + mpr("Overflow temples: ", MSGCH_DIAGNOSTICS); + + CrawlVector &levels = you.props[OVERFLOW_TEMPLES_KEY].get_vector(); + + for (unsigned int i = 0; i < levels.size(); i++) + { + CrawlStoreValue &val = levels[i]; + + // Does this level have an overflow temple? + if (val.get_flags() & SFLAG_UNSET) + continue; + + CrawlVector &temples = val.get_vector(); + + if (temples.size() == 0) + continue; + + std::vector<std::string> god_names; + + for (unsigned int j = 0; j < temples.size(); j++) + { + CrawlHashTable &temple_hash = temples[j]; + CrawlVector &gods = temple_hash[TEMPLE_GODS_KEY]; + + for (unsigned int k = 0; k < gods.size(); k++) + { + god_type god = (god_type) gods[k].get_byte(); + + god_names.push_back(god_name(god)); + } + } + + mprf(MSGCH_DIAGNOSTICS, "%lu on D:%lu (%s)", temples.size(), + i + 1, + comma_separated_line( god_names.begin(), + god_names.end() ).c_str() + ); + } } void wizard_map_level() diff --git a/crawl-ref/source/wiz-fsim.cc b/crawl-ref/source/wiz-fsim.cc index 4aa2b2bac7..31d052a268 100644 --- a/crawl-ref/source/wiz-fsim.cc +++ b/crawl-ref/source/wiz-fsim.cc @@ -17,9 +17,9 @@ #include "item_use.h" #include "it_use2.h" #include "message.h" -#include "monplace.h" +#include "mon-place.h" #include "monster.h" -#include "monstuff.h" +#include "mon-stuff.h" #include "options.h" #include "player.h" #include "quiver.h" @@ -32,7 +32,8 @@ static int _create_fsim_monster(int mtype, int hp) const int mi = create_monster( mgen_data::hostile_at( - static_cast<monster_type>(mtype), false, 0, 0, you.pos())); + static_cast<monster_type>(mtype), + "the fight simulator", false, 0, 0, you.pos())); if (mi == -1) return (mi); diff --git a/crawl-ref/source/wiz-item.cc b/crawl-ref/source/wiz-item.cc index 8b11fb100a..bae01bc91a 100644 --- a/crawl-ref/source/wiz-item.cc +++ b/crawl-ref/source/wiz-item.cc @@ -22,7 +22,8 @@ #include "it_use2.h" #include "invent.h" #include "makeitem.h" -#include "monstuff.h" +#include "mon-iter.h" +#include "mon-stuff.h" #include "mon-util.h" #include "options.h" #include "religion.h" @@ -729,25 +730,20 @@ void wizard_unidentify_pack() // Forget things that nearby monsters are carrying, as well. // (For use with the "give monster an item" wizard targetting // command.) - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mon(&you.get_los()); mon; ++mon) { - monsters* mon = &menv[i]; - - if (mon->alive() && mons_near(mon)) + for (int j = 0; j < NUM_MONSTER_SLOTS; ++j) { - for (int j = 0; j < NUM_MONSTER_SLOTS; ++j) - { - if (mon->inv[j] == NON_ITEM) - continue; + if (mon->inv[j] == NON_ITEM) + continue; - item_def &item = mitm[mon->inv[j]]; + item_def &item = mitm[mon->inv[j]]; - if (!item.is_valid()) - continue; + if (!item.is_valid()) + continue; - set_ident_type(item, ID_UNKNOWN_TYPE); - unset_ident_flags(item, ISFLAG_IDENT_MASK); - } + set_ident_type(item, ID_UNKNOWN_TYPE); + unset_ident_flags(item, ISFLAG_IDENT_MASK); } } } diff --git a/crawl-ref/source/wiz-mon.cc b/crawl-ref/source/wiz-mon.cc index eaccf8346e..3701d344a0 100644 --- a/crawl-ref/source/wiz-mon.cc +++ b/crawl-ref/source/wiz-mon.cc @@ -20,9 +20,10 @@ #include "jobs.h" #include "macro.h" #include "message.h" -#include "monplace.h" -#include "monspeak.h" -#include "monstuff.h" +#include "mon-place.h" +#include "mon-speak.h" +#include "mon-stuff.h" +#include "mon-iter.h" #include "mon-util.h" #include "output.h" #include "religion.h" @@ -253,13 +254,9 @@ void debug_list_monsters() std::string prev_name = ""; int count = 0; - for (int i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi; mi; ++mi) { - const monsters *m = &menv[mon_nums[i]]; - if (!m->alive()) - continue; - - std::string name = m->name(DESC_PLAIN, true); + std::string name = mi->name(DESC_PLAIN, true); if (prev_name != name && count > 0) { @@ -276,15 +273,15 @@ void debug_list_monsters() count++; prev_name = name; - int exp = exper_value(m); + int exp = exper_value(*mi); total_exp += exp; - if ((m->flags & (MF_WAS_NEUTRAL | MF_CREATED_FRIENDLY)) - || m->has_ench(ENCH_ABJ)) + if ((mi->flags & (MF_WAS_NEUTRAL | MF_CREATED_FRIENDLY)) + || mi->has_ench(ENCH_ABJ)) { continue; } - if (m->flags & MF_GOT_HALF_XP) + if (mi->flags & MF_GOT_HALF_XP) exp /= 2; total_adj_exp += exp; @@ -338,9 +335,8 @@ void wizard_spawn_control() { // 50 spots are reserved for non-wandering monsters. int max_spawn = MAX_MONSTERS - 50; - for (int i = 0; i < MAX_MONSTERS; ++i) - if (menv[i].alive()) - max_spawn--; + for (monster_iterator mi; mi; ++mi) + if (mi->alive()) if (max_spawn <= 0) { diff --git a/crawl-ref/source/xom.cc b/crawl-ref/source/xom.cc index 91d006d747..f7a694d840 100644 --- a/crawl-ref/source/xom.cc +++ b/crawl-ref/source/xom.cc @@ -26,9 +26,10 @@ #include "message.h" #include "misc.h" #include "mon-behv.h" +#include "mon-iter.h" #include "mon-util.h" -#include "monplace.h" -#include "monstuff.h" +#include "mon-place.h" +#include "mon-stuff.h" #include "mutation.h" #include "notes.h" #include "options.h" @@ -84,7 +85,7 @@ static const spell_type _xom_nontension_spells[] = // Spells to be cast at tension > 0, i.e. usually in battle situations. static const spell_type _xom_tension_spells[] = { - SPELL_BLINK, SPELL_CONFUSING_TOUCH, SPELL_CAUSE_FEAR, SPELL_MASS_SLEEP, + SPELL_BLINK, SPELL_CONFUSING_TOUCH, SPELL_CAUSE_FEAR, SPELL_ENGLACIATION, SPELL_DISPERSAL, SPELL_STONESKIN, SPELL_RING_OF_FLAMES, SPELL_OLGREBS_TOXIC_RADIANCE, SPELL_TUKIMAS_VORPAL_BLADE, SPELL_MAXWELLS_SILVER_HAMMER, SPELL_FIRE_BRAND, SPELL_FREEZING_AURA, @@ -1197,14 +1198,10 @@ static int _xom_do_potion(bool debug = false) static int _xom_confuse_monsters(int sever, bool debug = false) { bool rc = false; - monsters *monster; - for (unsigned i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi(&you.get_los()); mi; ++mi) { - monster = &menv[i]; - - if (monster->type == MONS_NO_MONSTER || !mons_near(monster) - || monster->wont_attack() - || !mons_class_is_confusable(monster->type) + if (mi->wont_attack() + || !mons_class_is_confusable(mi->type) || one_chance_in(20)) { continue; @@ -1213,14 +1210,14 @@ static int _xom_confuse_monsters(int sever, bool debug = false) if (debug) return (XOM_GOOD_CONFUSION); - if (monster->add_ench(mon_enchant(ENCH_CONFUSION, 0, + if (mi->add_ench(mon_enchant(ENCH_CONFUSION, 0, KC_FRIENDLY, random2(sever)))) { // Only give this message once. if (!rc) god_speaks(GOD_XOM, _get_xom_speech("confusion").c_str()); - simple_monster_message(monster, " looks rather confused."); + simple_monster_message(*mi, " looks rather confused."); rc = true; } } @@ -1265,12 +1262,14 @@ static int _xom_send_allies(int sever, bool debug = false) { monster_type mon_type = _xom_random_demon(sever); - summons[i] = - create_monster( - mgen_data(mon_type, BEH_FRIENDLY, - 3, MON_SUMM_AID, - you.pos(), MHITYOU, - MG_FORCE_BEH, GOD_XOM)); + mgen_data mg(mon_type, BEH_FRIENDLY, &you, 3, MON_SUMM_AID, + you.pos(), MHITYOU, MG_FORCE_BEH, GOD_XOM); + + // Even though the friendlies are charged to you for accounting, + // they should still show as Xom's fault if one of them kills you. + mg.non_actor_summoner = "Xom"; + + summons[i] = create_monster(mg); if (summons[i] != -1) { @@ -1328,6 +1327,7 @@ static int _xom_send_allies(int sever, bool debug = false) || (!is_demonic[i] && hostiletype == 2)) { mon->attitude = ATT_HOSTILE; + // XXX need to reset summon quota here? behaviour_event(mon, ME_ALERT, MHITYOU); } } @@ -1370,10 +1370,12 @@ static int _xom_send_one_ally(int sever, bool debug = false) if (different && one_chance_in(4)) beha = BEH_HOSTILE; - const int summons = - create_monster( - mgen_data(mon_type, beha, 6, MON_SUMM_AID, you.pos(), MHITYOU, - MG_FORCE_BEH, GOD_XOM)); + mgen_data mg(mon_type, beha, (beha == BEH_FRIENDLY) ? &you : 0, 6, + MON_SUMM_AID, you.pos(), MHITYOU, MG_FORCE_BEH, GOD_XOM); + + mg.non_actor_summoner = "Xom"; + + const int summons = create_monster(mg); if (summons != -1) { @@ -1541,24 +1543,16 @@ static int _xom_swap_weapons(bool debug = false) } std::vector<monsters *> mons_wpn; - for (unsigned i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi(&you); mi; ++mi) { - monsters* m = &menv[i]; - - if (!m->alive()) - continue; - - if (!you.see_cell(m->pos())) - continue; - - if (!wpn || m->wont_attack() || m->is_summoned() - || mons_itemuse(m) < MONUSE_STARTING_EQUIPMENT - || (m->flags & MF_HARD_RESET)) + if (!wpn || mi->wont_attack() || mi->is_summoned() + || mons_itemuse(*mi) < MONUSE_STARTING_EQUIPMENT + || (mi->flags & MF_HARD_RESET)) { continue; } - const int mweap = m->inv[MSLOT_WEAPON]; + const int mweap = mi->inv[MSLOT_WEAPON]; if (mweap == NON_ITEM) continue; @@ -1567,11 +1561,11 @@ static int _xom_swap_weapons(bool debug = false) // Let's be nice about this. if (weapon.base_type == OBJ_WEAPONS && !(weapon.flags & ISFLAG_SUMMONED) - && you.can_wield(weapon, true) && m->can_wield(*wpn, true) + && you.can_wield(weapon, true) && mi->can_wield(*wpn, true) && !get_weapon_brand(weapon) != SPWPN_DISTORTION && (!is_artefact(weapon) || _art_is_safe(weapon))) { - mons_wpn.push_back(m); + mons_wpn.push_back(*mi); } } if (mons_wpn.empty()) @@ -1677,18 +1671,9 @@ static int _xom_rearrange_pieces(int sever, bool debug = false) return (XOM_DID_NOTHING); std::vector<monsters *> mons; - for (unsigned i = 0; i < MAX_MONSTERS; ++i) - { - monsters* m = &menv[i]; + for (monster_iterator mi(&you); mi; ++mi) + mons.push_back(*mi); - if (!m->alive()) - continue; - - if (!you.see_cell(m->pos())) - continue; - - mons.push_back(m); - } if (mons.empty()) return (XOM_DID_NOTHING); @@ -1741,24 +1726,16 @@ static int _xom_rearrange_pieces(int sever, bool debug = false) static int _xom_animate_monster_weapon(int sever, bool debug = false) { std::vector<monsters *> mons_wpn; - for (unsigned i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi(&you); mi; ++mi) { - monsters* m = &menv[i]; - - if (!m->alive()) - continue; - - if (!you.see_cell(m->pos())) - continue; - - if (m->wont_attack() || m->is_summoned() - || mons_itemuse(m) < MONUSE_STARTING_EQUIPMENT - || (m->flags & MF_HARD_RESET)) + if (mi->wont_attack() || mi->is_summoned() + || mons_itemuse(*mi) < MONUSE_STARTING_EQUIPMENT + || (mi->flags & MF_HARD_RESET)) { continue; } - const int mweap = m->inv[MSLOT_WEAPON]; + const int mweap = mi->inv[MSLOT_WEAPON]; if (mweap == NON_ITEM) continue; @@ -1771,7 +1748,7 @@ static int _xom_animate_monster_weapon(int sever, bool debug = false) && !is_special_unrandom_artefact(weapon) && !get_weapon_brand(weapon) != SPWPN_DISTORTION) { - mons_wpn.push_back(m); + mons_wpn.push_back(*mi); } } if (mons_wpn.empty()) @@ -1791,10 +1768,14 @@ static int _xom_animate_monster_weapon(int sever, bool debug = false) ASSERT(wpn != NON_ITEM); const int dur = std::min(2 + (random2(sever) / 5), 6); - const int monster = create_monster( - mgen_data(MONS_DANCING_WEAPON, BEH_FRIENDLY, - dur, SPELL_TUKIMAS_DANCE, - mon->pos(), mon->mindex(), 0, GOD_XOM)); + + mgen_data mg(MONS_DANCING_WEAPON, BEH_FRIENDLY, &you, dur, + SPELL_TUKIMAS_DANCE, mon->pos(), mon->mindex(), + 0, GOD_XOM); + + mg.non_actor_summoner = "Xom"; + + const int monster = create_monster(mg); if (monster == -1) return (XOM_DID_NOTHING); @@ -1881,10 +1862,13 @@ static int _xom_send_major_ally(int sever, bool debug = false) if (!is_demonic && one_chance_in(4)) beha = BEH_HOSTILE; - const int summons = - create_monster( - mgen_data(_xom_random_demon(sever, one_chance_in(8)), beha, - 0, 0, you.pos(), MHITYOU, MG_FORCE_BEH, GOD_XOM)); + mgen_data mg(_xom_random_demon(sever, one_chance_in(8)), beha, + (beha == BEH_FRIENDLY) ? &you : 0, + 0, 0, you.pos(), MHITYOU, MG_FORCE_BEH, GOD_XOM); + + mg.non_actor_summoner = "Xom"; + + const int summons = create_monster(mg); if (summons != -1) { @@ -2846,22 +2830,18 @@ static int _xom_player_confusion_effect(int sever, bool debug = false) bool mons_too = false; if (coinflip()) { - for (unsigned i = 0; i < MAX_MONSTERS; ++i) + for (monster_iterator mi(&you.get_los()); mi; ++mi) { - monsters* const monster = &menv[i]; - - if (!monster->alive() - || !mons_near(monster) - || !mons_class_is_confusable(monster->type) + if (!mons_class_is_confusable(mi->type) || one_chance_in(20)) { continue; } - if (monster->add_ench(mon_enchant(ENCH_CONFUSION, 0, + if (mi->add_ench(mon_enchant(ENCH_CONFUSION, 0, KC_FRIENDLY, random2(sever)))) { - simple_monster_message(monster, + simple_monster_message(*mi, " looks rather confused."); } mons_too = true; @@ -3212,7 +3192,7 @@ static int _xom_summon_hostiles(int sever, bool debug = false) { if (create_monster( mgen_data::hostile_at( - _xom_random_demon(sever), + _xom_random_demon(sever), "Xom", true, 4, MON_SUMM_WRATH, you.pos(), 0, GOD_XOM)) != -1) { |