Moved map markers to mapmark.cc.
Added support for timer markers that remove a feature after a certain timeout. Need to hook up messaging to Lua.
Added bazaars (need more bazaar layouts).
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1899 c06c8d41-db1a-0410-9941-cceddc491573
GQL5SIGBHLU3FMCE54XVGLRY5AZHRM6DUEB722REA2DPLGJSN6EQC
CPGSHENA5WYRZBW6NBZ2MQKNXE4RJS4SR3Q2H5NL5D3DDDRHHVVQC
TXVVUZNKI2O5YJXC2N4GPG3RJFNC6LSC5IJZKD5XLS4LGJHD2H7AC
YLWMDMNLJOERFAGH5RIFTRWLGCEOWAD4GIWUIXKYA7EE3EWHCVAQC
VVEULZ7FMS53F6WZUJLNJ23URJMCCWHBUEDVGKI6R72JO2DLL5HQC
WKKMCCUZDVXF2Q6XKELUNVAGYP74DC7QIRGN6QAST6OW4UWZNTLAC
UOW2X5KTUHYCM73SWNOSJPHUKWVLF3OJTNSISSSENEURBX2XWHVQC
6GSPAIEMWJXYSCR5EC2WBOGYDEDR6ESIZC6TKN2FVE2CVPSHUHXAC
35KOQQV4ZBNNIAXGKPOYHOWTN7RBQY7HRZTVMR3WAS4GOYFBM6PQC
K6ELQ4HEZYDROC7CJFLPJS64AAJQ4G6RVLL4GBRUG6FJMKSBDDIQC
SSCG2FLJMUTTIRXBFSPLAUUBUIN375ZGL5UOAF3SC62ZIILSMMKAC
2G55UEHQ7554OPNSZVTUCZTWSHIFKGT56QEGSYFKCTX547I4AL3AC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
XHNJ2W4AQHIF32P2ENIMMDLWAIFWP442KJIZC6RKS4HBJNZIHHBAC
2ZZD6EYMSPVCXZTICL4VGYGGQRRWDLZ24KBCDBVIYC54OZ4C6GGAC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
WWR4IDWLXP4XLBWDZBA5GFG7CRKUJQNRK7FFUFOISK6OJTMYQPFQC
TZ55IZNANEJO2WDTKYWVLY2W2VV6BR7WKIN7XLNISAMMFT6LG2WQC
ANBVGN4RZOMY5LI4QSHOV2477FN55H353ZYLSVCPTXC7AWWSQZBAC
Y66ZAXN24E3HLIBOSW4OXUTQ4X4PRGNJII4KVDQH4GQJVA6GO3NAC
IVVTHLTTLOP5TSULXJWUSSXHOKYWVU3OWKYVK45A7RIB6V34MYQAC
LCCGXSFIDQFIRXHGRJWOELNPQOHHCXCWXS366GOULDFPQVOKAIJAC
QS3ZRS3E6KL3YJHPKYEWCWJYRBJSXD5OOYF6Y25HZVECGPJRDB5QC
ZP2KE7A2LE7Z2S7AC45WE4CXDSEVDTWIMV2EM4IBUKXYJIDU6R7QC
OP6CTAKWCAU64JXQ3USQYR5E5IFHQHNCACII5UMVRXUTZXJQOAZAC
T4IH76FA5TWHFOZUJFHLQXQJENJHWTUZZP4EGNA7D4GTZY7D4ZKAC
5UVDIVD4NSXA52U4QMQIVST3GSZJ2A2YZK3RUEXKPM43YVQ7LI5AC
PR2LVM33MZJBAOQ5ZIQNX6CH4DPPG7JJLRCFAPTPLMXSKNJAGJQAC
W5VEC2PBIM5DMU5233HOWAZUEPTGWJRZZIA3H35YYQQW6BTP6XUAC
7AMQN7MITMXBNVDAK5VOXTQ4TZIAOD6ZLOFJG7GQMBTY23Y2BKSAC
2WRXQTGYDBLV46WRNVIUKGNA5QS563XZNNW3N2L6PVOCHIP2YGHQC
MSQI3TH6T62JAXQGLL52QZCWAMC372TGB6ZNNRDGUGMJKBNNV2VAC
ILOED4VB4I6VPAUTR75ZWX6MXDYXB5DO2EDK2UH67O3HNKWV23RQC
UDYVF65OZSNPANLHDI3ODBEGUAKAVZ4KH4OZFAKR2CQJPO4AXU6QC
DTO3EUKWHZ5RJNGNCFYXSOVTIPVXPP637F2W7WFGYKJ7JK7VNKNQC
QKGDOYIYKE6B36ION5O2DRW65DWWPZMYNWJVH7LJJ7FPGGM2MYAQC
DDU4A3JGN5IUIPP5IASOODKPR2WBHSDSV4FITZ6HNXNSXXQACWAQC
74LQ7JXVLAFSHLI7LCBKFX47CNTYSKGUQSXNX5FCIUIGCC2JTR3QC
PJDC24L7LXX6NZ7J5P7MNJJHAKQDJQEBV4CMDR4VSXLMWRIBMNKQC
JM6GKZ6VMX6FNVOZIDXIV22HGX7YESMIFZFE6EEQVCMFJIEA3FNAC
6HG6JFO47Y3BZLU7Y6G3R2CX6JFGN4X5PKK6S5IGUXUYQ5GVZYFQC
RGHXFBNIULRVRYLBGG5JZDMYVM2E2JJ2Y5KQPMU6PUS3V26G6ZXQC
3PY3L3A4QRW3Z5Y7SHO4TMVOOP2VNCO27X2MX4DTOP2SADLBQUOAC
UL7XFKMUX3WIU4O2LZANK4ECJ654UZPDBFGNXUEYZYOLKBYBCG6AC
JQFQX7IWSJ4TYWVUVXAFMCPSAN67PRMNECDQI5WMON2JFMQVVUEQC
NCDWWDJQLAU5ORSAQGZKJJ5E22VTDGGPJMVVBWQFHQ2B3U3UFHDQC
34C4U6EQWERY75GZJKUCM5KVGU2OUICETS5LGZF6RMKMZT4R5SQAC
KFJEFN377VIZ7OH2XCYOGCELNEGO4CIOOP7DNXEMX3LFKIKWXVTAC
MQ62OAMLGJVRW2QIL4PAZRAU6PC52ZVGY2FCOBIY6IWGQIHMU5CAC
AUXHSGS4EFOPZ6TVZYWNVOUDO7NYKUKE3HBKGQQWTALSVFOE3HAAC
UBQTNLYGD3SNWMUNGWUPX7EXEGQXOXCFCPWIVWBFE7ID7DJLPFWAC
WW6THKR7JN447YC23YYHYYNH7ABMCFFSECNUFTIJBZX6JHX6W7TAC
TAHSTXR7ROOMDFUSBUU4ZAIEWQLAS5CIRCTARLD4Q2BGNLSL7E5QC
XKAJWK6MPHS3ZCZIPPLTIMOPF6AROGLRDDCS6EFE3IGE4AHT7MYQC
TAVHZJPVNJBZR7CUURAOYNDZPNVQ3AGHTXDEP5K4JGYETBLQJDRQC
TV3ZC6WOZKSQQJQN26JIVKCHK6UK7WMDBYZDUYRWEAZ4JB4YVNAAC
RISMOCQM6BKK4XSIRKYLOBB2UPDYJNDAL6OGIIR5GGNZQAK5YSZAC
SW3RLYFNRT3IJBK6LYKHKP2J2YDU7SXQWAJZX7U6S7ICYW43OMNQC
52W74WXL5XIH6YFJBQRVAO47YHCS3CPMUUZS4Q3AZ3HAPDWMT54AC
OWNMHNCGA5H3A6AULXXW473PKC7N6IINE3LJCB3KCFG2XA3TYCQQC
C22455VGUQOSUX2OORA32LROFQ7NNYDMD2ZDTTUZSAQLXK4AD6QAC
OYTCBRC7LE44EUVRZVYTOOVKQWJ6P6YE3FXTOGUTNKEMLNWPHKSQC
XY77S75KH5KV54MZVAPMUC64TVRE2QM2KVJAAGJGCIBGQEC5GUTQC
ZVK4J5HTKFNOOIVCI62ZWEYGXEE5TYJ65DLYYZAZWTADFSXE62ZAC
KKROXTUPBNEXXEUUDJNADATK3BCQPSQWFZ6L4VTKBPTYXJLYUHDQC
2YSMM7QMFZOPD5NXAD2OAMDJEY5LOZO4NCYBC7UCQVANKINJRNBAC
KCHX2F3JFEWOZT3WMJVZAAQUU2QSZ5Q7RDCD7WUJ7VE65J52JFUQC
3XZOL3FFQZITUJIGDD6B6V6ZYMBN524JKNN6ZPJAXEC7RY433I3QC
ZJLJGSB2XSBQU42OFQMXL3EG4CXAQGOYAU6YTV2SAWZEJIPFH2CAC
6QWZDCP5HGYLTJO3WWYJJGRRT7QFY6IG64TC7TUB553Z7GAA2HIQC
KXUQB3WNWC5IFL6VFWADEPQMMU3VV3NDI5FLA666PGOEWFYUHCLQC
4RFKVDJKTCRBZU6WPJ2E5OVI5IRPY3UTRPOBLC5QHY4CQJJTLZKQC
W5WCC5J7PL6IXZ5LPSUWGY3IVQBCTK3FKOD5ADYRWWH2N425NEAAC
56C44YMFHZ62GXAAOLYSLLGBVGRWXB53W2VI37Q26ZECEK2XG5SQC
CQ24AVAI6SW3AHTIDMLPSTRRBEU6FHRF5I5FD6G5QIYE6PO4BQMQC
GACH6PWPGGUBEE7PFEPQMOZKSR7HTQGL2WLGF2AQPJD3FCCSKZNQC
LOJYD6QZRNLNDDZJKVBMKQIBPTKSRN2ETCYGNVV47M7L3QLUJUJAC
WLX2RQMMOMP2PYPAGJRM4VFD2WTLJTOAZZPPY3MV76FU2EGEJ54QC
H3552BCIAVBLKAYKE4DHFLBLFW5RGRMYBMRRYHYEB5IPIJRUVU5QC
W52PCSHX72WAMWKG6L4BPUBVMO6E72KYYBNKAA7554KNOTY6V7WQC
BXXOYFMWNQY4TLLJBFYROSH43KO5F4JQTATU3ZEJNKGIJGOIQN4AC
77H4BWWPPGLM3PLZH4QTAJRXIZTSDVNCOKZE223I437FN2UJ34RQC
Y2VKZYSQXLYYQNB6OSQP44IYLT2M56SE2ZW2MHOAZUODKCVDHEAQC
R6XS2HO5QX2FJUGL5UQQRNETKCMYWTUFPHPPS5SYWK3OQA4UDUQQC
ILN2K6ASDZSMEHOPJ22IZLZJUO6DDGZTKAKXM3YXG6JZZHJNLX4AC
WE3JT43OR4L6675GINGU4B3YDBMURJZHDDYY3VLHUJEBAKH2HYEAC
command_type stair_direction(dungeon_feature_type stair)
{
return ((stair < DNGN_STONE_STAIRS_UP_I
|| stair > DNGN_ROCK_STAIRS_UP)
&& (stair < DNGN_RETURN_FROM_ORCISH_MINES
|| stair > DNGN_RETURN_RESERVED_4))
? CMD_GO_DOWNSTAIRS : CMD_GO_UPSTAIRS;
}
return ((id.level_type == LEVEL_DUNGEON
&& can_travel_interlevel())
|| (id.level_type == LEVEL_PANDEMONIUM
&& you.level_type == LEVEL_PANDEMONIUM));
return ((id.level_type == LEVEL_DUNGEON && can_travel_interlevel())
|| (id.level_type == you.level_type && player_in_mappable_area()));
//////////////////////////////////////////////////////////////////////////
// crawl_environment
void crawl_environment::add_marker(map_marker *marker)
{
markers.insert(dgn_pos_marker(marker->pos, marker));
}
void crawl_environment::remove_marker(map_marker *marker)
{
std::pair<dgn_marker_map::iterator, dgn_marker_map::iterator>
els = markers.equal_range(marker->pos);
for (dgn_marker_map::iterator i = els.first; i != els.second; ++i)
{
if (i->second == marker)
{
markers.erase(i);
break;
}
}
delete marker;
}
void crawl_environment::remove_markers_at(const coord_def &c)
{
std::pair<dgn_marker_map::iterator, dgn_marker_map::iterator>
els = markers.equal_range(c);
for (dgn_marker_map::iterator i = els.first; i != els.second; )
{
dgn_marker_map::iterator todel = i++;
delete todel->second;
markers.erase(todel);
}
}
map_marker *crawl_environment::find_marker(const coord_def &c,
map_marker_type type) const
{
std::pair<dgn_marker_map::const_iterator, dgn_marker_map::const_iterator>
els = markers.equal_range(c);
for (dgn_marker_map::const_iterator i = els.first; i != els.second; ++i)
if (type == MAT_ANY || i->second->get_type() == type)
return (i->second);
return (NULL);
}
std::vector<map_marker*> crawl_environment::get_markers(const coord_def &c)
const
{
std::pair<dgn_marker_map::const_iterator, dgn_marker_map::const_iterator>
els = markers.equal_range(c);
std::vector<map_marker*> rmarkers;
for (dgn_marker_map::const_iterator i = els.first; i != els.second; ++i)
rmarkers.push_back(i->second);
return (rmarkers);
}
void crawl_environment::clear_markers()
{
for (dgn_marker_map::iterator i = markers.begin(); i != markers.end(); ++i)
delete i->second;
markers.clear();
}
}
}
bool grid_sealable_portal(dungeon_feature_type grid)
{
switch (grid)
{
case DNGN_ENTER_HELL:
case DNGN_ENTER_ABYSS:
case DNGN_ENTER_PANDEMONIUM:
case DNGN_ENTER_LABYRINTH:
case DNGN_ENTER_BAZAAR:
return (true);
default:
return (false);
}
}
command_type grid_stair_direction(dungeon_feature_type grid)
{
switch (grid)
{
case DNGN_STONE_STAIRS_UP_I:
case DNGN_STONE_STAIRS_UP_II:
case DNGN_STONE_STAIRS_UP_III:
case DNGN_ROCK_STAIRS_UP:
case DNGN_RETURN_FROM_ORCISH_MINES:
case DNGN_RETURN_FROM_HIVE:
case DNGN_RETURN_FROM_LAIR:
case DNGN_RETURN_FROM_SLIME_PITS:
case DNGN_RETURN_FROM_VAULTS:
case DNGN_RETURN_FROM_CRYPT:
case DNGN_RETURN_FROM_HALL_OF_BLADES:
case DNGN_RETURN_FROM_ZOT:
case DNGN_RETURN_FROM_TEMPLE:
case DNGN_RETURN_FROM_SNAKE_PIT:
case DNGN_RETURN_FROM_ELVEN_HALLS:
case DNGN_RETURN_FROM_TOMB:
case DNGN_RETURN_FROM_SWAMP:
case DNGN_RETURN_FROM_SHOALS:
case DNGN_RETURN_RESERVED_2:
case DNGN_RETURN_RESERVED_3:
case DNGN_RETURN_RESERVED_4:
case DNGN_ENTER_SHOP:
case DNGN_EXIT_HELL:
case DNGN_EXIT_BAZAAR:
return (CMD_GO_UPSTAIRS);
case DNGN_ENTER_BAZAAR:
case DNGN_ENTER_HELL:
case DNGN_ENTER_LABYRINTH:
case DNGN_STONE_STAIRS_DOWN_I:
case DNGN_STONE_STAIRS_DOWN_II:
case DNGN_STONE_STAIRS_DOWN_III:
case DNGN_ROCK_STAIRS_DOWN:
case DNGN_ENTER_DIS:
case DNGN_ENTER_GEHENNA:
case DNGN_ENTER_COCYTUS:
case DNGN_ENTER_TARTARUS:
case DNGN_ENTER_ABYSS:
case DNGN_EXIT_ABYSS:
case DNGN_ENTER_PANDEMONIUM:
case DNGN_EXIT_PANDEMONIUM:
case DNGN_TRANSIT_PANDEMONIUM:
case DNGN_ENTER_ORCISH_MINES:
case DNGN_ENTER_HIVE:
case DNGN_ENTER_LAIR:
case DNGN_ENTER_SLIME_PITS:
case DNGN_ENTER_VAULTS:
case DNGN_ENTER_CRYPT:
case DNGN_ENTER_HALL_OF_BLADES:
case DNGN_ENTER_ZOT:
case DNGN_ENTER_TEMPLE:
case DNGN_ENTER_SNAKE_PIT:
case DNGN_ENTER_ELVEN_HALLS:
case DNGN_ENTER_TOMB:
case DNGN_ENTER_SWAMP:
case DNGN_ENTER_SHOALS:
case DNGN_ENTER_RESERVED_2:
case DNGN_ENTER_RESERVED_3:
case DNGN_ENTER_RESERVED_4:
return (CMD_GO_DOWNSTAIRS);
default:
return (CMD_NO_CMD);
: "You hear an empty echo.";
: "You hear a crunching noise.";
}
// Returns true if exits from this type of level involve going upstairs.
bool level_type_exits_up(level_area_type type)
{
return (type == LEVEL_LABYRINTH || type == LEVEL_BAZAAR);
}
bool level_type_exits_down(level_area_type type)
{
return (type == LEVEL_PANDEMONIUM || type == LEVEL_ABYSS);
static bool dgn_shift_item_around(const coord_def &pos, item_def &item)
{
std::list<coord_def> points;
for (int yi = -1; yi <= 1; ++yi)
{
for (int xi = -1; xi <= 1; ++xi)
{
if (!xi && !yi)
continue;
const coord_def np(pos.x + xi, pos.y + yi);
if (!in_bounds(np) || travel_point_distance[np.x][np.y])
continue;
travel_point_distance[np.x][np.y] = 1;
const dungeon_feature_type feat = grd(np);
if (!grid_is_solid(feat) && !grid_destroys_items(feat))
{
int index = item.index();
move_item_to_grid(&index, np.x, np.y);
return (true);
}
points.push_back(np);
}
}
for (std::list<coord_def>::iterator i = points.begin(); i != points.end();
++i)
{
if (dgn_shift_item_around(*i, item))
return (true);
}
return (false);
}
// Moves an item on the floor to the nearest adjacent floor-space.
static bool dgn_shift_item(const coord_def &pos, item_def &item)
{
memset(travel_point_distance, 0, sizeof(travel_distance_grid_t));
travel_point_distance[pos.x][pos.y] = 0;
return (dgn_shift_item_around(pos, item));
}
static void dgn_check_terrain_items(const coord_def &pos)
{
const dungeon_feature_type grid = grd(pos);
if (grid_is_solid(grid) || grid_destroys_items(grid))
{
int item = igrd(pos);
bool did_destroy = false;
while (item != NON_ITEM)
{
const int curr = item;
item = mitm[item].link;
// Game-critical item.
if (true || item_is_critical(mitm[curr]))
dgn_shift_item(pos, mitm[curr]);
else
{
destroy_item(curr);
did_destroy = true;
}
}
if (did_destroy && player_can_hear(pos))
mprf(MSGCH_SOUND, grid_item_destruction_message(grid));
}
}
static void dgn_check_terrain_monsters(const coord_def &pos)
{
const int mindex = mgrd(pos);
if (mindex != NON_MONSTER)
{
monsters *mons = &menv[mindex];
if (grid_is_solid(grd(pos)))
monster_teleport(mons, true, false);
else
mons_check_pool(mons, KILL_MISC, -1);
}
}
void dungeon_terrain_changed(const coord_def &pos)
{
dgn_check_terrain_items(pos);
if (pos == you.pos())
{
if (!grid_is_solid(grd(pos)))
{
if (!you.flies())
move_player_to_grid(pos.x, pos.y, false, true, false);
}
else
you_teleport_now(true, false);
}
dgn_check_terrain_monsters(pos);
}
if ((stair_find < DNGN_ENTER_LABYRINTH
|| stair_find > DNGN_ROCK_STAIRS_DOWN)
&& stair_find != DNGN_ENTER_HELL
&& ((stair_find < DNGN_ENTER_DIS
|| stair_find > DNGN_TRANSIT_PANDEMONIUM)
&& stair_find != DNGN_STONE_ARCH)
&& !(stair_find >= DNGN_ENTER_ORCISH_MINES
&& stair_find < DNGN_RETURN_FROM_ORCISH_MINES))
if (grid_stair_direction(stair_find) != CMD_GO_DOWNSTAIRS)
bool collect_travel_data = you.level_type != LEVEL_LABYRINTH
&& you.level_type != LEVEL_ABYSS
&& you.level_type != LEVEL_PANDEMONIUM;
bool collect_travel_data = can_travel_interlevel();
#ifndef __MAPMARK_H__
#define __MAPMARK_H__
#include "dungeon.h"
#include "dgnevent.h"
//////////////////////////////////////////////////////////////////////////
// Map markers
// Can't change this order without breaking saves.
enum map_marker_type
{
MAT_FEATURE, // Stock marker.
MAT_TIMED_FEATURE,
NUM_MAP_MARKER_TYPES,
MAT_ANY
};
class map_marker
{
public:
map_marker(map_marker_type type, const coord_def &pos);
virtual ~map_marker();
map_marker_type get_type() const { return type; }
virtual void activate();
virtual void write(tagHeader &) const;
virtual void read(tagHeader &);
virtual std::string describe() const = 0;
static map_marker *read_marker(tagHeader&);
static map_marker *parse_marker(const std::string &text)
throw (std::string);
public:
coord_def pos;
protected:
map_marker_type type;
typedef map_marker *(*marker_reader)(tagHeader &, map_marker_type);
typedef map_marker *(*marker_parser)(const std::string &);
static marker_reader readers[NUM_MAP_MARKER_TYPES];
static marker_parser parsers[NUM_MAP_MARKER_TYPES];
};
class map_feature_marker : public map_marker
{
public:
map_feature_marker(const coord_def &pos = coord_def(0, 0),
dungeon_feature_type feat = DNGN_UNSEEN);
map_feature_marker(const map_feature_marker &other);
void write(tagHeader &) const;
void read(tagHeader &);
std::string describe() const;
static map_marker *read(tagHeader &, map_marker_type);
static map_marker *parse(const std::string &s) throw (std::string);
public:
dungeon_feature_type feat;
};
class map_timed_feature_marker : public map_feature_marker, dgn_event_listener
{
public:
map_timed_feature_marker(const coord_def &pos = coord_def(),
int duration_turns = 0,
dungeon_feature_type feat = DNGN_FLOOR);
void activate();
void write(tagHeader &) const;
void read(tagHeader &);
std::string describe() const;
void notify_dgn_event(const dgn_event &e);
// Expires this marker *now* and cleans it up.
void timeout(bool verbose);
static map_marker *read(tagHeader &, map_marker_type);
static map_marker *parse(const std::string &s) throw (std::string);
private:
const char *bell_urgency(int ticks) const;
const char *noise_maker(int ticks) const;
public:
// Ticks are a tenth of a turn.
int duration_ticks;
int warn_threshold;
};
void env_activate_markers();
void env_add_marker(map_marker *);
void env_remove_marker(map_marker *);
void env_remove_markers_at(const coord_def &c, map_marker_type);
map_marker *env_find_marker(const coord_def &c, map_marker_type);
std::vector<map_marker*> env_get_markers(const coord_def &c);
void env_clear_markers();
#endif
/*
* File: mapmark.cc
* Summary: Level markers (annotations).
*
* Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-07-20T11:40:25.964128Z $
*
*/
#include "AppHdr.h"
#include "mapmark.h"
#include "direct.h"
#include "libutil.h"
#include "luadgn.h"
#include "stuff.h"
#include "tags.h"
#include "view.h"
////////////////////////////////////////////////////////////////////////
// Dungeon markers
map_marker::marker_reader map_marker::readers[NUM_MAP_MARKER_TYPES] =
{
&map_feature_marker::read,
&map_timed_feature_marker::read,
};
map_marker::marker_parser map_marker::parsers[NUM_MAP_MARKER_TYPES] =
{
&map_feature_marker::parse,
&map_timed_feature_marker::parse,
};
map_marker::map_marker(map_marker_type t, const coord_def &p)
: pos(p), type(t)
{
}
map_marker::~map_marker()
{
}
void map_marker::activate()
{
}
void map_marker::write(tagHeader &outf) const
{
marshallShort(outf, type);
marshallCoord(outf, pos);
}
void map_marker::read(tagHeader &inf)
{
// Don't read type! The type has to be read by someone who knows how
// to look up the unmarshall function.
unmarshallCoord(inf, pos);
}
map_marker *map_marker::read_marker(tagHeader &inf)
{
const map_marker_type type =
static_cast<map_marker_type>(unmarshallShort(inf));
return readers[type]? (*readers[type])(inf, type) : NULL;
}
map_marker *map_marker::parse_marker(const std::string &s) throw (std::string)
{
for (int i = 0; i < NUM_MAP_MARKER_TYPES; ++i)
{
if (parsers[i])
{
if (map_marker *m = parsers[i](s))
return (m);
}
}
return (NULL);
}
////////////////////////////////////////////////////////////////////////////
// map_feature_marker
map_feature_marker::map_feature_marker(
const coord_def &p,
dungeon_feature_type _feat)
: map_marker(MAT_FEATURE, p), feat(_feat)
{
}
map_feature_marker::map_feature_marker(
const map_feature_marker &other)
: map_marker(MAT_FEATURE, other.pos), feat(other.feat)
{
}
void map_feature_marker::write(tagHeader &outf) const
{
this->map_marker::write(outf);
marshallShort(outf, feat);
}
void map_feature_marker::read(tagHeader &inf)
{
map_marker::read(inf);
feat = static_cast<dungeon_feature_type>(unmarshallShort(inf));
}
map_marker *map_feature_marker::read(tagHeader &inf, map_marker_type)
{
map_marker *mapf = new map_feature_marker();
mapf->read(inf);
return (mapf);
}
map_marker *map_feature_marker::parse(const std::string &s) throw (std::string)
{
if (s.find("feat:") != 0)
return (NULL);
std::string raw = s;
strip_tag(raw, "feat:", true);
const dungeon_feature_type ft = dungeon_feature_by_name(raw);
if (ft == DNGN_UNSEEN)
throw make_stringf("Bad feature marker: %s (unknown feature '%s')",
s.c_str(), raw.c_str());
return new map_feature_marker(coord_def(0, 0), ft);
}
std::string map_feature_marker::describe() const
{
return make_stringf("feature (%s)", dungeon_feature_name(feat));
}
////////////////////////////////////////////////////////////////////////////
// map_feature_marker
map_timed_feature_marker::map_timed_feature_marker(
const coord_def &_pos,
int duration_turns,
dungeon_feature_type _feat)
: map_feature_marker(_pos, _feat), duration_ticks(duration_turns * 10),
warn_threshold(-1000)
{
type = MAT_TIMED_FEATURE;
}
void map_timed_feature_marker::activate()
{
dungeon_events.register_listener(DET_TURN_ELAPSED, this);
if (player_can_hear(pos))
{
const dungeon_feature_type ft = grd(pos);
switch (ft)
{
case DNGN_ENTER_BAZAAR:
mprf(MSGCH_SOUND, "You %shear coins being counted.",
duration_ticks < 1000? "can faintly " : "");
break;
case DNGN_ENTER_LABYRINTH:
mprf(MSGCH_SOUND, "You hear a faint echoing snort.");
break;
default:
break;
}
}
}
void map_timed_feature_marker::write(tagHeader &th) const
{
map_feature_marker::write(th);
marshallShort(th, duration_ticks);
marshallShort(th, warn_threshold);
}
void map_timed_feature_marker::read(tagHeader &th)
{
map_feature_marker::read(th);
duration_ticks = unmarshallShort(th);
warn_threshold = unmarshallShort(th);
}
std::string map_timed_feature_marker::describe() const
{
return make_stringf("timer: %d ticks (%s)",
duration_ticks, dungeon_feature_name(feat));
}
const char *map_timed_feature_marker::bell_urgency(int ticks) const
{
if (ticks > 5000)
return "stately ";
else if (ticks > 4000)
return "";
else if (ticks > 2500)
return "brisk ";
else if (ticks > 1500)
return "urgent ";
else if (ticks > 0)
return "frantic ";
else
return "last, dying notes of the ";
}
const char *map_timed_feature_marker::noise_maker(int ticks) const
{
switch (grd(pos))
{
case DNGN_ENTER_LABYRINTH:
return (ticks > 0? "tolling of a bell" : "bell");
case DNGN_ENTER_BAZAAR:
return (ticks > 0? "ticking of an ancient clock" : "clock");
default:
return (ticks > 0?
"trickling of a stream filled with giant, killer bugs."
: "stream");
}
}
void map_timed_feature_marker::notify_dgn_event(const dgn_event &e)
{
if (!e.elapsed_ticks || e.type != DET_TURN_ELAPSED)
return;
if (warn_threshold == -1000)
warn_threshold = std::max(50, duration_ticks - 500);
duration_ticks -= e.elapsed_ticks;
if (duration_ticks < warn_threshold || duration_ticks <= 0)
{
if (duration_ticks > 900)
warn_threshold = duration_ticks - 500;
else
warn_threshold = duration_ticks - 250;
if (duration_ticks > 0 && player_can_hear(pos))
mprf(MSGCH_SOUND, "You hear the %s%s.",
bell_urgency(duration_ticks),
noise_maker(duration_ticks));
if (duration_ticks <= 0)
timeout(true);
}
}
void map_timed_feature_marker::timeout(bool verbose)
{
if (verbose)
{
if (see_grid(pos))
mprf("%s disappears!",
feature_description(grd(pos), NUM_TRAPS, false,
DESC_CAP_THE, false).c_str());
else
mpr("The walls and floor vibrate strangely for a moment.");
}
// And it's gone forever.
grd(pos) = feat;
dungeon_terrain_changed(pos);
// Stop listening for further ticks.
dungeon_events.remove_listener(this);
// Kill this marker.
env_remove_marker(this);
}
map_marker *map_timed_feature_marker::read(tagHeader &th, map_marker_type)
{
map_marker *mt = new map_timed_feature_marker();
mt->read(th);
return (mt);
}
map_marker *map_timed_feature_marker::parse(const std::string &s)
throw (std::string)
{
if (s.find("timer:") != 0)
return (NULL);
std::string raw = s;
strip_tag(raw, "timer:", true);
int navg = strip_number_tag(raw, "avg:");
if (navg == TAG_UNFOUND)
navg = 1;
if (navg < 1 || navg > 20)
throw make_stringf("Bad marker spec '%s' (avg out of bounds)",
s.c_str());
dungeon_feature_type feat = DNGN_FLOOR;
std::string fname = strip_tag_prefix(raw, "feat:");
if (!fname.empty()
&& (feat = dungeon_feature_by_name(fname)) == DNGN_UNSEEN)
{
throw make_stringf("Bad feature name (%s) in marker spec '%s'",
fname.c_str(), s.c_str());
}
std::vector<std::string> limits = split_string("-", raw);
const int nlims = limits.size();
if (nlims < 1 || nlims > 2)
throw make_stringf("Malformed turn range (%s) in marker '%s'",
raw.c_str(), s.c_str());
const int low = atoi(limits[0].c_str());
const int high = nlims == 1? low : atoi(limits[1].c_str());
if (low == 0 || high < low)
throw make_stringf("Malformed turn range (%s) in marker '%s'",
raw.c_str(), s.c_str());
const int duration = low == high? low : random_range(low, high, navg);
return new map_timed_feature_marker(coord_def(0, 0),
duration, feat);
}
//////////////////////////////////////////////////////////////////////////
// Map markers in env.
void env_activate_markers()
{
for (dgn_marker_map::iterator i = env.markers.begin();
i != env.markers.end(); ++i)
{
i->second->activate();
}
}
void env_add_marker(map_marker *marker)
{
env.markers.insert(dgn_pos_marker(marker->pos, marker));
}
void env_remove_marker(map_marker *marker)
{
std::pair<dgn_marker_map::iterator, dgn_marker_map::iterator>
els = env.markers.equal_range(marker->pos);
for (dgn_marker_map::iterator i = els.first; i != els.second; ++i)
{
if (i->second == marker)
{
env.markers.erase(i);
break;
}
}
delete marker;
}
void env_remove_markers_at(const coord_def &c,
map_marker_type type)
{
std::pair<dgn_marker_map::iterator, dgn_marker_map::iterator>
els = env.markers.equal_range(c);
for (dgn_marker_map::iterator i = els.first; i != els.second; )
{
dgn_marker_map::iterator todel = i++;
if (type == MAT_ANY || todel->second->get_type() == type)
{
delete todel->second;
env.markers.erase(todel);
}
}
}
map_marker *env_find_marker(const coord_def &c, map_marker_type type)
{
std::pair<dgn_marker_map::const_iterator, dgn_marker_map::const_iterator>
els = env.markers.equal_range(c);
for (dgn_marker_map::const_iterator i = els.first; i != els.second; ++i)
if (type == MAT_ANY || i->second->get_type() == type)
return (i->second);
return (NULL);
}
std::vector<map_marker*> env_get_markers(const coord_def &c)
{
std::pair<dgn_marker_map::const_iterator, dgn_marker_map::const_iterator>
els = env.markers.equal_range(c);
std::vector<map_marker*> rmarkers;
for (dgn_marker_map::const_iterator i = els.first; i != els.second; ++i)
rmarkers.push_back(i->second);
return (rmarkers);
}
void env_clear_markers()
{
for (dgn_marker_map::iterator i = env.markers.begin();
i != env.markers.end(); ++i)
delete i->second;
env.markers.clear();
}
}
// Returns true if s contains tag 'tag', and strips out tag from s.
bool strip_tag(std::string &s, const std::string &tag)
{
if (s == tag)
{
s.clear();
return (true);
}
std::string::size_type pos;
if ((pos = s.find(" " + tag + " ")) != std::string::npos)
{
// Leave one space intact.
s.erase(pos, tag.length() + 1);
return (true);
}
if ((pos = s.find(tag + " ")) != std::string::npos
|| (pos = s.find(" " + tag)) != std::string::npos)
{
s.erase(pos, tag.length() + 1);
return (true);
}
return (false);
}
#define TAG_UNFOUND -20404
int strip_number_tag(std::string &s, const std::string &tagprefix)
{
std::string::size_type pos = s.find(tagprefix);
if (pos == std::string::npos)
return (TAG_UNFOUND);
std::string::size_type ns = s.find(" ", pos);
if (ns == std::string::npos)
ns = s.length();
std::string argument =
s.substr(pos + tagprefix.length(), ns - pos - tagprefix.length());
s.erase(pos, ns - pos + 1);
return atoi(argument.c_str());
const dungeon_feature_type feat = dungeon_feature_by_name(arg);
if (feat == DNGN_UNSEEN)
return make_stringf("unknown feature: %s", arg.c_str());
transforms.push_back(new map_feat_marker_spec(key[0], feat));
transforms.push_back(new map_marker_spec(key[0], arg));
map.add_marker(new map_feature_marker(positions[0], feat));
return ("");
try
{
map_marker *mark = map_marker::parse_marker(marker);
if (!mark)
return make_stringf("Unable to parse marker from %s",
marker.c_str());
mark->pos = positions[0];
map.add_marker(mark);
return ("");
}
catch (const std::string &err)
{
return (err);
}
const coord_def pos(luaL_checkint(ls, 2), luaL_checkint(ls, 3));
dungeon_feature_type feat = DNGN_UNSEEN;
if (lua_isnumber(ls, 4))
feat = static_cast<dungeon_feature_type>( luaL_checkint(ls, 4) );
else
feat = dungeon_feature_by_name( luaL_checkstring(ls, 4) );
map->map.add_marker( new map_feature_marker(pos, feat) );
}
// Returns true if s contains tag 'tag', and strips out tag from s.
bool strip_tag(std::string &s, const std::string &tag, bool skip_padding)
{
if (s == tag)
{
s.clear();
return (true);
}
std::string::size_type pos;
if (skip_padding)
{
if ((pos = s.find(tag)) != std::string::npos)
{
s.erase(pos, tag.length());
trim_string(s);
return (true);
}
return (false);
}
if ((pos = s.find(" " + tag + " ")) != std::string::npos)
{
// Leave one space intact.
s.erase(pos, tag.length() + 1);
trim_string(s);
return (true);
}
if ((pos = s.find(tag + " ")) != std::string::npos
|| (pos = s.find(" " + tag)) != std::string::npos)
{
s.erase(pos, tag.length() + 1);
trim_string(s);
return (true);
}
return (false);
std::string strip_tag_prefix(std::string &s, const std::string &tagprefix)
{
const std::string::size_type pos = s.find(tagprefix);
if (pos == std::string::npos)
return ("");
std::string::size_type ns = s.find(" ", pos);
if (ns == std::string::npos)
ns = s.length();
const std::string argument =
s.substr(pos + tagprefix.length(), ns - pos - tagprefix.length());
s.erase(pos, ns - pos + 1);
trim_string(s);
return (argument);
}
int strip_number_tag(std::string &s, const std::string &tagprefix)
{
const std::string num = strip_tag_prefix(s, tagprefix);
return (num.empty()? TAG_UNFOUND : atoi(num.c_str()));
}
}
// The Orb of Zot and unique runes are considered critical.
bool item_is_critical(const item_def &item)
{
if (item.base_type == OBJ_ORBS)
return (true);
return (item.base_type == OBJ_MISCELLANY
&& item.sub_type == MISC_RUNE_OF_ZOT
&& (item.plus != RUNE_DEMONIC
&& item.plus != RUNE_ABYSSAL));
public:
void add_marker(map_marker *);
void remove_marker(map_marker *);
void remove_markers_at(const coord_def &c);
map_marker *find_marker(const coord_def &c, map_marker_type) const;
std::vector<map_marker*> get_markers(const coord_def &c) const;
void clear_markers();
// When adding:
//
// * New stairs/portals: update grid_stair_direction.
// * Any: edit view.cc and add a glyph and colour for the feature.
// * Any: edit direct.cc and add a description for the feature.
// * Any: edit dat/descript.txt and add a long description if appropriate.
// * Any: check the grid_* functions in misc.cc and make sure
// they return sane values for your new feature.
//
// Also take note of MINMOVE and MINSEE above.
//
// Map markers
class map_marker
{
public:
map_marker(map_marker_type type, const coord_def &pos);
virtual ~map_marker();
map_marker_type get_type() const { return type; }
virtual void write(tagHeader &) const;
virtual void read(tagHeader &);
virtual map_marker *clone() const = 0;
virtual std::string describe() const = 0;
static map_marker *read_marker(tagHeader&);
public:
coord_def pos;
protected:
map_marker_type type;
typedef map_marker *(*marker_reader)(tagHeader &, map_marker_type);
static marker_reader readers[NUM_MAP_MARKER_TYPES];
};
class map_feature_marker : public map_marker
{
public:
map_feature_marker(const coord_def &pos = coord_def(0, 0),
dungeon_feature_type feat = DNGN_UNSEEN);
map_feature_marker(const map_feature_marker &other);
void write(tagHeader &) const;
void read(tagHeader &);
map_marker *clone() const;
std::string describe() const;
static map_marker *read(tagHeader &, map_marker_type);
public:
dungeon_feature_type feat;
};
//////////////////////////////////////////////////////////////////////////
}
static void fixup_bazaar_stairs()
{
for (int y = 0; y < GYM; ++y)
{
for (int x = 0; x < GXM; ++x)
{
const dungeon_feature_type feat = grd[x][y];
if (grid_is_stone_stair(feat) || grid_is_rock_stair(feat))
{
if (grid_stair_direction(feat) == CMD_GO_DOWNSTAIRS)
grd[x][y] = DNGN_EXIT_BAZAAR;
else
grd[x][y] = DNGN_STONE_ARCH;
}
}
}
}
static void bazaar_level(int level_number)
{
int vault = random_map_for_place(level_id::current(), false);
if (vault == -1)
vault = random_map_for_tag("bazaar", false);
if (vault != -1)
{
ensure_vault_placed( build_vaults(level_number, vault) );
link_items();
fixup_bazaar_stairs();
return;
}
// No primary Bazaar vaults (ugh).
plan_main(level_number, 0);
place_minivaults("bazaar", 1, 1, true);
// No vaults placed yet? Place some shops of our own.
if (level_vaults.empty())
place_shops(level_number, random_range(5, MAX_SHOPS));
link_items();
fixup_bazaar_stairs();
if (level_type != LEVEL_DUNGEON)
if (curr.level_type != LEVEL_DUNGEON && !force)
return;
if (lo == -1)
lo = hi = 1;
int nvaults = random_range(lo, hi);
if (!tag.empty())
{
for (int i = 0; i < nvaults; ++i)
{
const int vault = random_map_for_tag(tag, true);
if (vault == -1)
return;
build_minivaults(you.your_level, vault);
}
int chance = level_number == 0? 50 : 100;
while (chance && random2(100) < chance)
int chance = you.your_level == 0? 50 : 100;
while ((chance && random2(100) < chance) || nvaults-- > 0)
if (level_number >= 11 && level_number <= 23 && one_chance_in(15))
place_specific_stair(DNGN_ENTER_LABYRINTH);
if (one_chance_in(15))
place_specific_stair(DNGN_ENTER_LABYRINTH, "lab_entry",
level_number, true);
if (one_chance_in(20))
place_specific_stair(DNGN_ENTER_BAZAAR, "bzr_entry",
level_number, true);
}
////////////////////////////////////////////////////////////////////////
// Dungeon markers
map_marker::marker_reader
map_marker::readers[NUM_MAP_MARKER_TYPES] =
{
&map_feature_marker::read,
};
map_marker::map_marker(map_marker_type t, const coord_def &p)
: pos(p), type(t)
{
}
map_marker::~map_marker()
{
void map_marker::write(tagHeader &outf) const
{
marshallShort(outf, type);
marshallCoord(outf, pos);
}
void map_marker::read(tagHeader &inf)
{
// Don't read type! The type has to be read by someone who knows how
// to look up the unmarshall function.
unmarshallCoord(inf, pos);
}
map_marker *map_marker::read_marker(tagHeader &inf)
{
const map_marker_type type =
static_cast<map_marker_type>(unmarshallShort(inf));
return readers[type]? (*readers[type])(inf, type) : NULL;
}
////////////////////////////////////////////////////////////////////////////
// map_feature_marker
map_feature_marker::map_feature_marker(
const coord_def &p,
dungeon_feature_type _feat)
: map_marker(MAT_FEATURE, p), feat(_feat)
{
}
map_feature_marker::map_feature_marker(
const map_feature_marker &other)
: map_marker(MAT_FEATURE, other.pos), feat(other.feat)
{
}
void map_feature_marker::write(tagHeader &outf) const
{
this->map_marker::write(outf);
marshallShort(outf, feat);
}
void map_feature_marker::read(tagHeader &inf)
{
map_marker::read(inf);
feat = static_cast<dungeon_feature_type>(unmarshallShort(inf));
}
map_marker *map_feature_marker::read(tagHeader &inf, map_marker_type)
{
map_marker *mapf = new map_feature_marker();
mapf->read(inf);
return (mapf);
}
map_marker *map_feature_marker::clone() const
{
return new map_feature_marker(pos, feat);
}
std::string map_feature_marker::describe() const
{
return make_stringf("feature (%s)", dungeon_feature_name(feat));
}
std::string feature_description(int mx, int my);
std::string feature_description(int mx, int my,
description_level_type dtype = DESC_CAP_A,
bool add_stop = true);
std::string raw_feature_description(dungeon_feature_type grid,
trap_type tr = NUM_TRAPS,
bool temporary = false);
trap_type trap)
trap_type trap,
bool temporary,
description_level_type dtype,
bool add_stop)
{
std::string desc =
raw_feature_description(grid, trap, temporary);
if (add_stop)
desc += ".";
if (dtype == DESC_PLAIN || (!grid_is_trap(grid) && isupper(desc[0])))
return (desc);
switch (dtype)
{
case DESC_CAP_THE:
return "The " + desc;
case DESC_NOCAP_THE:
return "the " + desc;
case DESC_CAP_A:
return article_a(desc, false);
case DESC_NOCAP_A:
return article_a(desc, true);
default:
return (desc);
}
}
std::string raw_feature_description(dungeon_feature_type grid,
trap_type trap,
bool temporary)
return ("A labyrinth entrance.");
if (temporary)
return ("slowly fading labyrinth entrance");
else
return ("labyrinth entrance");
case DNGN_ENTER_BAZAAR:
if (temporary)
return ("gently fading gateway to a fabulous bazaar");
else
return ("gateway to a fabulous bazaar");
case DNGN_EXIT_BAZAAR:
return ("exit from the bazaar");
/*
* File: dgnevent.h
* Summary: General dungeon events.
*
* Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-07-20T11:40:25.964128Z $
*
*/
#ifndef __DGNEVENT_H__
#define __DGNEVENT_H__
#include "externs.h"
#include <list>
enum dgn_event_type
{
DET_NONE = 0x0000,
DET_TURN_ELAPSED = 0x0001,
DET_MONSTER_MOVED = 0x0002,
DET_PLAYER_MOVED = 0x0004,
DET_LEAVING_LEVEL = 0x0008,
DET_ENTERING_LEVEL = 0x0010
};
class dgn_event
{
public:
dgn_event_type type;
coord_def place;
int elapsed_ticks;
public:
dgn_event(dgn_event_type t, const coord_def &p = coord_def(),
int ticks = you.time_taken)
: type(t), place(p), elapsed_ticks(ticks)
{
}
};
class dgn_event_listener
{
public:
virtual ~dgn_event_listener();
virtual void notify_dgn_event(const dgn_event &e) = 0;
};
// Alarm goes off when something enters this square.
struct dgn_square_alarm
{
public:
dgn_square_alarm() : eventmask(0), listeners() { }
public:
unsigned eventmask;
std::list<dgn_event_listener*> listeners;
};
struct dgn_listener_def
{
public:
dgn_listener_def(unsigned mask, dgn_event_listener *l)
: eventmask(mask), listener(l)
{
}
public:
unsigned eventmask;
dgn_event_listener *listener;
};
// Listeners are not saved here. Map markers have their own
// persistence and activation mechanisms. Other listeners must make
// their own persistence arrangements.
class dgn_event_dispatcher
{
public:
dgn_event_dispatcher() : global_event_mask(0), grid_triggers()
{
}
void clear();
void fire_position_event(dgn_event_type et, const coord_def &pos);
void fire_event(dgn_event_type et);
void fire_event(const dgn_event &e);
void register_listener(unsigned evmask, dgn_event_listener *,
const coord_def &pos = coord_def());
void remove_listener(dgn_event_listener *,
const coord_def &pos = coord_def());
private:
void register_listener_at(unsigned mask, const coord_def &pos,
dgn_event_listener *l);
void remove_listener_at(const coord_def &pos, dgn_event_listener *l);
private:
unsigned global_event_mask;
std::auto_ptr<dgn_square_alarm> grid_triggers[GXM][GYM];
std::list<dgn_listener_def> listeners;
};
extern dgn_event_dispatcher dungeon_events;
#endif
/*
* File: dgnevent.cc
* Summary: General dungeon events.
*
* Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-07-20T11:40:25.964128Z $
*
*/
#include "AppHdr.h"
#include "dgnevent.h"
#include "stuff.h"
dgn_event_dispatcher dungeon_events;
void dgn_event_dispatcher::clear()
{
global_event_mask = 0;
listeners.clear();
for (int y = 0; y < GYM; ++y)
for (int x = 0; x < GXM; ++x)
grid_triggers[x][y].reset(NULL);
}
void dgn_event_dispatcher::fire_position_event(
dgn_event_type event, const coord_def &pos)
{
dgn_square_alarm *alarm = grid_triggers[pos.x][pos.y].get();
if (alarm && (alarm->eventmask & event))
{
dgn_square_alarm alcopy = *alarm;
const dgn_event et(event, pos);
for (std::list<dgn_event_listener*>::iterator
i = alcopy.listeners.begin();
i != alcopy.listeners.end(); ++i)
{
(*i)->notify_dgn_event(et);
}
}
}
void dgn_event_dispatcher::fire_event(const dgn_event &e)
{
if (global_event_mask & e.type)
{
std::list<dgn_listener_def> lcopy = listeners;
for (std::list<dgn_listener_def>::iterator i = lcopy.begin();
i != lcopy.end(); ++i)
{
if (i->eventmask & e.type)
i->listener->notify_dgn_event(e);
}
}
}
void dgn_event_dispatcher::fire_event(dgn_event_type et)
{
fire_event(dgn_event(et));
}
void dgn_event_dispatcher::register_listener(unsigned mask,
dgn_event_listener *listener,
const coord_def &pos)
{
if (in_bounds(pos))
register_listener_at(mask, pos, listener);
else
{
global_event_mask |= mask;
for (std::list<dgn_listener_def>::iterator i = listeners.begin();
i != listeners.end(); ++i)
{
if (i->listener == listener)
{
i->eventmask |= mask;
return;
}
}
listeners.push_back(dgn_listener_def(mask, listener));
}
}
void dgn_event_dispatcher::register_listener_at(unsigned mask,
const coord_def &c,
dgn_event_listener *listener)
{
if (!grid_triggers[c.x][c.y].get())
grid_triggers[c.x][c.y].reset(new dgn_square_alarm);
dgn_square_alarm *alarm = grid_triggers[c.x][c.y].get();
alarm->eventmask |= mask;
if (std::find(alarm->listeners.begin(), alarm->listeners.end(),
listener) == alarm->listeners.end())
alarm->listeners.push_back(listener);
}
void dgn_event_dispatcher::remove_listener(dgn_event_listener *listener,
const coord_def &pos)
{
if (in_bounds(pos))
remove_listener_at(pos, listener);
else
{
for (std::list<dgn_listener_def>::iterator i = listeners.begin();
i != listeners.end(); ++i)
{
if (i->listener == listener)
{
listeners.erase(i);
return;
}
}
}
}
void dgn_event_dispatcher::remove_listener_at(const coord_def &pos,
dgn_event_listener *listener)
{
if (dgn_square_alarm *alarm = grid_triggers[pos.x][pos.y].get())
{
std::list<dgn_event_listener*>::iterator i =
std::find(alarm->listeners.begin(), alarm->listeners.end(),
listener);
if (i != alarm->listeners.end())
alarm->listeners.erase(i);
}
}
/////////////////////////////////////////////////////////////////////////////
// dgn_event_listener
dgn_event_listener::~dgn_event_listener()
{
}
"entry.des", "elf.des", "float.des", "hells.des", "hive.des", "lab.des",
"lair.des", "large.des", "mini.des", "orc.des", "pan.des", "portal.des",
"temple.des", "vaults.des", "zot.des"
"bazaar.des", "entry.des", "elf.des", "float.des", "hells.des", "hive.des",
"lab.des", "lair.des", "large.des", "mini.des", "orc.des", "pan.des",
"portal.des", "temple.des", "vaults.des", "zot.des"
###############################################################################
# bazaar.des - Bazaar entry vaults and bazaar layouts.
###############################################################################
###############################################################################
# Bazaar entries
# Utility functions
lua {{
function check_expire_marker(e)
if not crawl.one_chance_in(3) then
e.marker("O = timer: 1000")
end
end
}}
default-depth: D:10-27
###############################################################################
# Dummy entry
NAME: bzr_entry_dummy
TAGS: bzr_entry transparent
ORIENT: float
: check_expire_marker(_G)
MAP
O
ENDMAP
###############################################################################
# A simple water entry.
NAME: bzr_entry_001
TAGS: bzr_entry no_pool_fixup
ORIENT: float
SHUFFLE: wwl
: check_expire_marker(_G)
MAP
www
w.w.w
wwOww
w.w.w
www
ENDMAP
###############################################################################
# Bazaar layouts.
#
# "encompass" levels are recommended, and can be as small or large as you like.
# No monsters are pre-placed in bazaars, and monsters do not spawn in bazaars,
# but you can place monsters in your maps if you know what you're doing.
NAME: bazaar_001
TAGS: bazaar
ORIENT: encompass
KFEAT: A = any shop
MAP
xxxxxxxxx
xxxx>xxxx
xxx...xxx
xx..A..xx
x<.A.A.>x
xx..A..xx
xxx...xxx
xxxx>xxxx
xxxxxxxxx
ENDMAP
if ((grd[you.x_pos][you.y_pos] < DNGN_ENTER_LABYRINTH
|| grd[you.x_pos][you.y_pos] > DNGN_ROCK_STAIRS_DOWN)
&& grd[you.x_pos][you.y_pos] != DNGN_ENTER_HELL
&& ((grd[you.x_pos][you.y_pos] < DNGN_ENTER_DIS
|| grd[you.x_pos][you.y_pos] > DNGN_TRANSIT_PANDEMONIUM)
&& grd[you.x_pos][you.y_pos] != DNGN_STONE_ARCH)
&& !(grd[you.x_pos][you.y_pos] >= DNGN_ENTER_ORCISH_MINES
&& grd[you.x_pos][you.y_pos] < DNGN_RETURN_FROM_ORCISH_MINES))
if (grid_stair_direction(grd(you.pos())) != CMD_GO_DOWNSTAIRS)
If chosen, these maps will contain the stairs for that branch.
Use "O" to place the stairs. Branch entries should go to
ebranch.des. If a branch has very few entries, a dummy entry is
advisable to make sure the player doesn't get bored of the same
few entries recycled ad nauseam.
If chosen, these maps will contain the stairs for that
branch. Use "O" to place the stairs. If a branch has very
few entries, a dummy entry is advisable to make sure the
player doesn't get bored of the same few entries recycled
ad nauseam.
mpr, mesclr, random2, redraw_screen, input_line, c_input_line, getch, kbhit,
flush_input, sendkeys, playsound, runmacro, bindkey, setopt, msgch_num,
msgch_name, regex, message_filter, trim, split, game_started, err_trace, args
mpr, mesclr, random2, coinflip, one_chance_in, redraw_screen,
input_line, c_input_line, getch, kbhit, flush_input, sendkeys,
playsound, runmacro, bindkey, setopt, msgch_num, msgch_name, regex,
message_filter, trim, split, game_started, err_trace, args
turn_is_over, spells, abilities, name, race, class, god, hp, mp, hunger,
strength, intelligence, dexterity, xl, exp, res_poison, res_fire, res_cold,
res_draining, res_shock, res_statdrain, res_mutation, res_slowing, gourmand,
levitating, flying, transform, stop_activity, floor_items, where, branch,
subdepth, absdepth
turn_is_over, spells, abilities, name, race, class, god, hp, mp,
hunger, strength, intelligence, dexterity, xl, exp, res_poison,
res_fire, res_cold, res_draining, res_shock, res_statdrain,
res_mutation, res_slowing, gourmand, levitating, flying, transform,
stop_activity, floor_items, where, branch, subdepth, absdepth