summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/source/abyss.cc2
-rw-r--r--crawl-ref/source/acr.cc29
-rw-r--r--crawl-ref/source/arena.cc450
-rw-r--r--crawl-ref/source/arena.h8
-rw-r--r--crawl-ref/source/dat/arena.des26
-rw-r--r--crawl-ref/source/dat/clua/loadmaps.lua2
-rw-r--r--crawl-ref/source/directn.h5
-rw-r--r--crawl-ref/source/dungeon.cc62
-rw-r--r--crawl-ref/source/dungeon.h12
-rw-r--r--crawl-ref/source/externs.h2
-rw-r--r--crawl-ref/source/fight.cc6
-rw-r--r--crawl-ref/source/initfile.cc14
-rw-r--r--crawl-ref/source/initfile.h2
-rw-r--r--crawl-ref/source/makefile.obj1
-rw-r--r--crawl-ref/source/mapdef.cc21
-rw-r--r--crawl-ref/source/mapdef.h9
-rw-r--r--crawl-ref/source/message.cc7
-rw-r--r--crawl-ref/source/mon-util.cc12
-rw-r--r--crawl-ref/source/monplace.cc4
-rw-r--r--crawl-ref/source/monspeak.cc3
-rw-r--r--crawl-ref/source/monstuff.cc53
-rw-r--r--crawl-ref/source/mstuff2.cc4
-rw-r--r--crawl-ref/source/output.cc3
-rw-r--r--crawl-ref/source/player.cc6
-rw-r--r--crawl-ref/source/state.cc2
-rw-r--r--crawl-ref/source/state.h2
-rw-r--r--crawl-ref/source/stuff.cc2
-rw-r--r--crawl-ref/source/view.cc49
28 files changed, 731 insertions, 67 deletions
diff --git a/crawl-ref/source/abyss.cc b/crawl-ref/source/abyss.cc
index a1003b1385..910b85eec7 100644
--- a/crawl-ref/source/abyss.cc
+++ b/crawl-ref/source/abyss.cc
@@ -398,7 +398,7 @@ void area_shift(void)
{
#ifdef DEBUG_ABYSS
mprf(MSGCH_DIAGNOSTICS, "area_shift() - player at pos (%d, %d)",
- you.youpos.x, you.youpos.y);
+ you.position.x, you.position.y);
#endif
// Preserve floor props around the player, primarily so that
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index bd122ecf91..960b612392 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -43,6 +43,7 @@
#include "abl-show.h"
#include "abyss.h"
+#include "arena.h"
#include "branch.h"
#include "chardump.h"
#include "cio.h"
@@ -135,6 +136,8 @@ char info[ INFO_SIZE ]; // messaging queue extern'd everywhere {dlb}
int stealth; // externed in view.cc
+void world_reacts();
+
static key_recorder repeat_again_rec;
// Clockwise, around the compass from north (same order as enum RUN_DIR)
@@ -160,7 +163,6 @@ static void _close_door(coord_def move);
static void _start_running( int dir, int mode );
static void _prep_input();
-static void _world_reacts();
static command_type _get_next_cmd();
static keycode_type _get_next_keycode();
static command_type _keycode_to_command( keycode_type key );
@@ -1527,7 +1529,7 @@ static void _input()
crawl_state.cancel_cmd_repeat("Cannot move, cancelling command "
"repetition.");
- _world_reacts();
+ world_reacts();
return;
}
@@ -1547,13 +1549,13 @@ static void _input()
if (you_are_delayed() && current_delay_action() != DELAY_MACRO_PROCESS_KEY)
{
if (you.time_taken)
- _world_reacts();
+ world_reacts();
return;
}
if (you.turn_is_over)
{
- _world_reacts();
+ world_reacts();
return;
}
@@ -1622,7 +1624,7 @@ static void _input()
if (apply_berserk_penalty)
_do_berserk_no_combat_penalty();
- _world_reacts();
+ world_reacts();
}
else
viewwindow(true, false);
@@ -3049,7 +3051,7 @@ static void _check_sanctuary()
decrease_sanctuary_radius();
}
-static void _world_reacts()
+void world_reacts()
{
crawl_state.clear_god_acting();
@@ -3080,7 +3082,8 @@ static void _world_reacts()
search_around(false); // Check nonadjacent squares too.
}
- stealth = check_stealth();
+ if (!crawl_state.arena)
+ stealth = check_stealth();
#ifdef DEBUG_STEALTH
// Too annoying for regular diagnostics.
@@ -3090,7 +3093,7 @@ static void _world_reacts()
if (you.special_wield != SPWLD_NONE)
special_wielded();
- if (one_chance_in(10))
+ if (!crawl_state.arena && one_chance_in(10))
{
// this is instantaneous
if (player_teleport() > 0 && one_chance_in(100 / player_teleport()))
@@ -3099,7 +3102,7 @@ static void _world_reacts()
you_teleport_now( false, true ); // to new area of the Abyss
}
- if (env.cgrid(you.pos()) != EMPTY_CLOUD)
+ if (!crawl_state.arena && env.cgrid(you.pos()) != EMPTY_CLOUD)
in_a_cloud();
if (you.level_type == LEVEL_DUNGEON && you.duration[DUR_TELEPATHY])
@@ -3149,7 +3152,7 @@ static void _world_reacts()
viewwindow(true, true);
- if (Options.stash_tracking)
+ if (Options.stash_tracking && !crawl_state.arena)
{
StashTrack.update_visible_stashes(
Options.stash_tracking == STM_ALL ? StashTracker::ST_AGGRESSIVE
@@ -3872,6 +3875,12 @@ static bool _initialise(void)
}
#endif
+ if (crawl_state.arena)
+ {
+ run_arena();
+ end(0, false);
+ }
+
// Sets up a new game.
const bool newc = new_game();
if (!newc)
diff --git a/crawl-ref/source/arena.cc b/crawl-ref/source/arena.cc
new file mode 100644
index 0000000000..95855fc328
--- /dev/null
+++ b/crawl-ref/source/arena.cc
@@ -0,0 +1,450 @@
+#include "AppHdr.h"
+
+#include "externs.h"
+#include "arena.h"
+#include "chardump.h"
+#include "cio.h"
+#include "dungeon.h"
+#include "initfile.h"
+#include "libutil.h"
+#include "maps.h"
+#include "message.h"
+#include "mon-util.h"
+#include "monstuff.h"
+#include "monplace.h"
+#include "output.h"
+#include "skills2.h"
+#include "spl-util.h"
+#include "state.h"
+#include "version.h"
+#include "view.h"
+
+extern void world_reacts();
+
+namespace arena
+{
+ // A faction is just a big list of monsters. Monsters will be dropped
+ // around the appropriate marker.
+ struct faction
+ {
+ std::string desc;
+ mons_list members;
+ bool friendly;
+
+ faction(bool fr) : members(), friendly(fr) { }
+
+ void place_at(const coord_def &pos);
+
+ void clear()
+ {
+ members.clear();
+ }
+ };
+
+ int total_trials = 0;
+
+ int trials_done = 0;
+ int team_a_wins = 0;
+ bool allow_summons = true;
+ faction faction_a(true);
+ faction faction_b(false);
+
+ void adjust_monsters()
+ {
+ if (!allow_summons)
+ {
+ for (int m = 0; m < MAX_MONSTERS; ++m)
+ {
+ monsters *mons(&menv[m]);
+ if (!mons->alive())
+ continue;
+
+ monster_spells &spells(mons->spells);
+ for (int i = 0; i < NUM_MONSTER_SPELL_SLOTS; ++i)
+ {
+ spell_type sp = spells[i];
+ if (spell_typematch(sp, SPTYP_SUMMONING))
+ spells[i] = SPELL_NO_SPELL;
+ }
+ }
+ }
+ }
+
+ void faction::place_at(const coord_def &pos)
+ {
+ ASSERT(in_bounds(pos));
+ for (int i = 0, size = members.size(); i < size; ++i)
+ {
+ mons_spec spec = members.get_monster(i);
+
+ if (friendly)
+ spec.attitude = ATT_FRIENDLY;
+
+ for (int q = 0; q < spec.quantity; ++q)
+ {
+ const coord_def place =
+ find_newmons_square_contiguous(MONS_GIANT_BAT, pos, 6);
+ if (!in_bounds(place))
+ break;
+
+ const int imon = dgn_place_monster(spec, you.your_level,
+ place, false, true, false);
+ if (imon == -1)
+ end(1, false, "Failed to create monster at (%d,%d)",
+ place.x, place.y);
+ }
+ }
+ }
+
+ void center_print(unsigned sz, std::string text, int number = -1)
+ {
+ if (number >= 0)
+ text = make_stringf("(%d) %s", number, text.c_str());
+
+ if (text.length() > sz)
+ text = text.substr(0, sz);
+
+ int padding = (sz - text.length()) / 2 + text.length();
+ cprintf("%*s", padding, text.c_str());
+ }
+
+ void setup_level()
+ {
+ dgn_reset_level();
+
+ for (int x = 0; x < GXM; ++x)
+ for (int y = 0; y < GYM; ++y)
+ grd[x][y] = DNGN_ROCK_WALL;
+
+ unwind_bool gen(Generating_Level, true);
+
+ typedef unwind_var< std::set<std::string> > unwind_stringset;
+
+ const unwind_stringset mtags(you.uniq_map_tags);
+ const unwind_stringset mnames(you.uniq_map_names);
+
+ const map_def *map = random_map_for_tag("arena_level", false);
+ ASSERT(map);
+ dgn_place_map(map, true, true);
+
+ if (!env.rock_colour)
+ env.rock_colour = CYAN;
+ if (!env.floor_colour)
+ env.floor_colour = LIGHTGREY;
+ }
+
+ std::string find_monster_spec()
+ {
+ if (!SysEnv.arena_teams.empty())
+ return (SysEnv.arena_teams);
+ throw std::string("No monsters specified for the arena.");
+ }
+
+ void parse_faction(faction &fact, std::string spec)
+ throw (std::string)
+ {
+ fact.clear();
+ fact.desc = spec;
+
+ std::vector<std::string> monsters = split_string(",", spec);
+ for (int i = 0, size = monsters.size(); i < size; ++i)
+ {
+ const std::string err = fact.members.add_mons(monsters[i], false);
+ if (!err.empty())
+ throw err;
+ }
+ }
+
+ void parse_monster_spec()
+ throw (std::string)
+ {
+ std::string spec = find_monster_spec();
+
+ allow_summons = !strip_tag(spec, "no_summons");
+
+ const int ntrials = strip_number_tag(spec, "t:");
+ if (ntrials != TAG_UNFOUND && ntrials >= 1 && ntrials <= 99
+ && !total_trials)
+ total_trials = ntrials;
+
+ std::vector<std::string> factions = split_string(" v ", spec);
+
+ if (factions.size() == 1)
+ factions = split_string(" vs ", spec);
+
+ if (factions.size() != 2)
+ throw make_stringf("Expected arena monster spec \"xxx v yyy\", "
+ "but got \"%s\"", spec.c_str());
+
+ try
+ {
+ parse_faction(faction_a, factions[0]);
+ parse_faction(faction_b, factions[1]);
+ }
+ catch (const std::string &err)
+ {
+ throw make_stringf("Bad monster spec \"%s\": %s",
+ spec.c_str(),
+ err.c_str());
+ }
+ }
+
+ void setup_monsters()
+ throw (std::string)
+ {
+ unwind_var< FixedVector<bool, NUM_MONSTERS> >
+ uniq(you.unique_creatures);
+
+ parse_monster_spec();
+ coord_def place_a(dgn_find_feature_marker(DNGN_STONE_STAIRS_UP_I));
+ coord_def place_b(dgn_find_feature_marker(DNGN_STONE_STAIRS_DOWN_I));
+ faction_a.place_at(place_a);
+ faction_b.place_at(place_b);
+ adjust_monsters();
+ }
+
+ void show_fight_banner(bool after_fight = false)
+ {
+ int line = 1;
+
+ cgotoxy(1, line++, GOTO_STAT);
+ textcolor(WHITE);
+ center_print(crawl_view.hudsz.x,
+ "Crawl " VER_NUM VER_QUAL " " VERSION_DETAIL);
+ line++;
+
+ cgotoxy(1, line++, GOTO_STAT);
+ textcolor(YELLOW);
+ center_print(crawl_view.hudsz.x, faction_a.desc,
+ total_trials ? team_a_wins : -1);
+ cgotoxy(1, line++, GOTO_STAT);
+ textcolor(LIGHTGREY);
+ center_print(crawl_view.hudsz.x, "vs");
+ cgotoxy(1, line++, GOTO_STAT);
+ textcolor(YELLOW);
+ center_print(crawl_view.hudsz.x, faction_b.desc,
+ total_trials ? trials_done - team_a_wins : -1);
+
+ if (total_trials > 1 && trials_done < total_trials)
+ {
+ cgotoxy(1, line++, GOTO_STAT);
+ textcolor(BROWN);
+ center_print(crawl_view.hudsz.x,
+ make_stringf("Round %d of %d",
+ after_fight ? trials_done
+ : trials_done + 1,
+ total_trials));
+ }
+ else
+ {
+ cgotoxy(1, line++, GOTO_STAT);
+ textcolor(BROWN);
+ clear_to_end_of_line();
+ }
+ }
+
+ void setup_others()
+ {
+ you.species = SP_HUMAN;
+ you.char_class = JOB_FIGHTER;
+ you.experience_level = 27;
+
+ you.mutation[MUT_ACUTE_VISION] = 3;
+
+ coord_def yplace(dgn_find_feature_marker(DNGN_ESCAPE_HATCH_UP));
+ // Fix up the viewport.
+ you.moveto(yplace);
+
+ strcpy(you.your_name, "Arena");
+
+ you.hp = you.hp_max = 99;
+ you.your_level = 20;
+
+ Options.show_gold_turns = false;
+
+ show_fight_banner();
+ }
+
+ void expand_mlist(int exp)
+ {
+ crawl_view.mlistp.y -= exp;
+ crawl_view.mlistsz.y += exp;
+ }
+
+ void setup_fight()
+ throw (std::string)
+ {
+ //no_messages mx;
+ setup_level();
+
+ // Monster set up may block waiting for matchups.
+ setup_monsters();
+
+ setup_others();
+ }
+
+ // Returns true as long as at least one member of each faction is alive.
+ bool fight_is_on()
+ {
+ bool found_friend = false;
+ bool found_enemy = false;
+ for (int i = 0; i < MAX_MONSTERS; ++i)
+ {
+ const monsters *mons(&menv[i]);
+ if (mons->alive())
+ {
+ if (mons->attitude == ATT_FRIENDLY)
+ found_friend = true;
+ else if (mons->attitude == ATT_HOSTILE)
+ found_enemy = true;
+ if (found_friend && found_enemy)
+ return (true);
+ }
+ }
+ return (false);
+ }
+
+ void report_foes()
+ {
+ for (int i = 0; i < MAX_MONSTERS; ++i)
+ {
+ monsters *mons(&menv[i]);
+ if (mons->alive())
+ {
+ 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);
+ }
+ }
+ }
+ }
+
+ 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());
+ }
+ }
+ }
+
+ bool friendlies_win()
+ {
+ for (int i = 0; i < MAX_MONSTERS; ++i)
+ {
+ monsters *mons(&menv[i]);
+ if (mons->alive())
+ return (mons->attitude == ATT_FRIENDLY);
+ }
+ return (false);
+ }
+
+ void do_fight()
+ {
+ mesclr(true);
+ {
+ cursor_control coff(false);
+ while (fight_is_on())
+ {
+ if (kbhit() && getch() == ESCAPE)
+ end(0, false, "Canceled contest at user request");
+
+ viewwindow(true, false);
+ unwind_var<coord_def> pos(you.position);
+ // Move hero offscreen.
+ you.position.y = -1;
+ you.time_taken = 10;
+ //report_foes();
+ world_reacts();
+ delay(Options.arena_delay);
+ mesclr();
+ }
+ viewwindow(true, false);
+ }
+
+ mesclr();
+
+ const bool team_a_won = friendlies_win();
+
+ trials_done++;
+
+ if (team_a_won)
+ team_a_wins++;
+
+ show_fight_banner(true);
+
+ mprf("Winner: %s!",
+ team_a_won ? faction_a.desc.c_str() : faction_b.desc.c_str());
+ }
+
+ void global_setup()
+ {
+ expand_mlist(5);
+ }
+
+ void write_results()
+ {
+ if (FILE *f = fopen("arena.result", "w"))
+ {
+ fprintf(f, "%d-%d\n", team_a_wins, trials_done - team_a_wins);
+ fclose(f);
+ }
+ }
+
+ void write_error(const std::string &error)
+ {
+ if (FILE *f = fopen("arena.result", "w"))
+ {
+ fprintf(f, "err: %s\n", error.c_str());
+ fclose(f);
+ }
+ }
+
+ void simulate()
+ {
+ init_level_connectivity();
+ do
+ {
+ try
+ {
+ setup_fight();
+ }
+ catch (const std::string &error)
+ {
+ write_error(error);
+ end(0, false, "%s", error.c_str());
+ }
+ do_fight();
+
+ if (trials_done < total_trials)
+ delay(Options.arena_delay * 8);
+ } while (trials_done < total_trials);
+
+ if (total_trials > 0)
+ {
+ mprf("Final score: %s (%d); %s (%d)",
+ faction_a.desc.c_str(), team_a_wins,
+ faction_b.desc.c_str(), trials_done - team_a_wins);
+ delay(Options.arena_delay * 8);
+ }
+
+ write_results();
+ }
+}
+
+void run_arena()
+{
+ arena::global_setup();
+ arena::simulate();
+}
diff --git a/crawl-ref/source/arena.h b/crawl-ref/source/arena.h
new file mode 100644
index 0000000000..864e643d24
--- /dev/null
+++ b/crawl-ref/source/arena.h
@@ -0,0 +1,8 @@
+#ifndef ARENA_H
+#define ARENA_H
+
+#include "AppHdr.h"
+
+void run_arena();
+
+#endif
diff --git a/crawl-ref/source/dat/arena.des b/crawl-ref/source/dat/arena.des
new file mode 100644
index 0000000000..1e4a708a83
--- /dev/null
+++ b/crawl-ref/source/dat/arena.des
@@ -0,0 +1,26 @@
+NAME: arena_level
+TAGS: arena_level no_mons_gen
+MARKER: A = feat: stone_stairs_up_i
+MARKER: B = feat: stone_stairs_down_i
+MARKER: O = feat: escape_hatch_up
+SUBST: A = ., B = ., O = .
+ORIENT: encompass
+MAP
+XXXXXXXXXXXXXXXXX
+X...............X
+X.......B.......X
+X...............X
+X...............X
+X...............X
+X...............X
+X...............X
+X.......O.......X
+X...............X
+X...............X
+X...............X
+X...............X
+X...............X
+X.......A.......X
+X...............X
+XXXXXXXXXXXXXXXXX
+ENDMAP
diff --git a/crawl-ref/source/dat/clua/loadmaps.lua b/crawl-ref/source/dat/clua/loadmaps.lua
index fcabf8907d..e5396aef14 100644
--- a/crawl-ref/source/dat/clua/loadmaps.lua
+++ b/crawl-ref/source/dat/clua/loadmaps.lua
@@ -13,6 +13,8 @@ local des_files = {
-- Example vaults, included here so that Crawl will syntax-check them
"didact.des",
+ "arena.des",
+
"altar.des", "bazaar.des", "entry.des", "elf.des", "float.des", "hells.des",
"hive.des", "icecave.des", "lab.des", "lair.des", "large.des", "layout.des",
"mini.des", "minitomb.des", "orc.des", "pan.des", "sewer.des", "temple.des",
diff --git a/crawl-ref/source/directn.h b/crawl-ref/source/directn.h
index 3d95e9f8d7..1759496612 100644
--- a/crawl-ref/source/directn.h
+++ b/crawl-ref/source/directn.h
@@ -74,6 +74,11 @@ public:
return viewp + viewhalfsz;
}
+ coord_def glosc() const
+ {
+ return (glos1 + glos2) / 2;
+ }
+
bool in_grid_los(const coord_def &c) const
{
return (c.x >= glos1.x && c.x <= glos2.x
diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc
index ed876851e6..b16ec0e371 100644
--- a/crawl-ref/source/dungeon.cc
+++ b/crawl-ref/source/dungeon.cc
@@ -86,7 +86,6 @@ coord_def spec_room::random_spot() const
// DUNGEON BUILDERS
static void _build_dungeon_level(int level_number, int level_type);
-static void _reset_level();
static bool _valid_dungeon_level(int level_number, int level_type);
static bool _find_in_area(int sx, int sy, int ex, int ey,
@@ -296,7 +295,7 @@ bool builder(int level_number, int level_type)
mapgen_report_map_build_start();
#endif
- _reset_level();
+ dgn_reset_level();
// If we're getting low on available retries, disable random vaults
// and minivaults (special levels will still be placed).
@@ -885,7 +884,7 @@ static bool _valid_dungeon_level(int level_number, int level_type)
return (true);
}
-static void _reset_level()
+void dgn_reset_level()
{
dgn_level_vetoed = false;
Level_Unique_Maps.clear();
@@ -4218,7 +4217,7 @@ bool dgn_place_map(const map_def *mdef, bool clobber, bool make_no_exits,
{
// For encompass maps, clear the entire level.
unwind_bool levgen(Generating_Level, true);
- _reset_level();
+ dgn_reset_level();
dungeon_events.clear();
const bool res = dgn_place_map(mdef, clobber, make_no_exits,
where);
@@ -4629,9 +4628,9 @@ static void _dgn_give_mon_spec_items(mons_spec &mspec,
}
-bool dgn_place_monster(mons_spec &mspec,
- int monster_level, const coord_def& where,
- bool force_pos, bool generate_awake, bool patrolling)
+int dgn_place_monster(mons_spec &mspec,
+ int monster_level, const coord_def& where,
+ bool force_pos, bool generate_awake, bool patrolling)
{
if (mspec.mid != -1)
{
@@ -4655,8 +4654,11 @@ bool dgn_place_monster(mons_spec &mspec,
{
// Don't place a unique monster a second time.
// (Boris is handled specially.)
- if (mons_is_unique(mid) && you.unique_creatures[mid])
- return (false);
+ if (mons_is_unique(mid) && you.unique_creatures[mid]
+ && !crawl_state.arena)
+ {
+ return (-1);
+ }
const int montype = mons_class_is_zombified(mid) ? mspec.monbase
: mid;
@@ -4701,9 +4703,31 @@ bool dgn_place_monster(mons_spec &mspec,
mg.power = monster_level;
mg.behaviour = (m_generate_awake) ? BEH_WANDER : BEH_SLEEP;
+ switch (mspec.attitude)
+ {
+ case ATT_FRIENDLY:
+ mg.behaviour = BEH_FRIENDLY;
+ break;
+ case ATT_NEUTRAL:
+ mg.behaviour = BEH_NEUTRAL;
+ break;
+ case ATT_GOOD_NEUTRAL:
+ mg.behaviour = BEH_GOOD_NEUTRAL;
+ break;
+ default:
+ break;
+ }
mg.base_type = mspec.monbase;
mg.number = mspec.number;
mg.colour = mspec.colour;
+
+ coord_def place(where);
+ if (!force_pos && mgrd(place) != NON_MONSTER
+ && mg.cls != RANDOM_MONSTER && mg.cls < NUM_MONSTERS)
+ {
+ place = find_newmons_square_contiguous(mg.cls, where, 6);
+ }
+
mg.pos = where;
if (mons_class_is_zombified(mg.base_type))
@@ -4723,9 +4747,9 @@ bool dgn_place_monster(mons_spec &mspec,
const int mindex = place_monster(mg, true);
if (mindex != -1 && mspec.items.size() > 0)
_dgn_give_mon_spec_items(mspec, mindex, mid, monster_level);
- return (mindex != -1);
+ return (mindex);
}
- return (false);
+ return (-1);
}
static bool _dgn_place_monster( const vault_placement &place, mons_spec &mspec,
@@ -4737,8 +4761,8 @@ static bool _dgn_place_monster( const vault_placement &place, mons_spec &mspec,
const bool patrolling
= mspec.patrolling || place.map.has_tag("patrolling");
- return dgn_place_monster(mspec, monster_level, where, false,
- generate_awake, patrolling);
+ return (-1 != dgn_place_monster(mspec, monster_level, where, false,
+ generate_awake, patrolling));
}
static bool _dgn_place_one_monster( const vault_placement &place,
@@ -7702,7 +7726,7 @@ static coord_def _dgn_find_closest_to_stone_stairs(coord_def base_pos)
return (np.nearest);
}
-static coord_def _dgn_find_feature_marker(dungeon_feature_type feat)
+coord_def dgn_find_feature_marker(dungeon_feature_type feat)
{
std::vector<map_marker*> markers = env.markers.get_all();
for (int i = 0, size = markers.size(); i < size; ++i)
@@ -7720,7 +7744,7 @@ static coord_def _dgn_find_feature_marker(dungeon_feature_type feat)
static coord_def _dgn_find_labyrinth_entry_point()
{
- return (_dgn_find_feature_marker(DNGN_ENTER_LABYRINTH));
+ return (dgn_find_feature_marker(DNGN_ENTER_LABYRINTH));
}
coord_def dgn_find_nearby_stair(dungeon_feature_type stair_to_find,
@@ -7736,7 +7760,7 @@ coord_def dgn_find_nearby_stair(dungeon_feature_type stair_to_find,
if (stair_to_find == DNGN_EXIT_PORTAL_VAULT)
{
- const coord_def pos(_dgn_find_feature_marker(stair_to_find));
+ const coord_def pos(dgn_find_feature_marker(stair_to_find));
if (in_bounds(pos))
{
if (map_marker *marker = env.markers.find(pos, MAT_FEATURE))
@@ -7761,7 +7785,7 @@ coord_def dgn_find_nearby_stair(dungeon_feature_type stair_to_find,
if (stair_to_find == DNGN_STONE_ARCH)
{
- const coord_def pos(_dgn_find_feature_marker(stair_to_find));
+ const coord_def pos(dgn_find_feature_marker(stair_to_find));
if (in_bounds(pos) && grd(pos) == stair_to_find)
return (pos);
}
@@ -7781,7 +7805,7 @@ coord_def dgn_find_nearby_stair(dungeon_feature_type stair_to_find,
if (stair_to_find == your_branch().exit_stairs)
{
- const coord_def pos(_dgn_find_feature_marker(DNGN_STONE_STAIRS_UP_I));
+ const coord_def pos(dgn_find_feature_marker(DNGN_STONE_STAIRS_UP_I));
if (in_bounds(pos) && grd(pos) == stair_to_find)
return (pos);
}
@@ -7922,7 +7946,7 @@ coord_def dgn_find_nearby_stair(dungeon_feature_type stair_to_find,
}
// Last attempt: look for marker.
- const coord_def pos(_dgn_find_feature_marker(stair_to_find));
+ const coord_def pos(dgn_find_feature_marker(stair_to_find));
if (in_bounds(pos))
return (pos);
diff --git a/crawl-ref/source/dungeon.h b/crawl-ref/source/dungeon.h
index bcfa1d6d16..04c84cdfd3 100644
--- a/crawl-ref/source/dungeon.h
+++ b/crawl-ref/source/dungeon.h
@@ -324,6 +324,8 @@ void write_level_connectivity(writer &th);
bool builder(int level_number, int level_type);
+coord_def dgn_find_feature_marker(dungeon_feature_type feat);
+
// Set floor/wall colour based on the mons_alloc array. Used for
// Abyss and Pan.
void dgn_set_colours_from_monsters();
@@ -344,10 +346,10 @@ coord_def dgn_find_nearby_stair(dungeon_feature_type stair_to_find,
coord_def base_pos, bool find_closest);
class mons_spec;
-bool dgn_place_monster(mons_spec &mspec,
- int monster_level, const coord_def& where,
- bool force_pos = false, bool generate_awake = false,
- bool patrolling = false);
+int dgn_place_monster(mons_spec &mspec,
+ int monster_level, const coord_def& where,
+ bool force_pos = false, bool generate_awake = false,
+ bool patrolling = false);
class item_list;
void dgn_place_multiple_items(item_list &list,
@@ -360,6 +362,8 @@ bool unset_level_flags(unsigned long flags, bool silent = false);
void dgn_set_lt_callback(std::string level_type_name,
std::string callback_name);
+void dgn_reset_level();
+
// Returns true if the given square is okay for use by any character,
// but always false for squares in non-transparent vaults. This
// function returns sane results only immediately after dungeon generation
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index 97c91451fb..30d890de26 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -2022,6 +2022,8 @@ public:
bool pickup_dropped; // Pickup dropped objects
int travel_delay; // How long to pause between travel moves
+ int arena_delay;
+
// Messages that stop travel
std::vector<message_filter> travel_stop_message;
std::vector<message_filter> force_more_message;
diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc
index 1f9c08369e..9f8a75d8ea 100644
--- a/crawl-ref/source/fight.cc
+++ b/crawl-ref/source/fight.cc
@@ -51,6 +51,7 @@
#include "spells4.h"
#include "spl-mis.h"
#include "spl-util.h"
+#include "state.h"
#include "stuff.h"
#include "transfor.h"
#include "traps.h"
@@ -369,9 +370,10 @@ void melee_attack::init_attack()
defender_shield = defender->shield();
water_attack = is_water_attack(attacker, defender);
- attacker_visible = attacker->visible();
+ attacker_visible = attacker->visible() || crawl_state.arena;
attacker_invisible = (!attacker_visible && see_grid(attacker->pos()));
- defender_visible = (defender && defender->visible());
+ defender_visible = (defender &&
+ (defender->visible() || crawl_state.arena));
defender_invisible = (!defender_visible && defender
&& see_grid(defender->pos()));
needs_message = (attacker_visible || defender_visible);
diff --git a/crawl-ref/source/initfile.cc b/crawl-ref/source/initfile.cc
index 5032753e8b..7cfcbe5c3e 100644
--- a/crawl-ref/source/initfile.cc
+++ b/crawl-ref/source/initfile.cc
@@ -710,6 +710,8 @@ void game_options::reset_options()
travel_delay = 20;
travel_stair_cost = 500;
+ arena_delay = 600;
+
// Sort only pickup menus by default.
sort_menus.clear();
set_menu_sort("pickup: true");
@@ -3280,6 +3282,7 @@ enum commandline_option_type {
CLO_MORGUE,
CLO_MACRO,
CLO_MAPSTAT,
+ CLO_ARENA,
CLO_NOPS
};
@@ -3287,7 +3290,7 @@ enum commandline_option_type {
static const char *cmd_ops[] = {
"scores", "name", "race", "class", "pizza", "plain", "dir", "rc",
"rcdir", "tscores", "vscores", "scorefile", "morgue", "macro",
- "mapstat"
+ "mapstat", "arena"
};
const int num_cmd_ops = CLO_NOPS;
@@ -3421,6 +3424,15 @@ bool parse_args( int argc, char **argv, bool rc_only )
SysEnv.map_gen_iters = 100;
break;
+ case CLO_ARENA:
+ crawl_state.arena = true;
+ if (next_is_param)
+ {
+ SysEnv.arena_teams = next_arg;
+ nextUsed = true;
+ }
+ break;
+
case CLO_MACRO:
if (!next_is_param)
return (false);
diff --git a/crawl-ref/source/initfile.h b/crawl-ref/source/initfile.h
index eae3c3d03c..471eba7387 100644
--- a/crawl-ref/source/initfile.h
+++ b/crawl-ref/source/initfile.h
@@ -74,6 +74,8 @@ public:
int map_gen_iters;
+ std::string arena_teams;
+
public:
void add_rcdir(const std::string &dir);
};
diff --git a/crawl-ref/source/makefile.obj b/crawl-ref/source/makefile.obj
index dc1bce8539..8e02163420 100644
--- a/crawl-ref/source/makefile.obj
+++ b/crawl-ref/source/makefile.obj
@@ -4,6 +4,7 @@ OBJECTS = \
abl-show.o \
abyss.o \
acr.o \
+arena.o \
beam.o \
branch.o \
chardump.o \
diff --git a/crawl-ref/source/mapdef.cc b/crawl-ref/source/mapdef.cc
index af02c2b429..f9b0c14001 100644
--- a/crawl-ref/source/mapdef.cc
+++ b/crawl-ref/source/mapdef.cc
@@ -2090,6 +2090,22 @@ mons_list::mons_spec_slot mons_list::parse_mons_spec(std::string spec)
mspec.patrolling = strip_tag(mon_str, "patrolling");
mspec.band = strip_tag(mon_str, "band");
+ if (!mon_str.empty() && isdigit(mon_str[0]))
+ {
+ // Look for space after initial digits.
+ std::string::size_type pos =
+ mon_str.find_first_not_of("0123456789");
+ if (pos != std::string::npos && mon_str[pos] == ' ')
+ {
+ const std::string mcount = mon_str.substr(0, pos);
+ const int count = atoi(mcount.c_str());
+ if (count >= 1 && count <= 99)
+ mspec.quantity = count;
+
+ mon_str = mon_str.substr(pos);
+ }
+ }
+
// place:Elf:7 to choose monsters appropriate for that level,
// for example.
const std::string place = strip_tag_prefix(mon_str, "place:");
@@ -2179,8 +2195,9 @@ mons_list::mons_spec_slot mons_list::parse_mons_spec(std::string spec)
}
else if (mons_class_itemuse(mid) < MONUSE_STARTING_EQUIPMENT)
{
- error = make_stringf("Monster '%s' can't use items.",
- mon_str.c_str());
+ if (mid != MONS_DANCING_WEAPON || mspec.items.size() > 1)
+ error = make_stringf("Monster '%s' can't use items.",
+ mon_str.c_str());
}
}
diff --git a/crawl-ref/source/mapdef.h b/crawl-ref/source/mapdef.h
index 2d43e59519..faca8b7c0a 100644
--- a/crawl-ref/source/mapdef.h
+++ b/crawl-ref/source/mapdef.h
@@ -417,7 +417,9 @@ class mons_spec
int mid;
level_id place;
monster_type monbase; // Base monster for zombies and dracs.
+ mon_attitude_type attitude;
int number; // Head count for hydras
+ int quantity; // Number of monsters (usually 1).
int genweight, mlevel;
bool fix_mons;
bool generate_awake;
@@ -432,9 +434,10 @@ class mons_spec
int num = 0,
int gw = 10, int ml = 0,
bool _fixmons = false, bool awaken = false, bool patrol = false)
- : mid(id), place(), monbase(base), number(num), genweight(gw),
- mlevel(ml), fix_mons(_fixmons), generate_awake(awaken),
- patrolling(false), band(false), colour(BLACK), items()
+ : mid(id), place(), monbase(base), attitude(ATT_HOSTILE), number(num),
+ quantity(1), genweight(gw), mlevel(ml), fix_mons(_fixmons),
+ generate_awake(awaken), patrolling(false), band(false),
+ colour(BLACK), items()
{
}
};
diff --git a/crawl-ref/source/message.cc b/crawl-ref/source/message.cc
index f47545b7a1..1efdc0f2a5 100644
--- a/crawl-ref/source/message.cc
+++ b/crawl-ref/source/message.cc
@@ -909,6 +909,13 @@ void more(void)
}
#endif
+ if (crawl_state.arena)
+ {
+ delay(Options.arena_delay);
+ mesclr();
+ return;
+ }
+
if (crawl_state.is_replaying_keys() || autoclear_more)
{
mesclr();
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 9314094e1f..2ac2063a78 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -46,6 +46,7 @@
#include "shopping.h" // for item values
#include "spells3.h"
#include "spl-util.h"
+#include "state.h"
#include "stuff.h"
#include "terrain.h"
#include "tiles.h"
@@ -1972,15 +1973,14 @@ static std::string _str_monam(const monsters& mon, description_level_type desc,
// (Uniques don't get this, because their names are proper nouns.)
if (!mons_is_unique(mon.type))
{
+ const bool use_your = !crawl_state.arena && mons_friendly(&mon);
switch (desc)
{
case DESC_CAP_THE:
- result = (mons_friendly(&mon) ? "Your "
- : "The ");
+ result = (use_your ? "Your " : "The ");
break;
case DESC_NOCAP_THE:
- result = (mons_friendly(&mon) ? "your "
- : "the ");
+ result = (use_your ? "your " : "the ");
break;
case DESC_CAP_A:
result = "A ";
@@ -7870,7 +7870,9 @@ std::string do_mon_str_replacements(const std::string &in_msg,
msg = replace_all(msg, "@the_monster@", name);
msg = replace_all(msg, "@The_monster@", name);
}
- else if (monster->attitude == ATT_FRIENDLY && !mons_is_unique(monster->type)
+ else if (monster->attitude == ATT_FRIENDLY
+ && !mons_is_unique(monster->type)
+ && !crawl_state.arena
&& player_monster_visible(monster))
{
nocap = DESC_PLAIN;
diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc
index ad7701530e..a9bfdeb5f8 100644
--- a/crawl-ref/source/monplace.cc
+++ b/crawl-ref/source/monplace.cc
@@ -23,6 +23,7 @@
#include "mon-util.h"
#include "player.h"
#include "religion.h"
+#include "state.h"
#include "stuff.h"
#include "spells4.h"
#include "terrain.h"
@@ -226,6 +227,9 @@ static void _hell_spawn_random_monsters()
// one_chance_in(value) checks with the new x_chance_in_y(5, value). (jpeg)
void spawn_random_monsters()
{
+ if (crawl_state.arena)
+ return;
+
#ifdef DEBUG_MON_CREATION
mpr("in spawn_random_monsters()", MSGCH_DIAGNOSTICS);
#endif
diff --git a/crawl-ref/source/monspeak.cc b/crawl-ref/source/monspeak.cc
index 2619563f2b..86de314347 100644
--- a/crawl-ref/source/monspeak.cc
+++ b/crawl-ref/source/monspeak.cc
@@ -36,6 +36,7 @@
#include "religion.h"
#include "spells2.h"
#include "spells4.h"
+#include "state.h"
#include "stuff.h"
#include "view.h"
@@ -266,7 +267,7 @@ bool mons_speaks(const monsters *monster)
prefixes.push_back("neutral");
}
- else if (mons_friendly(monster))
+ else if (mons_friendly(monster) && !crawl_state.arena)
prefixes.push_back("friendly");
else
prefixes.push_back("hostile");
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index ea3118f5ec..f630cbeb59 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -509,7 +509,8 @@ static void _give_adjusted_experience(monsters *monster, killer_type killer,
// Give a message for monsters dying out of sight.
if (need_xp_msg && exp_gain > 0
- && (!mons_near(monster) || !you.can_see(monster)))
+ && (!mons_near(monster) || !you.can_see(monster))
+ && !crawl_state.arena)
{
mpr("You feel a bit more experienced.");
}
@@ -3403,6 +3404,41 @@ static bool _handle_monster_patrolling(monsters *mon)
return (false);
}
+static void _arena_set_foe(monsters *mons)
+{
+ const int mind = monster_index(mons);
+
+ int nearest = -1;
+ int best_distance = -1;
+ for (int i = 0; i < MAX_MONSTERS; ++i)
+ {
+ if (mind == i)
+ continue;
+
+ const monsters *other(&menv[i]);
+ if (!other->alive() || mons_aligned(mind, i))
+ continue;
+
+ const int distance = grid_distance(mons->pos(), other->pos());
+ if (best_distance == -1 || distance < best_distance)
+ {
+ best_distance = distance;
+ nearest = i;
+ }
+ }
+
+ if (nearest != -1)
+ {
+ mons->foe = nearest;
+ mons->target = menv[nearest].pos();
+ }
+ else
+ {
+ mons->foe = MHITNOT;
+ mons->target = mons->pos();
+ }
+}
+
//---------------------------------------------------------------
//
// handle_behaviour
@@ -3441,6 +3477,7 @@ static void _handle_behaviour(monsters *mon)
bool patrolling = mon->is_patrolling();
static std::vector<level_exit> e;
static int e_index = -1;
+
// Check for confusion -- early out.
if (mon->has_ench(ENCH_CONFUSION))
{
@@ -3448,6 +3485,15 @@ static void _handle_behaviour(monsters *mon)
return;
}
+ if (crawl_state.arena)
+ {
+ if (!mon->get_foe() || one_chance_in(3))
+ mon->foe = MHITNOT;
+ if (mon->foe == MHITNOT || mon->foe == MHITYOU)
+ _arena_set_foe(mon);
+ return;
+ }
+
if (mons_wall_shielded(mon) && grid_is_solid(mon->pos()))
{
// Monster is safe, so it's behaviour can be simplified to fleeing.
@@ -4060,7 +4106,7 @@ bool simple_monster_message(const monsters *monster, const char *event,
description_level_type descrip)
{
- if (mons_near( monster )
+ if ((mons_near( monster ) || crawl_state.arena)
&& (channel == MSGCH_MONSTER_SPELL || channel == MSGCH_FRIEND_SPELL
|| player_monster_visible(monster)))
{
@@ -4250,7 +4296,9 @@ static void _handle_movement(monsters *monster)
delta = you.pos() - monster->pos();
}
else
+ {
delta = monster->target - monster->pos();
+ }
// Move the monster.
mmov.x = (delta.x > 0) ? 1 : ((delta.x < 0) ? -1 : 0);
@@ -6526,6 +6574,7 @@ static void _handle_monster_move(int i, monsters *monster)
}
_handle_behaviour(monster);
+ ASSERT(!crawl_state.arena || monster->foe != MHITYOU);
// Submerging monsters will hide from clouds.
if (cloud_num != EMPTY_CLOUD && _mons_avoids_cloud(monster, cl_type)
diff --git a/crawl-ref/source/mstuff2.cc b/crawl-ref/source/mstuff2.cc
index 90e32f49e6..bb70bb8907 100644
--- a/crawl-ref/source/mstuff2.cc
+++ b/crawl-ref/source/mstuff2.cc
@@ -166,10 +166,6 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast,
// Targeted spells need a valid target.
ASSERT(!(flags & SPFLAG_TARGETING_MASK) || in_bounds(pbolt.target));
-
- // Don't target harmful spells at self unless confused.
- ASSERT(monster->pos() != pbolt.target || monster->confused()
- || (flags & (SPFLAG_HELPFUL | SPFLAG_ESCAPE | SPFLAG_RECOVERY)));
#endif
if (do_noise)
diff --git a/crawl-ref/source/output.cc b/crawl-ref/source/output.cc
index 22a9e1a186..b9ebfd1c6a 100644
--- a/crawl-ref/source/output.cc
+++ b/crawl-ref/source/output.cc
@@ -1500,6 +1500,9 @@ void get_monster_pane_info(std::vector<monster_pane_info>& mons)
// they have to be consolidated, and 1 otherwise.
int update_monster_pane()
{
+ if (!map_bounds(you.pos()))
+ return (-1);
+
const int max_print = crawl_view.mlistsz.y;
textbackground(BLACK);
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index f04a9e4094..1bc4a67654 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -2919,6 +2919,9 @@ void forget_map(unsigned char chance_forgotten, bool force)
void gain_exp( unsigned int exp_gained, unsigned int* actual_gain,
unsigned int* actual_avail_gain)
{
+ if (crawl_state.arena)
+ return;
+
if (player_equip_ego_type( EQ_BODY_ARMOUR, SPARM_ARCHMAGI ))
exp_gained = div_rand_round( exp_gained, 4 );
@@ -6941,6 +6944,9 @@ bool player::visible_to(const actor *looker) const
bool player::can_see(const actor *target) const
{
+ if (crawl_state.arena)
+ return target->visible_to(this);
+
if (this == target)
return visible_to(target);
diff --git a/crawl-ref/source/state.cc b/crawl-ref/source/state.cc
index f6eafa288b..d076bc8ebf 100644
--- a/crawl-ref/source/state.cc
+++ b/crawl-ref/source/state.cc
@@ -25,7 +25,7 @@ game_state::game_state()
: mouse_enabled(false), waiting_for_command(false),
terminal_resized(false), io_inited(false), need_save(false),
saving_game(false), updating_scores(false), seen_hups(0),
- map_stat_gen(false), unicode_ok(false), glyph2strfn(NULL),
+ map_stat_gen(false), arena(false), unicode_ok(false), glyph2strfn(NULL),
multibyte_strlen(NULL), terminal_resize_handler(NULL),
terminal_resize_check(NULL), doing_prev_cmd_again(false),
prev_cmd(CMD_NO_CMD), repeat_cmd(CMD_NO_CMD), cmd_repeat_count(0),
diff --git a/crawl-ref/source/state.h b/crawl-ref/source/state.h
index 24c4fc45b8..fe8ab01938 100644
--- a/crawl-ref/source/state.h
+++ b/crawl-ref/source/state.h
@@ -42,6 +42,8 @@ struct game_state
bool map_stat_gen; // Set if we're generating stats on maps.
+ bool arena; // Set if we're in arena mode.
+
bool unicode_ok; // Is unicode support available?
std::string (*glyph2strfn)(unsigned glyph);
diff --git a/crawl-ref/source/stuff.cc b/crawl-ref/source/stuff.cc
index ee9a82986b..320fb7c66f 100644
--- a/crawl-ref/source/stuff.cc
+++ b/crawl-ref/source/stuff.cc
@@ -766,7 +766,7 @@ void end(int exit_code, bool print_error, const char *format, ...)
}
#if defined(WIN32CONSOLE) || defined(DOS) || defined(DGL_PAUSE_AFTER_ERROR)
- if (exit_code)
+ if (exit_code && !crawl_state.arena)
{
fprintf(stderr, "Hit Enter to continue...\n");
getchar();
diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc
index 93a918605d..ce20205bca 100644
--- a/crawl-ref/source/view.cc
+++ b/crawl-ref/source/view.cc
@@ -202,6 +202,8 @@ void set_envmap_col( int x, int y, int colour )
bool is_sanctuary(const coord_def& p)
{
+ if (!map_bounds(p))
+ return (false);
return (testbits(env.map(p).property, FPROP_SANCTUARY_1)
|| testbits(env.map(p).property, FPROP_SANCTUARY_2));
}
@@ -1183,7 +1185,7 @@ void force_monster_shout(monsters* monster)
inline static bool _update_monster_grid(const monsters *monster)
{
- const coord_def e = monster->pos() - you.pos() + coord_def(9,9);
+ const coord_def e = monster->pos() - crawl_view.glosc() + coord_def(9,9);
if (!player_monster_visible( monster ))
{
@@ -1476,11 +1478,13 @@ inline static void _update_item_grid(const coord_def &gp, const coord_def &ep)
void item_grid()
{
- for (radius_iterator ri(you.pos(), LOS_RADIUS, true, false); ri; ++ri)
+ const coord_def c(crawl_view.glosc());
+ for (radius_iterator ri(c, LOS_RADIUS, true, false);
+ ri; ++ri)
{
if (igrd(*ri) != NON_ITEM)
{
- const coord_def ep = *ri - you.pos() + coord_def(9, 9);
+ const coord_def ep = *ri - c + coord_def(9, 9);
if (env.show(ep))
_update_item_grid(*ri, ep);
}
@@ -1505,7 +1509,8 @@ void get_mons_glyph( const monsters *mons, unsigned *glych,
inline static void _update_cloud_grid(int cloudno)
{
int which_colour = LIGHTGREY;
- const coord_def e = env.cloud[cloudno].pos - you.pos() + coord_def(9,9);
+ const coord_def e = env.cloud[cloudno].pos - crawl_view.glosc()
+ + coord_def(9,9);
switch (env.cloud[cloudno].type)
{
@@ -2813,6 +2818,18 @@ void losight(env_show_grid &sh,
// clear out sh
sh.init(0);
+ if (crawl_state.arena)
+ {
+ for (int y = -ENV_SHOW_OFFSET; y <= ENV_SHOW_OFFSET; ++y)
+ for (int x = -ENV_SHOW_OFFSET; x <= ENV_SHOW_OFFSET; ++x)
+ {
+ const coord_def pos = center + coord_def(x, y);
+ if (map_bounds(pos))
+ sh[x + sh_xo][y + sh_yo] = gr(pos);
+ }
+ return;
+ }
+
const unsigned int num_cellrays = compressed_ray_x.size();
const unsigned int num_words = (num_cellrays + LONGSIZE - 1) / LONGSIZE;
@@ -3912,6 +3929,9 @@ bool mons_near(const monsters *monster, unsigned short foe)
if (foe == MHITYOU)
{
+ if (crawl_state.arena)
+ return (true);
+
if ( grid_distance(monster->pos(), you.pos()) <= LOS_RADIUS )
{
const coord_def diff = monster->pos() - you.pos() + coord_def(9,9);
@@ -3971,7 +3991,8 @@ bool see_grid( const env_show_grid &show,
// Answers the question: "Is a grid within character's line of sight?"
bool see_grid( const coord_def &p )
{
- return see_grid(env.show, you.pos(), p);
+ return (crawl_state.arena && crawl_view.in_grid_los(p))
+ || see_grid(env.show, you.pos(), p);
}
// Answers the question: "Would a grid be within character's line of sight,
@@ -4932,8 +4953,11 @@ static void _update_env_show(const coord_def &gp, const coord_def &ep)
_update_item_grid(gp, ep);
const int cloud = env.cgrid(gp);
- if (cloud != EMPTY_CLOUD && env.cloud[cloud].type != CLOUD_NONE)
+ if (cloud != EMPTY_CLOUD && env.cloud[cloud].type != CLOUD_NONE
+ && env.cloud[cloud].pos == gp)
+ {
_update_cloud_grid(cloud);
+ }
const monsters *mons = monster_at(gp);
if (mons && mons->alive())
@@ -5064,11 +5088,14 @@ void viewwindow(bool draw_it, bool do_updates)
int count_x, count_y;
- losight( env.show, grd, you.pos() ); // Must be done first.
+ if (map_bounds(you.pos()))
+ {
+ losight( env.show, grd, you.pos() ); // Must be done first.
- // What would be visible, if all of the translucent walls were
- // made opaque.
- losight( env.no_trans_show, grd, you.pos(), true );
+ // What would be visible, if all of the translucent walls were
+ // made opaque.
+ losight( env.no_trans_show, grd, you.pos(), true );
+ }
#ifdef USE_TILE
tile_draw_floor();
@@ -5180,7 +5207,7 @@ void viewwindow(bool draw_it, bool do_updates)
tileb[bufcount + 1] = bg | tile_unseen_flag(gc);
#endif
}
- else if (gc == you.pos())
+ else if (gc == you.pos() && !crawl_state.arena)
{
int object = env.show(ep);
unsigned short colour = env.show_col(ep);