summaryrefslogtreecommitdiffstats
path: root/crawl-ref
diff options
context:
space:
mode:
authorj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2008-06-24 22:16:50 +0000
committerj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2008-06-24 22:16:50 +0000
commit7ee1dfa39e789e7b631ff2883ee32b70b104a429 (patch)
tree384b9658812feaacf8951d6a12040e6d01f2f9b5 /crawl-ref
parentdefa394ffdf8aac28836530ed7b31455a8059345 (diff)
downloadcrawl-ref-7ee1dfa39e789e7b631ff2883ee32b70b104a429.tar.gz
crawl-ref-7ee1dfa39e789e7b631ff2883ee32b70b104a429.zip
Apply patch 1952761 by jarpian (wasp): targetting with the monster list.
I've updated the patch to the current mlist code, but there are still a couple of bugs that will need to be ironed out. For example, monsters are picked by comparing their attitude and type, which is not sufficient in the case of (non-collapsed) zombies, as well as mimics or ghosts. Also if the number of monsters in the visible list is greater than its rows (because some appear in the same row) then monsters outside of the visible list can be targetted. I guess this is an unintended feature. :) I'm certain there'll be more bugs, though. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@6129 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref')
-rw-r--r--crawl-ref/docs/crawl_manual.txt3
-rw-r--r--crawl-ref/source/command.cc3
-rw-r--r--crawl-ref/source/directn.cc136
-rw-r--r--crawl-ref/source/enum.h12
-rw-r--r--crawl-ref/source/externs.h1
-rw-r--r--crawl-ref/source/initfile.cc1
-rw-r--r--crawl-ref/source/output.cc120
-rw-r--r--crawl-ref/source/output.h25
-rw-r--r--crawl-ref/source/view.cc3
9 files changed, 237 insertions, 67 deletions
diff --git a/crawl-ref/docs/crawl_manual.txt b/crawl-ref/docs/crawl_manual.txt
index b9a2ca99db..1efc4ac2fa 100644
--- a/crawl-ref/docs/crawl_manual.txt
+++ b/crawl-ref/docs/crawl_manual.txt
@@ -250,7 +250,8 @@ can be subtle, and a full list with explanations is given in Appendix 5.
Monsters within your field of vision are listed on a special panel, the
monster list. Single monsters also get indicators of their health status
in the form of a coloured box, and also on effects they enjoy or suffer
-from.
+from. Within target mode you can directly target single monsters by use
+of the monster list. Use Ctrl-L to toggle this on or off.
Sometimes characters will be able to use special abilities, e.g. the
Naga's ability to spit poison, or the magical power to turn invisible
diff --git a/crawl-ref/source/command.cc b/crawl-ref/source/command.cc
index 24a11729ec..0365448d36 100644
--- a/crawl-ref/source/command.cc
+++ b/crawl-ref/source/command.cc
@@ -729,6 +729,9 @@ static const char *targeting_help_1 =
"<w><<</w>/<w>></w> : cycle through up/down stairs\n"
"<w>Tab</w> : cycle through shops and portals\n"
"<w>Ctrl-F</w> : change monster targeting mode\n"
+#ifndef USE_TILE
+ "<w>Ctrl-L</w> : toggle targetting via monster list\n"
+#endif
"<w>Ctrl-P</w> : repeat prompt\n"
" \n"
"<h>Targeting (zapping wands, casting spells, etc.):\n"
diff --git a/crawl-ref/source/directn.cc b/crawl-ref/source/directn.cc
index 2f86f47638..69f547e24f 100644
--- a/crawl-ref/source/directn.cc
+++ b/crawl-ref/source/directn.cc
@@ -58,6 +58,7 @@
#include "travel.h"
#include "tutorial.h"
#include "view.h"
+#include "output.h"
#include "macro.h"
@@ -91,6 +92,10 @@ static bool _find_object( int x, int y, int mode, bool need_path, int range );
static bool _find_monster( int x, int y, int mode, bool need_path, int range );
static bool _find_feature( int x, int y, int mode, bool need_path, int range );
+#ifndef USE_TILE
+static bool _find_mlist( int x, int y, int mode, bool need_path, int range );
+#endif
+
static char _find_square_wrapper( int tx, int ty,
FixedVector<char, 2> &mfp, char direction,
bool (*targ)(int, int, int, bool, int),
@@ -433,7 +438,31 @@ static void direction_again(dist& moves, targeting_type restricts,
// tx,ty target x,y
// dx,dy direction delta for DIR_DIR
//
-//---------------------------------------------------------------
+//--------------------------------------------------------------
+
+#ifndef USE_TILE
+// XXX: Hack - can't pass mlist entries into _find_mlist().
+std::vector<monster_pane_info> mlist;
+static void _fill_monster_list(void)
+{
+ std::vector<monster_pane_info> temp;
+ get_monster_pane_info(temp);
+
+ // Get the unique entries.
+ mlist.clear();
+ int start = 0, end = 1;
+ while (start < (int) temp.size())
+ {
+ mlist.push_back(temp[start]);
+ for (end = start + 1; end < (int) temp.size(); ++end)
+ if (monster_pane_info::less_than(temp[start], temp[end]))
+ break;
+
+ start = end;
+ }
+}
+#endif
+
void direction(dist& moves, targeting_type restricts,
targ_mode_type mode, int range, bool just_looking,
bool needs_path, const char *prompt,
@@ -445,6 +474,14 @@ void direction(dist& moves, targeting_type restricts,
beh->just_looking = just_looking;
+#ifndef USE_TILE
+ if (!just_looking && Options.mlist_targetting == MLIST_TARGET_HIDDEN)
+ {
+ Options.mlist_targetting = MLIST_TARGET_ON;
+ _fill_monster_list();
+ }
+#endif
+
if (crawl_state.is_replaying_keys() && restricts != DIR_DIR)
{
direction_again(moves, restricts, mode, range, just_looking,
@@ -502,6 +539,7 @@ void direction(dist& moves, targeting_type restricts,
}
bool show_prompt = true;
+
while (true)
{
// Prompts might get scrolled off if you have too few lines available.
@@ -602,6 +640,23 @@ void direction(dist& moves, targeting_type restricts,
int i, mid;
+#ifndef USE_TILE
+ if (key_command >= CMD_TARGET_CYCLE_MLIST
+ && key_command <= CMD_TARGET_CYCLE_MLIST_END)
+ {
+ const int idx = key_command - CMD_TARGET_CYCLE_MLIST;
+ if (_find_square_wrapper(moves.tx, moves.ty, monsfind_pos, 1,
+ _find_mlist, needs_path, idx, range,
+ Options.target_wrap))
+ {
+ moves.tx = monsfind_pos[0];
+ moves.ty = monsfind_pos[1];
+ }
+ else if (!skip_iter)
+ flush_input_buffer(FLUSH_ON_FAILURE);
+ }
+#endif
+
switch (key_command)
{
// standard movement
@@ -664,6 +719,20 @@ void direction(dist& moves, targeting_type restricts,
target_mode_help_text(restricts));
break;
+#ifndef USE_TILE
+ case CMD_TARGET_TOGGLE_MLIST:
+ if (Options.mlist_targetting == MLIST_TARGET_ON)
+ Options.mlist_targetting = MLIST_TARGET_OFF;
+ else
+ Options.mlist_targetting = MLIST_TARGET_ON;
+
+ update_monster_pane();
+
+ if (Options.mlist_targetting == MLIST_TARGET_ON)
+ _fill_monster_list();
+ break;
+#endif
+
#ifdef WIZARD
case CMD_TARGET_CYCLE_BEAM:
show_beam = find_ray(you.x_pos, you.y_pos, moves.tx, moves.ty,
@@ -796,6 +865,11 @@ void direction(dist& moves, targeting_type restricts,
you.prev_targ = MHITYOU;
else
you.prev_grd_targ = coord_def(moves.tx, moves.ty);
+
+#ifndef USE_TILE
+ if (Options.mlist_targetting == MLIST_TARGET_ON)
+ Options.mlist_targetting = MLIST_TARGET_HIDDEN;
+#endif
break;
case CMD_TARGET_OBJ_CYCLE_BACK:
@@ -833,6 +907,11 @@ void direction(dist& moves, targeting_type restricts,
loop_done = true;
moves.isCancel = true;
beh->mark_ammo_nonchosen();
+
+#ifndef USE_TILE
+ if (Options.mlist_targetting == MLIST_TARGET_ON)
+ Options.mlist_targetting = MLIST_TARGET_HIDDEN;
+#endif
break;
#ifdef WIZARD
@@ -1022,7 +1101,7 @@ void direction(dist& moves, targeting_type restricts,
true, ray, 0, true) )
{
#else
- if ( need_beam_redraw )
+ if (need_beam_redraw)
{
viewwindow(true, false);
#endif
@@ -1164,6 +1243,46 @@ bool in_los(int x, int y)
return (in_vlos(grid2view(coord_def(x, y))));
}
+#ifndef USE_TILE
+static bool _find_mlist( int x, int y, int idx, bool need_path, int range = -1)
+{
+ if ((int) mlist.size() <= idx)
+ return (false);
+
+ if (!_is_target_in_range(x, y, range) || !in_los(x,y))
+ return (false);
+
+ const int targ_mon = mgrd[ x ][ y ];
+ if (targ_mon == NON_MONSTER)
+ return (false);
+
+ int real_idx = 0;
+ for (unsigned int i = 0; i < mlist.size()-1; i++)
+ {
+ if (real_idx == idx)
+ {
+ real_idx = i;
+ break;
+ }
+
+ // While the monsters are identical, don't increase real_idx.
+ if (mlist[i].m_mon->type == mlist[i+1].m_mon->type
+ && mlist[i].m_attitude == mlist[i+1].m_attitude)
+ {
+ continue;
+ }
+ real_idx++;
+ }
+
+ monsters *mon = &menv[targ_mon];
+ const monsters *monl = mlist[real_idx].m_mon;
+ extern mon_attitude_type mons_attitude(const monsters *m);
+
+ return (mons_attitude(mon) == mlist[idx].m_attitude
+ && mon->type == monl->type);
+}
+#endif
+
static bool _find_monster( int x, int y, int mode, bool need_path,
int range = -1)
{
@@ -1556,8 +1675,8 @@ static char _find_square_wrapper( int tx, int ty,
FixedVector<char, 2> &mfp, char direction,
bool (*find_targ)(int x, int y, int mode,
bool need_path, int range),
- bool need_path, int mode, int range, bool wrap,
- int los )
+ bool need_path, int mode, int range,
+ bool wrap, int los )
{
const char r = _find_square(grid2viewX(tx), grid2viewY(ty), mfp,
direction, find_targ, need_path, mode, range,
@@ -2500,7 +2619,13 @@ command_type targeting_behaviour::get_command(int key)
if (key == -1)
key = get_key();
- switch ( key )
+#ifndef USE_TILE
+ // Overrides the movement keys while mlist_targetting is active.
+ if (Options.mlist_targetting == MLIST_TARGET_ON && islower(key))
+ return static_cast<command_type> (CMD_TARGET_CYCLE_MLIST + (key - 'a'));
+#endif
+
+ switch (key)
{
case ESCAPE:
case 'x': return CMD_TARGET_CANCEL;
@@ -2539,6 +2664,7 @@ command_type targeting_behaviour::get_command(int key)
case '>': return CMD_TARGET_FIND_DOWNSTAIR;
case CONTROL('F'): return CMD_TARGET_CYCLE_TARGET_MODE;
+ case CONTROL('L'): return CMD_TARGET_TOGGLE_MLIST;
case 'p': return CMD_TARGET_PREV_TARGET;
case 'f': return CMD_TARGET_MAYBE_PREV_TARGET;
case 't': return CMD_TARGET_MAYBE_PREV_TARGET; // for the 0.3.4 keys
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index 9bc7585319..f9b3878b13 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -586,6 +586,9 @@ enum command_type
CMD_TARGET_CYCLE_FORWARD,
CMD_TARGET_CYCLE_BACK,
CMD_TARGET_CYCLE_BEAM,
+ CMD_TARGET_CYCLE_MLIST = 2000, // for indices a-z in the monster list
+ CMD_TARGET_CYCLE_MLIST_END = 2025,
+ CMD_TARGET_TOGGLE_MLIST,
CMD_TARGET_HIDE_BEAM,
CMD_TARGET_CENTER,
CMD_TARGET_CANCEL,
@@ -2796,6 +2799,15 @@ enum montravel_target_type
MTRAV_SUBMERSIBLE // Travelling to reach a submersible place.
};
+#ifndef USE_TILE
+enum mlist_targetting_type
+{
+ MLIST_TARGET_OFF = 0,
+ MLIST_TARGET_HIDDEN,
+ MLIST_TARGET_ON
+};
+#endif
+
#ifdef WIZARD
enum wizard_option_type
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index 8603111f87..579cf5e74a 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -1614,6 +1614,7 @@ public:
int mlist_min_height;
int msg_max_height;
bool mlist_allow_alternate_layout;
+ int mlist_targetting; // not actually a real option
bool classic_hud;
bool msg_condense_repeats;
diff --git a/crawl-ref/source/initfile.cc b/crawl-ref/source/initfile.cc
index 9b437a83b3..b69e653cf9 100644
--- a/crawl-ref/source/initfile.cc
+++ b/crawl-ref/source/initfile.cc
@@ -615,6 +615,7 @@ void game_options::reset_options()
mlist_min_height = 5;
msg_max_height = 10;
mlist_allow_alternate_layout = false;
+ mlist_targetting = 0;
classic_hud = false;
msg_condense_repeats = true;
diff --git a/crawl-ref/source/output.cc b/crawl-ref/source/output.cc
index ad0e9a284b..b769206e7c 100644
--- a/crawl-ref/source/output.cc
+++ b/crawl-ref/source/output.cc
@@ -1170,42 +1170,25 @@ std::string mpr_monster_list(bool past)
}
#ifndef USE_TILE
-
-// Monster info used by the pane; precomputes some data
-// to help with sorting and rendering.
-class monster_pane_info
+monster_pane_info::monster_pane_info(const monsters *m)
+ : m_mon(m)
{
- public:
- static bool less_than(const monster_pane_info& m1,
- const monster_pane_info& m2, bool zombified = true);
-
- monster_pane_info(const monsters* m)
- : m_mon(m)
- {
- m_attitude = mons_attitude(m);
-
- // Currently, difficulty is defined as "average hp". Leaks too
- // much info?
- const monsterentry* me = get_monster_data(m->type);
- m_difficulty = me->hpdice[0] * (me->hpdice[1] + (me->hpdice[2]>>1))
- + me->hpdice[3];
-
- m_brands = 0;
- if (mons_looks_stabbable(m)) m_brands |= 1;
- if (mons_looks_distracted(m)) m_brands |= 2;
- if (m->has_ench(ENCH_BERSERK)) m_brands |= 4;
-
- m_fullname = true;
- }
-
- void to_string(int count, std::string& desc, int& desc_color) const;
-
- const monsters* m_mon;
- mon_attitude_type m_attitude;
- int m_difficulty;
- int m_brands;
- bool m_fullname;
-};
+ // XXX: this doesn't take into account ENCH_NEUTRAL, but that's probably
+ // a bug for mons_attitude, not this.
+ // XXX: also, mons_attitude_type should be sorted hostile/neutral/friendly;
+ // will break saves a little bit though.
+ m_attitude = mons_attitude(m);
+
+ // Currently, difficulty is defined as "average hp". Leaks too much info?
+ const monsterentry* me = get_monster_data(m->type);
+ m_difficulty = me->hpdice[0] * (me->hpdice[1] + (me->hpdice[2]>>1))
+ + me->hpdice[3];
+
+ m_brands = 0;
+ if (mons_looks_stabbable(m)) m_brands |= 1;
+ if (mons_looks_distracted(m)) m_brands |= 2;
+ if (m->has_ench(ENCH_BERSERK)) m_brands |= 4;
+}
// Sort monsters by:
// attitude
@@ -1344,9 +1327,9 @@ void monster_pane_info::to_string( int count, std::string& desc,
desc = out.str();
}
-static void _print_next_monster_desc(
- const std::vector<monster_pane_info>& mons, int& start,
- bool zombified = false)
+static void _print_next_monster_desc(const std::vector<monster_pane_info>& mons,
+ int& start, bool zombified = false,
+ int idx = -1)
{
// Skip forward to past the end of the range of identical monsters.
unsigned int end;
@@ -1362,6 +1345,15 @@ static void _print_next_monster_desc(
{
int printed = 0;
+ // for targeting
+ if (idx >= 0)
+ {
+ textcolor(WHITE);
+ cprintf( stringize_glyph('a' + idx).c_str() );
+ cprintf(" - ");
+ printed += 4;
+ }
+
// One glyph for each monster.
for (unsigned int i_mon = start; i_mon < end; i_mon++)
{
@@ -1442,6 +1434,21 @@ static void _print_next_monster_desc(
textcolor(LIGHTGREY);
}
+void get_monster_pane_info(std::vector<monster_pane_info>& mons)
+{
+ std::vector<monsters*> visible;
+ get_playervisible_monsters(visible);
+ for (unsigned int i = 0; i < visible.size(); i++)
+ {
+ if (Options.target_zero_exp
+ || !mons_class_flag( visible[i]->type, M_NO_EXP_GAIN ))
+ {
+ mons.push_back(monster_pane_info(visible[i]));
+ }
+ }
+ std::sort(mons.begin(), mons.end(), monster_pane_info::less_than);
+}
+
#define BOTTOM_JUSTIFY_MONSTER_LIST 0
void update_monster_pane()
{
@@ -1452,19 +1459,7 @@ void update_monster_pane()
return;
std::vector<monster_pane_info> mons;
- {
- std::vector<monsters*> visible;
- get_playervisible_monsters(visible);
- for (unsigned int i = 0; i < visible.size(); i++)
- {
- if (Options.target_zero_exp
- || !mons_class_flag( visible[i]->type, M_NO_EXP_GAIN ))
- {
- mons.push_back(monster_pane_info(visible[i]));
- }
- }
- }
-
+ get_monster_pane_info(mons);
std::sort(mons.begin(), mons.end(), monster_pane_info::less_than);
// Count how many groups of monsters there are
@@ -1497,15 +1492,18 @@ void update_monster_pane()
#endif
// Print the monsters!
-
std::string blank; blank.resize(crawl_view.mlistsz.x, ' ');
int i_mons = 0;
for (int i_print = 0; i_print < max_print; ++i_print)
{
- cgotoxy(1, 1+i_print, GOTO_MLIST);
+ cgotoxy(1, 1 + i_print, GOTO_MLIST);
// i_mons is incremented by _print_next_monster_desc
- if ((i_print >= skip_lines) && (i_mons < (int)mons.size()))
- _print_next_monster_desc(mons, i_mons, zombified);
+ if (i_print >= skip_lines && i_mons < (int) mons.size())
+ {
+ _print_next_monster_desc(mons, i_mons, zombified,
+ Options.mlist_targetting == MLIST_TARGET_ON ? i_print
+ : -1);
+ }
else
cprintf("%s", blank.c_str());
}
@@ -1513,7 +1511,7 @@ void update_monster_pane()
if (i_mons < (int) mons.size())
{
// Didn't get to all of them.
- cgotoxy(crawl_view.mlistsz.x-4, crawl_view.mlistsz.y, GOTO_MLIST);
+ cgotoxy(crawl_view.mlistsz.x - 4, crawl_view.mlistsz.y, GOTO_MLIST);
cprintf(" ... ");
}
}
@@ -1564,10 +1562,9 @@ const char *equip_slot_to_name(int equip)
int equip_name_to_slot(const char *s)
{
for (int i = 0; i < NUM_EQUIP; ++i)
- {
if (!stricmp(s_equip_slot_names[i], s))
return i;
- }
+
return -1;
}
@@ -2122,10 +2119,15 @@ std::string _status_mut_abilities()
if (you.duration[DUR_CONF])
text += "confused, ";
- // how exactly did you get to show the status?
+ // How exactly did you get to show the status?
+ // It's not so unreasonable anymore now that the new overview screen is
+ // dumped. When the player dies while paralysed it's important information.
if (you.duration[DUR_PARALYSIS])
text += "paralysed, ";
+ if (you.duration[DUR_PETRIFIED])
+ text += "petrified, ";
+
if (you.duration[DUR_SLEEP])
text += "sleeping, ";
diff --git a/crawl-ref/source/output.h b/crawl-ref/source/output.h
index c8f1aa9312..073879a2a7 100644
--- a/crawl-ref/source/output.h
+++ b/crawl-ref/source/output.h
@@ -53,7 +53,7 @@ void print_stats_level(void);
void draw_border(void);
std::string mpr_monster_list(bool past = false);
void redraw_skill(const std::string &your_name, const std::string &class_name);
-void update_monster_pane(void);
+void update_monster_pane();
const char *equip_slot_to_name(int equip);
@@ -65,4 +65,27 @@ void print_overview_screen(void);
std::string dump_overview_screen(bool full_id);
+#ifndef USE_TILE
+// Monster info used by the pane; precomputes some data
+// to help with sorting and rendering.
+class monster_pane_info
+{
+ public:
+ static bool less_than(const monster_pane_info& m1,
+ const monster_pane_info& m2, bool zombified = true);
+
+ monster_pane_info(const monsters* m);
+
+ void to_string(int count, std::string& desc, int& desc_color) const;
+
+ const monsters* m_mon;
+ mon_attitude_type m_attitude;
+ int m_difficulty;
+ int m_brands;
+ bool m_fullname;
+};
+
+void get_monster_pane_info(std::vector<monster_pane_info>& mons);
+#endif
+
#endif
diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc
index 8bed707e4d..776504af6b 100644
--- a/crawl-ref/source/view.cc
+++ b/crawl-ref/source/view.cc
@@ -5028,8 +5028,9 @@ void viewwindow(bool draw_it, bool do_updates)
crawl_view.viewp.x + crawl_view.viewsz.x - 1,
crawl_view.viewp.y + crawl_view.viewsz.y - 1,
buffy);
-#endif
+
update_monster_pane();
+#endif
}
}