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
SKWBAGSAB625IIN4UP3NCPRX2H3KCPC2LULHS2A7JVRLO3EUBJDAC
5UOH5KYJW6OO5GYRNLLHSQF3UU4JBGJ32K6ZUFBRLVVVP43XJ4LQC
C3C6VLGVL7RLM53TCSL7ZWUTVV45MMZXCDL75BEAI4RIO43W6J7AC
PYZVEUF25HRJ6FFJH4HEQHUROLBJEYLOSTBKORAGQ5BEZ7DCKYDQC
GZGHMS7PHX5HPU66QXVWDELSIVA76PLB4OF734KSPKL3SETFIIOQC
HAM54HXIO2245W6REO4RZDY2QMIH476AWWJSMYAMSYYNEBBJSHWAC
FEKRY3DYIDLWVBLAZN7W2WFNEKZPCAHABXOSM6K5RLTH5WY2NODQC
FWVE7KM7BGEZUFQVM7H7UFGM3QMMPT7QHLNXSP62HG3SMBIPZBSQC
25CH7HH4LKXFIZ75YNMXS3TSXO6O27DYSOPLOD45K4OCNFWLS4LQC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
NY5JJY33IHF5EKTLPDFVYTN3PFNKV4A3MAH5MRQ3AWH53L2HFIQQC
QSRRV725GCNDOMIDS36NYAA65MOLDMAZSENVSZ3PNOLBFSGHH7BQC
JR2RAQ523LOWNDYJNK6AZVKI6WVMI622PIV72XWOVZYPXPUKSQWAC
NO2HRD7RZS42S55UG4FQ5EFQDY6WYWKGIXHUKYLWF36HHE3VZ7WAC
QV3SYOLTVIFCTWMVKJNJAUGJPCYSGXJOE64242YB2KV74Q46QB7QC
F2YWDQUXULLS2WKLVMNEJKEGSGG2MPEREVI2RKH7ROS2YYKKMXHAC
HT2Z5ZWY5G2QVHXCKFDQT62FRNGPRRD3HHJ2UULBWRTMAJICUDGAC
LDBTCT5WIPLJPZWXS2RUQ26QKISCUUTLO77M464WOE6VSYSNPKYAC
ZB77QXJUJWBFNVMJTAEHJNIILHJD4LIE5DVBEVXOEZ2RYT6I7DRAC
APWL24FMDRVA6NXFFCGNP3Z3FJJ6WFSRWO4ESHEOVT7Z5JGXPUQQC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
FBK5ECMQ6HJSQSN7C3DICKJIRJ3CSO3CHCQ3ONPBKLLSHDGPBQ7QC
I2B33Z7NZGC33AMDSSK446AZZYWKPHWLAGULVHKKZU4MVB4BNJOAC
IXW2IM5ITYDCXDB3ORDDVAR5XUSPVQ3BWLP3Q6TRXNTIKGMZTHXAC
VD4KDTGHVKCN35AWREYB4TEOUMCTW7SAUPAMTMF5ABC7VBHVKP4AC
FWLLPRIZDBJVQ336TPOLYAFT6WYGAFC52OFIOTRN2YQPFZ3PQVRQC
TJRYL3NXPW5IUGEV3YOC7JYWEXCZDBFPLT4AUG4P227WVKVB72ZAC
UEI5JAVCMN7Y2SACTEZPZSNFJWOJTC55G24Q6LKQCT4XNDH5ZQIAC
FEGNPOJI2SALUA2PVIXIQ2CIXFLSXD7UB7CNUSAAKV4L3POXCRFQC
GVCGKTH5IJ4VSQEIN4CRC7ZFVZW26JPIYNCPTO7GY66CSZZEW3ZQC
HSRRNAU5UAYC6B6IQWGJPFROMZBTJICPCH6DJVZDHDTAGOQ6IOYAC
JM7UAK777RAVDAVLQLEOBRTGNW2B47S5G55XITJXO243IUNZHVYQC
JFWC6LBPSC4SE52KE5FCBC2ZVCGLEJ6SJH5UUN5JRJLTNENENIJQC
V4DWL5WBO2JCODVS5QQNWXDH4DAYZN3D5V3UDCHM2KKOMADOTEDQC
IIN7AVA6JYRBXH6ZYRR7BY7TV6PW7ANAQ2A3PD55FKBKKQFEEF2AC
ABLV37FMURRJPEZV2VRKOUYAKEMLI7E6RA4PDAII2EJ5L7WBHKZQC
YHSVOROKPYS33Y4RYZRVZTE3G5LXOFX52HEDNLV6HIXOJYNOKH3QC
YAAJ6PTN6QUSWE52URI5AENOGD366FIHOIFUOXFUJLVZYE4OG6HQC
EOMCPVNQLX3IMLC46EAO67DPBH5KEG2FQTPBLGU62HIRWA3UQ7XQC
PI5BATR2SER3RFE76IUGHM2AGXVFOUM3PLU7WC2K2Q2BA5K2E73QC
5K2ANIEXD3CPJM4XNKNPZINP2G4NT7SJBKRN62WNBUKJXFERTILQC
RJI2QPQBXWAO73WAWUFUZGPUUKQTCXWHMYIVIADBTS5QYN7IQABAC
RVST2QHYJ757ZHK4AUJ5NGPDZ44AD6RVFVXYPKQIBJXZBDNUCHXQC
#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
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;
}
// 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);
void to_string(int count, std::string& desc, int& desc_color) const;
// 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];
const monsters* m_mon;
mon_attitude_type m_attitude;
int m_difficulty;
int m_brands;
bool m_fullname;
};
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;
}
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);
}
{
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);
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);
}
//---------------------------------------------------------------
//--------------------------------------------------------------
#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
#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
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();
}
#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);
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)