git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@6875 c06c8d41-db1a-0410-9941-cceddc491573
3SQQ4MM6YO4I37CQ6GIBIX6BXAEVHNVNHPVMR3PPBBNO454D6XWQC
WQSH2ITHKHQAONM55ME7JXLZYL6OQS5F477U66P2R5VHJVI2Q22QC
RFXNLDTX4EUIJAHEFKPBPFWDZTYFU5AGGI35EEBCONLBPXL5D5FQC
UX6M56N7WTF6B3OTKUFTONBUFZXNEL4SKQT22Q7IVFOBM25LKQ3AC
4EOIRJBTEWVOK4EXA4XAWWS5CHAWZHAYRO6BRZWZ2SU2CGKV6VQAC
5HRXXWHM5JHDZBCSUD65GYSQIFRD77DYV5PDAJZU4JTE4ZPH3LQAC
BCL6BB7HZXAJCAGKK6MZ7AGWNLFP46FIXRVGJ6LR3QLDE6XFQGVAC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
Q3B3UVMYEVC4YJUPYVSNTR4DJH4E6J4JJDHZNT5LNOCHCPPMEMXAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
25CH7HH4LKXFIZ75YNMXS3TSXO6O27DYSOPLOD45K4OCNFWLS4LQC
HBXWZNXAJ7LUX7FYUIHQYBTRMWVJC6CAQQL3NNZHK5ETLIFEZJ7QC
PBRFKFYILME3A2YLLVGRWJ2C7PCE2GONSINX65P4EG22ZGCW6JWAC
66KRMFZAWM65VI75Z6O4CIVCKB3Z2YQCQSGE44OAP6ESTEFUWYOQC
PEZFWKRHDHV4UJTPK5XJZ3CGTZ3LPTDYSPTYBENLQ7VRSP7YFSIQC
U6ILMKBXTQZYT62IGD2CALYNU4VQGRSTHN6QBFBU7BVUBHWYOEQQC
YP2ADVIVFDLAU4NYFG7BTHV6BMH7VPKUYQ6WVQF3Z725L3DSX7HAC
7G4KWTOOBRLHOZZGFGAXGTUCDF3FGSZOXVHUZZ3V2KVWYSFE7EKAC
GPEJOT73KMACP33IPAKFR5ROGHCOIP22VXZMQNYTGLEA2OSZUM2AC
L57WEZMVIHTFRLWVIPWOIOWHCF2I53TVUVYJ2V6IZ64R56FVTZZAC
4SUUJM2DQUEWHDG3UKJUDZABLHFVF2CFUX5GVAWKT7BBBGR2ISTQC
LP5EK64IEM7AHNYQID4GGKOQJQNZLKY4DCCZN47SIUZ6IXAXH5UAC
5FA5IEAXTMXYS2VUBVDKBKHPKAIOY4GN5SXYJORBYWQIGHVW3FFQC
ND3T5LCZATC63EVQ6SLI7XXMSUL7XICJDNLH3UCYUDEFWTA3N5MQC
CSRWDG2SUGS4YR4PAFI574EGEXW65P6JDT4ZHWDICS2G2GZIGEUQC
D7EPLNYHJH6C4CTMHCOUUODKGHCJRE4CGKNVSCHCSABN6ZOD2ZBAC
YMC3RKF4Z7DOHZNGG7INC343SXCTWOPK7ISD42I3WA3AZZNVBGIAC
J3M6J3UPL4AUJDXINY7UKH2JZQVQLKGH7AMOKI6L3QI7Y2F33O5QC
33QMQXTWFPR4LUBHEWTFGR74L5QJJDQTT5JZRBFTPDQBPXIHQIUQC
UL7XFKMUX3WIU4O2LZANK4ECJ654UZPDBFGNXUEYZYOLKBYBCG6AC
C4WXQRJTDW53PYFWQ4LOINSCI2IWMIQTH5WDSI7QUP72PKDBYHZAC
5ASC3STDYCNLZFEBN6UTMUCGDETHBR2OCBZCF5VIAZ5RRWLOTDYQC
T7CUIVICB74342RA32BR37T36FOX4RBSQIB5PNOHTGTGUYGDKSTQC
PSCYVKJ7DGXAL3V5U4O6AJTRV6Q3N3SHQWAZ73VIPRTE4W64F2XAC
7AMQN7MITMXBNVDAK5VOXTQ4TZIAOD6ZLOFJG7GQMBTY23Y2BKSAC
7HA2754QW3SBCAJ5K6KUXNXXXIZB5BIBCFPLXADCXHH6EREKXHSAC
NVSFIV2ZKP44XHCSCXG6OZVGL67OIFINC34J2EMKTA4KULCERUEAC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
IE3INS4WUXZOBVXB5VWRBYPVPXADD2U2W5H3TBTOYNWJ3EGRSGQQC
JCWJWGMQIKQGSSFJUQRKNIWW3HBOJSHYDTOPPE5BWOJTIJTDYUTAC
6L4EP4ZRWWYLT55PD5KTTJON5J2JB5VV5MWNHF5VPZQZ5BKEYZ4QC
I2G7DP3TJL4RDMYKNXAA67P3VRSO3RF7FHZWA5CYINSEWEQE2YSQC
// init ghost tile
void TileGhostInit(const struct ghost_demon &gs);
// init pandem demon tile (only in iso mode)
void TilePandemInit(struct ghost_demon &gs);
// edit pandem tile (debug)
void TileEditPandem();
// monster+weapon tile
void tile_mcache_unlock();
int get_base_idx_from_mcache(int tile_idx);
void tile_get_monster_weapon_offset(int mon_tile, int &ofs_x, int &ofs_y);
bool get_mcache_entry(int tile_idx, int &mon_idx, int &equ_tile, int &draco);
}
bool DungeonRegion::draw_objects(unsigned int fg, unsigned int x, unsigned int y)
{
unsigned int fg_idx = fg & TILE_FLAG_MASK;
// handled elsewhere
if (fg_idx == TILE_PLAYER)
return false;
int equ_tile;
int draco;
int mon_tile;
if (get_mcache_entry(fg_idx, mon_tile, equ_tile, draco))
{
if (!draco)
add_quad(TEX_DEFAULT, get_base_idx_from_mcache(fg_idx), x, y);
return true;
}
else if (fg_idx)
{
add_quad(TEX_DEFAULT, fg_idx, x, y);
}
return false;
int armour = 0;
int armour2 = 0;
int weapon = 0;
int weapon2 = 0;
int arm = 0;
for (int i = 0; i < TILEP_PART_MAX; i++)
doll.parts[i] = 0;
const dolls_data *doll = entry->doll();
if (doll)
draw_doll(*doll, x, y);
doll.parts[TILEP_PART_SHADOW] = TILEP_SHADOW_SHADOW;
doll.parts[TILEP_PART_BASE] = TILEP_BASE_DRACONIAN + colour * 2;
doll.parts[TILEP_PART_DRCWING] = tile_player_part_start[TILEP_PART_DRCWING]
+ colour;
doll.parts[TILEP_PART_DRCHEAD] = tile_player_part_start[TILEP_PART_DRCHEAD]
+ colour;
tile_draw_info dinfo[3];
unsigned int draw_info_count = entry->info(&dinfo[0]);
ASSERT(draw_info_count <= sizeof(dinfo) / (sizeof(dinfo[0])));
switch (mon_idx)
{
case MONS_DRACONIAN_CALLER:
weapon = TILEP_HAND1_STAFF_EVIL;
weapon2 = TILEP_HAND2_BOOK_YELLOW;
armour = TILEP_BODY_ROBE_BROWN;
break;
case MONS_DRACONIAN_MONK:
arm = TILEP_ARM_GLOVE_SHORT_BLUE;
armour = TILEP_BODY_KARATE2;
break;
case MONS_DRACONIAN_ZEALOT:
weapon = TILEP_HAND1_MACE;
weapon2 = TILEP_HAND2_BOOK_CYAN;
armour = TILEP_BODY_MONK_BLUE;
break;
case MONS_DRACONIAN_SHIFTER:
weapon = TILEP_HAND1_STAFF_LARGE;
armour = TILEP_BODY_ROBE_CYAN;
weapon2 = TILEP_HAND2_BOOK_GREEN;
break;
case MONS_DRACONIAN_ANNIHILATOR:
weapon = TILEP_HAND1_STAFF_RUBY;
weapon2 = TILEP_HAND2_FIRE_CYAN;
armour = TILEP_BODY_ROBE_GREEN_GOLD;
break;
case MONS_DRACONIAN_KNIGHT:
weapon = equ_tile;
weapon2 = TILEP_HAND2_SHIELD_KNIGHT_GRAY;
armour = TILEP_BODY_BPLATE_METAL1;
armour2 = TILEP_LEG_BELT_GRAY;
break;
case MONS_DRACONIAN_SCORCHER:
weapon = TILEP_HAND1_FIRE_RED;
weapon2 = TILEP_HAND2_BOOK_RED;
armour = TILEP_BODY_ROBE_RED;
break;
default:
weapon = equ_tile;
armour = TILEP_BODY_BELT2;
armour2 = TILEP_LEG_LOINCLOTH_RED;
break;
}
doll.parts[TILEP_PART_HAND1] = weapon;
doll.parts[TILEP_PART_HAND2] = weapon2;
doll.parts[TILEP_PART_BODY] = armour;
doll.parts[TILEP_PART_LEG] = armour2;
doll.parts[TILEP_PART_ARM] = arm;
draw_doll(doll, x, y);
for (unsigned int i = 0; i < draw_info_count; i++)
add_quad(TEX_DOLL, dinfo[i].idx, x, y, dinfo[i].ofs_x, dinfo[i].ofs_y);
if (fg_idx < TILE_MCACHE_START)
return;
int equ_tile;
int draco;
int mon_tile;
if (!get_mcache_entry(fg_idx, mon_tile, equ_tile, draco))
return;
if (draco == 0)
{
int ofs_x, ofs_y;
tile_get_monster_weapon_offset(mon_tile, ofs_x, ofs_y);
add_quad(TEX_DOLL, equ_tile, x, y, ofs_x, ofs_y, true, TILE_Y);
unsigned int bg_idx = bg & TILE_FLAG_MASK;
// In some cases, overlay a second weapon tile...
if (mon_tile == TILE_MONS_DEEP_ELF_BLADEMASTER)
{
int eq2;
switch (equ_tile)
{
case TILEP_HAND1_DAGGER:
eq2 = TILEP_HAND2_DAGGER;
break;
case TILEP_HAND1_SABRE:
eq2 = TILEP_HAND2_SABRE;
break;
default:
case TILEP_HAND1_SHORT_SWORD_SLANT:
eq2 = TILEP_HAND2_SHORT_SWORD_SLANT;
break;
};
add_quad(TEX_DOLL, eq2, x, y, -ofs_x, ofs_y, true, TILE_Y);
}
}
else
if (fg_idx && fg_idx <= TILE_MAIN_MAX)
int colour;
switch (draco)
{
default:
case MONS_DRACONIAN: colour = 0; break;
case MONS_BLACK_DRACONIAN: colour = 1; break;
case MONS_YELLOW_DRACONIAN: colour = 2; break;
case MONS_GREEN_DRACONIAN: colour = 4; break;
case MONS_MOTTLED_DRACONIAN:colour = 5; break;
case MONS_PALE_DRACONIAN: colour = 6; break;
case MONS_PURPLE_DRACONIAN: colour = 7; break;
case MONS_RED_DRACONIAN: colour = 8; break;
case MONS_WHITE_DRACONIAN: colour = 9; break;
}
draw_draco(colour, mon_tile, equ_tile, x, y);
add_quad(TEX_DEFAULT, fg_idx, x, y);
m_textures[TEX_DUNGEON].set_info(TILE_DNGN_MAX, &tile_dngn_info[0]);
m_textures[TEX_DOLL].set_info(TILEP_PLAYER_MAX, &tile_player_info[0]);
m_textures[TEX_DUNGEON].set_info(TILE_DNGN_MAX, &tile_dngn_info);
m_textures[TEX_DOLL].set_info(TILEP_PLAYER_MAX, &tile_player_info);
struct mcache_entry
{
int mon_tile;
int equ_tile;
int draco;
};
static std::vector<mcache_entry> mcache;
int get_base_idx_from_mcache(int tile_idx)
{
int mcache_idx = tile_idx - TILE_MCACHE_START;
if (mcache_idx >= 0 && mcache_idx < (int)mcache.size())
{
return mcache[mcache_idx].mon_tile;
}
return tile_idx;
}
bool get_mcache_entry(int tile_idx, int &mon_idx, int &equ_tile, int &draco)
{
int mcache_idx = tile_idx - TILE_MCACHE_START;
if (mcache_idx >= 0 && (unsigned int)mcache_idx < mcache.size())
{
mon_idx = mcache[mcache_idx].mon_tile;
equ_tile = mcache[mcache_idx].equ_tile;
draco = mcache[mcache_idx].draco;
return true;
}
return false;
}
static int _mcache_register(int mon_tile, int equ_tile, int draco = 0)
{
mcache_entry entry;
entry.mon_tile = mon_tile;
entry.equ_tile = equ_tile;
entry.draco = draco;
mcache.push_back(entry);
int idx = TILE_MCACHE_START + mcache.size() - 1;
return idx;
}
ASSERT(mon_idx != -1);
int ch = _tileidx_monster_base(mon_idx, detected);
const monsters* mons = &menv[mon_idx];
int ch = _tileidx_monster_base(mons, detected);
case 's': ch = TILE_MONS_WOLF_SPIDER; break;
case 'I': ch = TILE_MONS_ICE_BEAST; break;
case '8': ch = TILE_MONS_STONE_GOLEM; break;
case 'D': ch = TILE_MONS_DRAGON; break;
case 'L': ch = TILE_MONS_LICH; break;
case '#': ch = TILE_MONS_VAPOUR; break;
case 'S': ch = TILE_MONS_LAVA_SNAKE; break;
case 'b': ch = TILE_MONS_GIANT_BAT; break;
case 's': ch = TILEP_MONS_WOLF_SPIDER; break;
case 'I': ch = TILEP_MONS_ICE_BEAST; break;
case '8': ch = TILEP_MONS_STONE_GOLEM; break;
case 'D': ch = TILEP_MONS_DRAGON; break;
case 'L': ch = TILEP_MONS_LICH; break;
case '#': ch = TILEP_MONS_VAPOUR; break;
case 'S': ch = TILEP_MONS_LAVA_SNAKE; break;
case 'b': ch = TILEP_MONS_GIANT_BAT; break;
int race = draco_subspecies(&menv[idx]);
int cls = menv[idx].type;
int eq = 0;
if (mon_wep != NON_ITEM &&
(cls == race || cls == MONS_DRACONIAN_KNIGHT))
{
eq = tilep_equ_weapon(mitm[mon_wep]);
}
t = flag | _mcache_register(cls, eq, race);
unsigned int mcache_idx = mcache.register_monster(&menv[idx]);
t = flag | (mcache_idx ? mcache_idx : t0);
else if (mon_wep != NON_ITEM)
{
int eq = tilep_equ_weapon(mitm[mon_wep]);
switch(t0)
{
// 3D chars
case TILE_MONS_VAULT_GUARD:
case TILE_MONS_BLORK_THE_ORC:
case TILE_MONS_ORC:
case TILE_MONS_ORC_KNIGHT:
case TILE_MONS_ORC_WARLORD:
case TILE_MONS_ORC_WARRIOR:
case TILE_MONS_URUG:
case TILE_MONS_GOBLIN:
case TILE_MONS_IJYB:
case TILE_MONS_HOBGOBLIN:
case TILE_MONS_GNOLL:
case TILE_MONS_BOGGART:
case TILE_MONS_KOBOLD:
case TILE_MONS_KOBOLD_DEMONOLOGIST:
case TILE_MONS_BIG_KOBOLD:
case TILE_MONS_DEEP_ELF_FIGHTER:
case TILE_MONS_DEEP_ELF_SOLDIER:
case TILE_MONS_DEEP_ELF_KNIGHT:
case TILE_MONS_DEEP_ELF_BLADEMASTER:
case TILE_MONS_DEEP_ELF_MASTER_ARCHER:
case TILE_MONS_DEEP_ELF_MAGE:
case TILE_MONS_DEEP_ELF_SUMMONER:
case TILE_MONS_DEEP_ELF_CONJURER:
case TILE_MONS_DEEP_ELF_PRIEST:
case TILE_MONS_DEEP_ELF_HIGH_PRIEST:
case TILE_MONS_DEEP_ELF_DEMONOLOGIST:
case TILE_MONS_DEEP_ELF_ANNIHILATOR:
case TILE_MONS_DEEP_ELF_SORCERER:
case TILE_MONS_DEEP_ELF_DEATH_MAGE:
case TILE_MONS_MIDGE:
case TILE_MONS_IMP:
case TILE_MONS_NAGA:
case TILE_MONS_GREATER_NAGA:
case TILE_MONS_NAGA_WARRIOR:
case TILE_MONS_NAGA_MAGE:
case TILE_MONS_OGRE_MAGE:
case TILE_MONS_RED_DEVIL:
case TILE_MONS_WIZARD:
case TILE_MONS_HUMAN:
case TILE_MONS_ELF:
case TILE_MONS_ANGEL:
case TILE_MONS_HELL_KNIGHT:
case TILE_MONS_NORRIS:
case TILE_MONS_MAUD:
case TILE_MONS_DUANE:
case TILE_MONS_EDMUND:
case TILE_MONS_FRANCES:
case TILE_MONS_HAROLD:
case TILE_MONS_JOSEPH:
case TILE_MONS_JOZEF:
case TILE_MONS_RUPERT:
case TILE_MONS_TERENCE:
case TILE_MONS_WAYNE:
case TILE_MONS_FREDERICK:
case TILE_MONS_RAKSHASA:
case TILE_MONS_RAKSHASA_FAKE:
case TILE_MONS_VAMPIRE_KNIGHT:
case TILE_MONS_SKELETAL_WARRIOR:
case TILE_MONS_MERMAID:
case TILE_MONS_MERMAID_WATER:
case TILE_MONS_MERFOLK_FIGHTER:
case TILE_MONS_MERFOLK_FIGHTER_WATER:
if (eq != 0 )
t = flag | _mcache_register(t0, eq);
break;
}
}
tiles.add_text_tag(TAG_NAMED_MONSTER,
menv[idx].name(DESC_CAP_A), gc);
if (menv[idx].type == MONS_PLAYER_GHOST)
{
// Beautification hack. "Foo's ghost" is a little bit
// verbose as a tag. "Foo" on its own should be sufficient.
tiles.add_text_tag(TAG_NAMED_MONSTER, menv[idx].mname, gc);
}
else
{
tiles.add_text_tag(TAG_NAMED_MONSTER,
menv[idx].name(DESC_CAP_A), gc);
}
/*
* File: tilemcache.h
* Summary: Monster cache support
* Written by: Enne Walker
*/
#ifdef USE_TILE
#ifndef TILEMCACHE_H
#define TILEMCACHE_H
#include "AppHdr.h"
#include "debug.h"
#include <vector>
// The monster cache is designed to hold extra information about monsters that
// can't be contained in a single tile. This is usually for equipment,
// doll parts, or demon parts.
//
// Monster cache entries for monsters that are out of sight are ref-counted
// that they can be drawn even if that monster no longer exists. When no
// out-of-sight tiles refer to them, they can be deleted.
class tile_draw_info
{
public:
tile_draw_info() : idx(~0), ofs_x(0), ofs_y(0) {}
void set(unsigned int _idx, int _ofs_x = 0, int _ofs_y = 0)
{ idx = _idx; _ofs_x = ofs_x; _ofs_y = ofs_y; }
unsigned int idx;
int ofs_x;
int ofs_y;
};
class mcache_entry
{
public:
mcache_entry() : m_ref_count(0) {}
virtual ~mcache_entry() {}
void inc_ref() { m_ref_count++; }
void dec_ref() { m_ref_count--; ASSERT(m_ref_count >= 0); }
int ref_count() { return m_ref_count; }
virtual unsigned int info(tile_draw_info *dinfo) const { return 0; }
virtual const dolls_data *doll() const { return NULL; }
virtual void construct(writer &th);
protected:
mcache_entry(reader &th);
// ref count in backstore
int m_ref_count;
};
class mcache_manager
{
public:
~mcache_manager();
unsigned int register_monster(const monsters *mon);
mcache_entry *get(unsigned int idx);
void clear_nonref();
void clear_all();
void read(reader &th);
void construct(writer &th);
protected:
std::vector<mcache_entry*> m_entries;
};
// The global monster cache.
extern mcache_manager mcache;
#endif
#endif
#include "tilemcache.h"
#include "tags.h"
#include "ghost.h"
#include "mon-util.h"
mcache_manager mcache;
// Used internally for streaming
enum mcache_type
{
MCACHE_MONSTER,
MCACHE_DRACO,
MCACHE_GHOST,
MCACHE_DEMON,
MCACHE_MAX,
MCACHE_NULL
};
// Custom marshall/unmarshall functions.
static void unmarshallDoll(reader &th, dolls_data &doll)
{
for (unsigned int i = 0; i < TILEP_PART_MAX; i++)
{
doll.parts[i] = unmarshallLong(th);
}
}
static void marshallDoll(writer &th, const dolls_data &doll)
{
for (unsigned int i = 0; i < TILEP_PART_MAX; i++)
{
marshallLong(th, doll.parts[i]);
}
}
static void unmarshallDemon(reader &th, demon_data &demon)
{
demon.head = unmarshallLong(th);
demon.body = unmarshallLong(th);
demon.wings = unmarshallLong(th);
}
static void marshallDemon(writer &th, const demon_data &demon)
{
marshallLong(th, demon.head);
marshallLong(th, demon.body);
marshallLong(th, demon.wings);
}
// Internal mcache classes. The mcache_manager creates these internally.
// The only access external clients need is through the virtual
// info function.
class mcache_monster : public mcache_entry
{
public:
mcache_monster(const monsters *mon);
mcache_monster(reader &th);
virtual unsigned int info(tile_draw_info *dinfo) const;
static bool valid(const monsters *mon);
static bool get_weapon_offset(int mon_tile, int &ofs_x, int &ofs_y);
virtual void construct(writer &th);
protected:
int m_mon_tile;
int m_equ_tile;
};
class mcache_draco : public mcache_entry
{
public:
mcache_draco(const monsters *mon);
mcache_draco(reader &th);
virtual const dolls_data *doll() const;
static bool valid(const monsters *mon);
virtual void construct(writer &th);
protected:
dolls_data m_doll;
};
class mcache_ghost : public mcache_entry
{
public:
mcache_ghost(const monsters *mon);
mcache_ghost(reader &th);
virtual const dolls_data *doll() const;
static bool valid(const monsters *mon);
virtual void construct(writer &th);
protected:
dolls_data m_doll;
};
class mcache_demon : public mcache_entry
{
public:
mcache_demon(const monsters *mon);
mcache_demon(reader &th);
virtual unsigned int info(tile_draw_info *dinfo) const;
static bool valid(const monsters *mon);
virtual void construct(writer &th);
protected:
demon_data m_demon;
};
/////////////////////////////////////////////////////////////////////////////
// tile_fg_store
unsigned int tile_fg_store::operator=(unsigned int tile)
{
if (tile & TILE_FLAG_MASK == m_tile & TILE_FLAG_MASK)
{
// update, as flags may have changed.
m_tile = tile;
return m_tile;
}
mcache_entry *old_entry = mcache.get(m_tile);
if (old_entry)
old_entry->dec_ref();
m_tile = tile;
mcache_entry *new_entry = mcache.get(m_tile);
if (new_entry)
new_entry->inc_ref();
return m_tile;
}
/////////////////////////////////////////////////////////////////////////////
// mcache_manager
mcache_manager::~mcache_manager()
{
clear_all();
}
unsigned int mcache_manager::register_monster(const monsters *mon)
{
assert(mon);
if (!mon)
return 0;
// TODO enne - is it worth it to search against all mcache entries?
// TODO enne - pool mcache types to avoid too much alloc/dealloc?
mcache_entry *entry;
if (mcache_demon::valid(mon))
{
entry = new mcache_demon(mon);
}
else if (mcache_ghost::valid(mon))
{
entry = new mcache_ghost(mon);
}
else if (mcache_draco::valid(mon))
{
entry = new mcache_draco(mon);
}
else if (mcache_monster::valid(mon))
{
entry = new mcache_monster(mon);
}
else
{
return 0;
}
unsigned int idx = ~0;
for (unsigned int i = 0; i < m_entries.size(); i++)
{
if (!m_entries[i])
{
m_entries[i] = entry;
idx = i;
break;
}
}
if (idx > m_entries.size())
{
idx = m_entries.size();
m_entries.push_back(entry);
}
return TILEP_MCACHE_START + idx;
}
void mcache_manager::clear_nonref()
{
for (unsigned int i = 0; i < m_entries.size(); i++)
{
if (!m_entries[i] || m_entries[i]->ref_count() > 0)
continue;
delete m_entries[i];
m_entries[i] = NULL;
}
}
void mcache_manager::clear_all()
{
for (unsigned int i = 0; i < m_entries.size(); i++)
{
delete m_entries[i];
}
m_entries.resize(0);
}
mcache_entry *mcache_manager::get(unsigned int tile)
{
unsigned int idx = tile & TILE_FLAG_MASK;
if (idx < TILEP_MCACHE_START)
return NULL;
if (idx >= TILEP_MCACHE_START + m_entries.size())
return NULL;
mcache_entry *entry = m_entries[idx - TILEP_MCACHE_START];
return (entry);
}
void mcache_manager::read(reader &th)
{
unsigned int size = unmarshallLong(th);
m_entries.reserve(size);
m_entries.clear();
for (unsigned int i = 0; i < size; i++)
{
char type = unmarshallByte(th);
mcache_entry *entry;
switch (type)
{
case MCACHE_MONSTER:
entry = new mcache_monster(th);
break;
case MCACHE_DRACO:
entry = new mcache_draco(th);
break;
case MCACHE_GHOST:
entry = new mcache_ghost(th);
break;
case MCACHE_DEMON:
entry = new mcache_demon(th);
break;
default:
ASSERT(!"Invalid streamed mcache type.");
case MCACHE_NULL:
entry = NULL;
break;
}
m_entries.push_back(entry);
}
}
void mcache_manager::construct(writer &th)
{
marshallLong(th, m_entries.size());
for (unsigned int i = 0; i < m_entries.size(); i++)
{
if (m_entries[i] == NULL)
{
marshallByte(th, MCACHE_NULL);
continue;
}
if (dynamic_cast<mcache_monster*>(m_entries[i]))
marshallByte(th, MCACHE_MONSTER);
else if (dynamic_cast<mcache_draco*>(m_entries[i]))
marshallByte(th, MCACHE_DRACO);
else if (dynamic_cast<mcache_ghost*>(m_entries[i]))
marshallByte(th, MCACHE_GHOST);
else if (dynamic_cast<mcache_demon*>(m_entries[i]))
marshallByte(th, MCACHE_DEMON);
else
{
marshallByte(th, MCACHE_NULL);
continue;
}
m_entries[i]->construct(th);
}
}
/////////////////////////////////////////////////////////////////////////////
// mcache_entry
mcache_entry::mcache_entry(reader &th)
{
m_ref_count = unmarshallLong(th);
}
void mcache_entry::construct(writer &th)
{
marshallLong(th, m_ref_count);
}
/////////////////////////////////////////////////////////////////////////////
// mcache_monster
mcache_monster::mcache_monster(const monsters *mon)
{
assert(mcache_monster::valid(mon));
m_mon_tile = tileidx_monster(mon, false) & TILE_FLAG_MASK;
int mon_wep = mon->inv[MSLOT_WEAPON];
m_equ_tile = tilep_equ_weapon(mitm[mon_wep]);
}
bool mcache_monster::get_weapon_offset(int mon_tile, int &ofs_x, int &ofs_y)
{
switch (mon_tile)
{
case TILEP_MONS_VAULT_GUARD:
case TILEP_MONS_HOBGOBLIN:
case TILEP_MONS_DEEP_ELF_MASTER_ARCHER:
case TILEP_MONS_IMP:
case TILEP_MONS_ANGEL:
case TILEP_MONS_NORRIS:
case TILEP_MONS_MAUD:
case TILEP_MONS_DUANE:
case TILEP_MONS_EDMUND:
case TILEP_MONS_FRANCES:
case TILEP_MONS_HAROLD:
case TILEP_MONS_JOSEPH:
case TILEP_MONS_JOZEF:
case TILEP_MONS_RUPERT:
case TILEP_MONS_TERENCE:
case TILEP_MONS_WAYNE:
case TILEP_MONS_FREDERICK:
case TILEP_MONS_RAKSHASA:
case TILEP_MONS_RAKSHASA_FAKE:
case TILEP_MONS_VAMPIRE_KNIGHT:
case TILEP_MONS_SKELETAL_WARRIOR:
case TILEP_MONS_MERMAID:
case TILEP_MONS_MERMAID_WATER:
case TILEP_MONS_MERFOLK_FIGHTER:
case TILEP_MONS_MERFOLK_FIGHTER_WATER:
ofs_x = 0;
ofs_y = 0;
break;
case TILEP_MONS_ORC:
case TILEP_MONS_URUG:
case TILEP_MONS_BLORK_THE_ORC:
case TILEP_MONS_ORC_WARRIOR:
case TILEP_MONS_ORC_KNIGHT:
case TILEP_MONS_ORC_WARLORD:
ofs_x = 0;
ofs_y = 2;
break;
case TILEP_MONS_GOBLIN:
case TILEP_MONS_IJYB:
ofs_x = 0;
ofs_y = 4;
break;
case TILEP_MONS_GNOLL:
ofs_x = -1;
ofs_y = 0;
break;
case TILEP_MONS_BOGGART:
case TILEP_MONS_DEEP_ELF_FIGHTER:
case TILEP_MONS_DEEP_ELF_SOLDIER:
ofs_x = 0;
ofs_y = 2;
break;
case TILEP_MONS_DEEP_ELF_KNIGHT:
ofs_x = 0;
ofs_y = 1;
break;
case TILEP_MONS_KOBOLD:
ofs_x = 3;
ofs_y = 4;
break;
case TILEP_MONS_KOBOLD_DEMONOLOGIST:
ofs_x = 0;
ofs_y = -10;
break;
case TILEP_MONS_BIG_KOBOLD:
ofs_x = 2;
ofs_y = 3;
break;
case TILEP_MONS_MIDGE:
ofs_x = 0;
ofs_y = -2;
break;
case TILEP_MONS_NAGA:
case TILEP_MONS_GREATER_NAGA:
case TILEP_MONS_NAGA_WARRIOR:
case TILEP_MONS_GUARDIAN_NAGA:
case TILEP_MONS_NAGA_MAGE:
ofs_x = 0;
ofs_y = 1;
break;
case TILEP_MONS_HELL_KNIGHT:
ofs_x = -1;
ofs_y = 3;
break;
case TILEP_MONS_RED_DEVIL:
ofs_x = 2;
ofs_y = -3;
break;
case TILEP_MONS_WIZARD:
ofs_x = 2;
ofs_y = -2;
break;
case TILEP_MONS_HUMAN:
ofs_x = 5;
ofs_y = 2;
break;
case TILEP_MONS_ELF:
ofs_y = 1;
ofs_x = 4;
break;
case TILEP_MONS_OGRE_MAGE:
ofs_y = -2;
ofs_x = -4;
break;
case TILEP_MONS_DEEP_ELF_MAGE:
case TILEP_MONS_DEEP_ELF_SUMMONER:
case TILEP_MONS_DEEP_ELF_CONJURER:
case TILEP_MONS_DEEP_ELF_PRIEST:
case TILEP_MONS_DEEP_ELF_HIGH_PRIEST:
case TILEP_MONS_DEEP_ELF_DEMONOLOGIST:
case TILEP_MONS_DEEP_ELF_ANNIHILATOR:
case TILEP_MONS_DEEP_ELF_SORCERER:
ofs_x = -1;
ofs_y = -2;
break;
case TILEP_MONS_DEEP_ELF_DEATH_MAGE:
ofs_x = -1;
ofs_y = 0;
break;
default:
// This monster cannot be displayed with a weapon.
return false;
}
return true;
}
unsigned int mcache_monster::info(tile_draw_info *dinfo) const
{
int ofs_x, ofs_y;
get_weapon_offset(m_mon_tile, ofs_x, ofs_y);
dinfo[0].set(m_mon_tile);
dinfo[1].set(m_equ_tile, ofs_x, ofs_y);
// In some cases, overlay a second weapon tile...
if (m_mon_tile == TILEP_MONS_DEEP_ELF_BLADEMASTER)
{
int eq2;
switch (m_equ_tile)
{
case TILEP_HAND1_DAGGER:
eq2 = TILEP_HAND2_DAGGER;
break;
case TILEP_HAND1_SABRE:
eq2 = TILEP_HAND2_SABRE;
break;
default:
case TILEP_HAND1_SHORT_SWORD_SLANT:
eq2 = TILEP_HAND2_SHORT_SWORD_SLANT;
break;
};
dinfo[2].set(eq2, -ofs_x, ofs_y);
return 3;
}
else
{
return 2;
}
}
bool mcache_monster::valid(const monsters *mon)
{
if (!mon)
return false;
int mon_wep = mon->inv[MSLOT_WEAPON];
if (mon_wep == NON_ITEM)
return false;
int mon_tile = tileidx_monster(mon, false) & TILE_FLAG_MASK;
int ox, oy;
return get_weapon_offset(mon_tile, ox, oy);
}
mcache_monster::mcache_monster(reader &th) : mcache_entry(th)
{
m_mon_tile = unmarshallLong(th);
m_equ_tile = unmarshallLong(th);
}
void mcache_monster::construct(writer &th)
{
mcache_entry::construct(th);
marshallLong(th, m_mon_tile);
marshallLong(th, m_equ_tile);
}
/////////////////////////////////////////////////////////////////////////////
// mcache_draco
mcache_draco::mcache_draco(const monsters *mon)
{
assert(mcache_draco::valid(mon));
int draco = draco_subspecies(mon);
int colour;
switch (draco)
{
default:
case MONS_DRACONIAN: colour = 0; break;
case MONS_BLACK_DRACONIAN: colour = 1; break;
case MONS_YELLOW_DRACONIAN: colour = 2; break;
case MONS_GREEN_DRACONIAN: colour = 4; break;
case MONS_MOTTLED_DRACONIAN:colour = 5; break;
case MONS_PALE_DRACONIAN: colour = 6; break;
case MONS_PURPLE_DRACONIAN: colour = 7; break;
case MONS_RED_DRACONIAN: colour = 8; break;
case MONS_WHITE_DRACONIAN: colour = 9; break;
}
m_doll.parts[TILEP_PART_SHADOW] = TILEP_SHADOW_SHADOW;
m_doll.parts[TILEP_PART_BASE] = TILEP_BASE_DRACONIAN + colour * 2;
m_doll.parts[TILEP_PART_DRCWING] =
tile_player_part_start[TILEP_PART_DRCWING] + colour;
m_doll.parts[TILEP_PART_DRCHEAD] =
tile_player_part_start[TILEP_PART_DRCHEAD] + colour;
int mon_wep = mon->inv[MSLOT_WEAPON];
int equ_tile = (mon_wep != NON_ITEM) ? tilep_equ_weapon(mitm[mon_wep]) : 0;
switch (mon->type)
{
case MONS_DRACONIAN_CALLER:
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_STAFF_EVIL;
m_doll.parts[TILEP_PART_HAND2] = TILEP_HAND2_BOOK_YELLOW;
m_doll.parts[TILEP_PART_BODY] = TILEP_BODY_ROBE_BROWN;
break;
case MONS_DRACONIAN_MONK:
m_doll.parts[TILEP_PART_ARM] = TILEP_ARM_GLOVE_SHORT_BLUE;
m_doll.parts[TILEP_PART_BODY] = TILEP_BODY_KARATE2;
break;
case MONS_DRACONIAN_ZEALOT:
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_MACE;
m_doll.parts[TILEP_PART_HAND2] = TILEP_HAND2_BOOK_CYAN;
m_doll.parts[TILEP_PART_BODY] = TILEP_BODY_MONK_BLUE;
break;
case MONS_DRACONIAN_SHIFTER:
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_STAFF_LARGE;
m_doll.parts[TILEP_PART_HAND2] = TILEP_HAND2_BOOK_GREEN;
m_doll.parts[TILEP_PART_BODY] = TILEP_BODY_ROBE_CYAN;
break;
case MONS_DRACONIAN_ANNIHILATOR:
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_STAFF_RUBY;
m_doll.parts[TILEP_PART_HAND2] = TILEP_HAND2_FIRE_CYAN;
m_doll.parts[TILEP_PART_BODY] = TILEP_BODY_ROBE_GREEN_GOLD;
break;
case MONS_DRACONIAN_KNIGHT:
m_doll.parts[TILEP_PART_HAND1] = equ_tile;
m_doll.parts[TILEP_PART_HAND2] = TILEP_HAND2_SHIELD_KNIGHT_GRAY;
m_doll.parts[TILEP_PART_BODY] = TILEP_BODY_BPLATE_METAL1;
m_doll.parts[TILEP_PART_LEG] = TILEP_LEG_BELT_GRAY;
break;
case MONS_DRACONIAN_SCORCHER:
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_FIRE_RED;
m_doll.parts[TILEP_PART_HAND2] = TILEP_HAND2_BOOK_RED;
m_doll.parts[TILEP_PART_BODY] = TILEP_BODY_ROBE_RED;
break;
default:
m_doll.parts[TILEP_PART_HAND1] = equ_tile;
m_doll.parts[TILEP_PART_BODY] = TILEP_BODY_BELT2;
m_doll.parts[TILEP_PART_LEG] = TILEP_LEG_LOINCLOTH_RED;
break;
}
}
const dolls_data *mcache_draco::doll() const
{
return &m_doll;
}
bool mcache_draco::valid(const monsters *mon)
{
return (mon && mon->type >= MONS_FIRST_DRACONIAN
&& mon->type <= MONS_LAST_DRACONIAN);
}
mcache_draco::mcache_draco(reader &th) : mcache_entry(th)
{
unmarshallDoll(th, m_doll);
}
void mcache_draco::construct(writer &th)
{
mcache_entry::construct(th);
marshallDoll(th, m_doll);
}
/////////////////////////////////////////////////////////////////////////////
// mcache_ghost
mcache_ghost::mcache_ghost(const monsters *mon)
{
assert(mcache_ghost::valid(mon));
const struct ghost_demon &ghost = *mon->ghost;
unsigned int pseudo_rand = ghost.max_hp * 54321 * 54321;
int gender = (pseudo_rand >> 8) & 1;
tilep_race_default(ghost.species, gender,
ghost.xl, m_doll.parts);
tilep_job_default(ghost.job, gender, m_doll.parts);
for (int p = TILEP_PART_CLOAK; p < TILEP_PART_MAX; p++)
{
if (m_doll.parts[p] == TILEP_SHOW_EQUIP)
{
int part_offset = pseudo_rand % tile_player_part_count[p];
m_doll.parts[p] = tile_player_part_start[p] + part_offset;
}
}
int ac = ghost.ac;
ac *= (5 + (pseudo_rand / 11) % 11);
ac /= 10;
if (ac > 25)
m_doll.parts[TILEP_PART_BODY] = TILEP_BODY_PLATE_BLACK;
else if (ac > 20)
m_doll.parts[TILEP_PART_BODY]= TILEP_BODY_BANDED;
else if (ac > 15)
m_doll.parts[TILEP_PART_BODY]= TILEP_BODY_SCALEMAIL;
else if (ac > 10)
m_doll.parts[TILEP_PART_BODY]= TILEP_BODY_CHAINMAIL;
else if (ac > 5 )
m_doll.parts[TILEP_PART_BODY]= TILEP_BODY_LEATHER_HEAVY;
else
m_doll.parts[TILEP_PART_BODY]= TILEP_BODY_ROBE_BLUE;
int sk = ghost.best_skill;
int dam = ghost.damage;
dam *= (5 + pseudo_rand % 11);
dam /= 10;
switch (sk)
{
case SK_MACES_FLAILS:
if (dam > 30)
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_GREAT_FRAIL;
else if (dam > 25)
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_GREAT_MACE;
else if (dam > 20)
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_SPIKED_FRAIL;
else if (dam > 15)
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_MORNINGSTAR;
else if (dam > 10)
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_FRAIL;
else if (dam > 5)
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_MACE;
else
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_CLUB_SLANT;
break;
case SK_SHORT_BLADES:
if (dam > 20)
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_SABRE;
else if (dam > 10)
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_SHORT_SWORD_SLANT;
else
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_DAGGER_SLANT;
break;
case SK_LONG_BLADES:
if (dam > 25)
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_GREAT_SWORD_SLANT;
else if (dam > 20)
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_KATANA_SLANT;
else if (dam > 15)
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_SCIMITAR;
else if (dam > 10)
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_LONG_SWORD_SLANT;
else
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_FALCHION;
break;
case SK_AXES:
if (dam > 30)
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_EXECUTIONERS_AXE;
else if (dam > 20)
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_BATTLEAXE;
else if (dam > 15)
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_BROAD_AXE;
else if (dam > 10)
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_WAR_AXE;
else
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_HAND_AXE;
break;
case SK_POLEARMS:
if (dam > 30)
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_GLAIVE;
else if (dam > 20)
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_SCYTHE;
else if (dam > 15)
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_HALBERD;
else if (dam > 10)
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_TRIDENT2;
else if (dam > 10)
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_HAMMER;
else
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_SPEAR;
break;
case SK_BOWS:
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_BOW2;
break;
case SK_CROSSBOWS:
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_CROSSBOW;
break;
case SK_SLINGS:
m_doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_SLING;
break;
case SK_UNARMED_COMBAT:
default:
m_doll.parts[TILEP_PART_HAND1] = m_doll.parts[TILEP_PART_HAND2] = 0;
break;
}
}
const dolls_data *mcache_ghost::doll() const
{
return &m_doll;
}
bool mcache_ghost::valid(const monsters *mon)
{
return (mon && mon->type == MONS_PLAYER_GHOST);
}
mcache_ghost::mcache_ghost(reader &th) : mcache_entry(th)
{
unmarshallDoll(th, m_doll);
}
void mcache_ghost::construct(writer &th)
{
mcache_entry::construct(th);
marshallDoll(th, m_doll);
}
/////////////////////////////////////////////////////////////////////////////
// mcache_demon
mcache_demon::mcache_demon(const monsters *mon)
{
assert(mcache_demon::valid(mon));
const struct ghost_demon &ghost = *mon->ghost;
unsigned int pseudo_rand1 = ghost.max_hp * 54321 * 54321;
unsigned int pseudo_rand2 = ghost.ac * 54321 * 54321;
unsigned int pseudo_rand3 = ghost.ev * 54321 * 54321;
int head_offset = pseudo_rand1 % tile_player_count(TILEP_DEMON_HEAD);
m_demon.head = TILEP_DEMON_HEAD + head_offset;
int body_offset = pseudo_rand2 % tile_player_count(TILEP_DEMON_BODY);
m_demon.body = TILEP_DEMON_BODY + body_offset;
if (ghost.ev % 2)
{
int wings_offset = pseudo_rand3 % tile_player_count(TILEP_DEMON_WINGS);
m_demon.wings = TILEP_DEMON_WINGS + wings_offset;
}
else
{
m_demon.wings = 0;
}
}
unsigned int mcache_demon::info(tile_draw_info *dinfo) const
{
if (m_demon.wings)
{
dinfo[0].set(m_demon.wings);
dinfo[1].set(m_demon.body);
dinfo[2].set(m_demon.head);
return 3;
}
else
{
dinfo[0].set(m_demon.body);
dinfo[1].set(m_demon.head);
return 2;
}
}
bool mcache_demon::valid(const monsters *mon)
{
return (mon && mon->type == MONS_PANDEMONIUM_DEMON);
}
mcache_demon::mcache_demon(reader &th) : mcache_entry(th)
{
unmarshallDemon(th, m_demon);
}
void mcache_demon::construct(writer &th)
{
mcache_entry::construct(th);
marshallDemon(th, m_demon);
}
void TileGhostInit(const struct ghost_demon &ghost)
{
#if 0
dolls_data doll;
int x, y;
unsigned int pseudo_rand = ghost.max_hp * 54321 * 54321;
char mask[TILE_X*TILE_Y];
int g_gender = (pseudo_rand >> 8) & 1;
for (x = 0; x < TILE_X; x++)
for (y = 0; y < TILE_X; y++)
mask[x + y*TILE_X] = (x+y)&1;
for (x = 0; x < TILEP_PART_MAX; x++)
{
doll.parts[x] = 0;
current_parts[x] = 0;
}
tilep_race_default(ghost.species, g_gender,
ghost.xl, doll.parts);
tilep_job_default (ghost.job, g_gender, doll.parts);
for (x = TILEP_PART_CLOAK; x < TILEP_PART_MAX; x++)
{
if (doll.parts[x] == TILEP_SHOW_EQUIP)
{
doll.parts[x] = 1 + (pseudo_rand % tilep_parts_total[x]);
if (x == TILEP_PART_BODY)
{
int p = 0;
int ac = ghost.ac;
ac *= (5 + (pseudo_rand/11) % 11);
ac /= 10;
if (ac > 25)
p = TILEP_BODY_PLATE_BLACK;
else if (ac > 20)
p = TILEP_BODY_BANDED;
else if (ac > 15)
p = TILEP_BODY_SCALEMAIL;
else if (ac > 10)
p = TILEP_BODY_CHAINMAIL;
else if (ac > 5 )
p = TILEP_BODY_LEATHER_HEAVY;
else
p = TILEP_BODY_ROBE_BLUE;
doll.parts[x] = p;
}
}
}
int sk = ghost.best_skill;
int dam = ghost.damage;
int p = 0;
dam *= (5 + pseudo_rand % 11);
dam /= 10;
switch (sk)
{
case SK_MACES_FLAILS:
if (dam > 30)
p = TILEP_HAND1_GREAT_FRAIL;
else if (dam > 25)
p = TILEP_HAND1_GREAT_MACE;
else if (dam > 20)
p = TILEP_HAND1_SPIKED_FRAIL;
else if (dam > 15)
p = TILEP_HAND1_MORNINGSTAR;
else if (dam > 10)
p = TILEP_HAND1_FRAIL;
else if (dam > 5)
p = TILEP_HAND1_MACE;
else
p = TILEP_HAND1_CLUB_SLANT;
doll.parts[TILEP_PART_HAND1] = p;
break;
case SK_SHORT_BLADES:
if (dam > 20)
p = TILEP_HAND1_SABRE;
else if (dam > 10)
p = TILEP_HAND1_SHORT_SWORD_SLANT;
else
p = TILEP_HAND1_DAGGER_SLANT;
doll.parts[TILEP_PART_HAND1] = p;
break;
case SK_LONG_BLADES:
if (dam > 25)
p = TILEP_HAND1_GREAT_SWORD_SLANT;
else if (dam > 20)
p = TILEP_HAND1_KATANA_SLANT;
else if (dam > 15)
p = TILEP_HAND1_SCIMITAR;
else if (dam > 10)
p = TILEP_HAND1_LONG_SWORD_SLANT;
else
p = TILEP_HAND1_FALCHION;
doll.parts[TILEP_PART_HAND1] = p;
break;
case SK_AXES:
if (dam > 30)
p = TILEP_HAND1_EXECUTIONERS_AXE;
else if (dam > 20)
p = TILEP_HAND1_BATTLEAXE;
else if (dam > 15)
p = TILEP_HAND1_BROAD_AXE;
else if (dam > 10)
p = TILEP_HAND1_WAR_AXE;
else
p = TILEP_HAND1_HAND_AXE;
doll.parts[TILEP_PART_HAND1] = p;
break;
case SK_POLEARMS:
if (dam > 30)
p = TILEP_HAND1_GLAIVE;
else if (dam > 20)
p = TILEP_HAND1_SCYTHE;
else if (dam > 15)
p = TILEP_HAND1_HALBERD;
else if (dam > 10)
p = TILEP_HAND1_TRIDENT2;
else if (dam > 10)
p = TILEP_HAND1_HAMMER;
else
p = TILEP_HAND1_SPEAR;
doll.parts[TILEP_PART_HAND1] = p;
break;
case SK_BOWS:
doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_BOW2;
break;
case SK_CROSSBOWS:
doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_CROSSBOW;
break;
case SK_SLINGS:
doll.parts[TILEP_PART_HAND1] = TILEP_HAND1_SLING;
break;
case SK_UNARMED_COMBAT:
default:
doll.parts[TILEP_PART_HAND1] = doll.parts[TILEP_PART_HAND2] = 0;
break;
}
ImgClear(DollCacheImg);
// Clear
_ImgCopyToTileImg(TILE_MONS_PLAYER_GHOST, DollCacheImg, 0, 0, 1);
_draw_doll(DollCacheImg, &doll);
_ImgCopyToTileImg(TILE_MONS_PLAYER_GHOST, DollCacheImg, 0, 0, 1, mask, false);
_redraw_spx_tcache(TILE_MONS_PLAYER_GHOST);
#endif
}
void tile_get_monster_weapon_offset(int mon_tile, int &ofs_x, int &ofs_y)
{
ofs_x = 0;
ofs_y = 0;
switch (mon_tile)
{
case TILE_MONS_ORC:
case TILE_MONS_URUG:
case TILE_MONS_BLORK_THE_ORC:
case TILE_MONS_ORC_WARRIOR:
case TILE_MONS_ORC_KNIGHT:
case TILE_MONS_ORC_WARLORD:
ofs_y = 2;
break;
case TILE_MONS_GOBLIN:
case TILE_MONS_IJYB:
ofs_y = 4;
break;
case TILE_MONS_GNOLL:
ofs_x = -1;
break;
case TILE_MONS_BOGGART:
ofs_y = 2;
break;
case TILE_MONS_DEEP_ELF_FIGHTER:
case TILE_MONS_DEEP_ELF_SOLDIER:
ofs_y = 2;
break;
case TILE_MONS_DEEP_ELF_KNIGHT:
ofs_y = 1;
break;
case TILE_MONS_KOBOLD:
ofs_x = 3;
ofs_y = 4;
break;
case TILE_MONS_KOBOLD_DEMONOLOGIST:
ofs_y = -10;
break;
case TILE_MONS_BIG_KOBOLD:
ofs_x = 2;
ofs_y = 3;
break;
case TILE_MONS_MIDGE:
ofs_y = -2;
break;
case TILE_MONS_NAGA:
case TILE_MONS_GREATER_NAGA:
case TILE_MONS_NAGA_WARRIOR:
case TILE_MONS_GUARDIAN_NAGA:
case TILE_MONS_NAGA_MAGE:
ofs_y = 1;
break;
case TILE_MONS_HELL_KNIGHT:
ofs_x = -1;
ofs_y = 3;
break;
case TILE_MONS_RED_DEVIL:
ofs_x = 2;
ofs_y = -3;
break;
case TILE_MONS_WIZARD:
ofs_x = 2;
ofs_y = -2;
break;
case TILE_MONS_HUMAN:
ofs_x = 5;
ofs_y = 2;
break;
case TILE_MONS_ELF:
ofs_y = 1;
ofs_x = 4;
break;
case TILE_MONS_OGRE_MAGE:
ofs_y = -2;
ofs_x = -4;
break;
case TILE_MONS_DEEP_ELF_MAGE:
case TILE_MONS_DEEP_ELF_SUMMONER:
case TILE_MONS_DEEP_ELF_CONJURER:
case TILE_MONS_DEEP_ELF_PRIEST:
case TILE_MONS_DEEP_ELF_HIGH_PRIEST:
case TILE_MONS_DEEP_ELF_DEMONOLOGIST:
case TILE_MONS_DEEP_ELF_ANNIHILATOR:
case TILE_MONS_DEEP_ELF_SORCERER:
ofs_x = -1;
ofs_y = -2;
break;
case TILE_MONS_DEEP_ELF_DEATH_MAGE:
ofs_x = -1;
break;
}
}
fprintf(fp, "extern int tile_%s_count[%s];\n",
lcname.c_str(), max.c_str());
fprintf(fp, "extern const char *tile_%s_name[%s];\n",
lcname.c_str(), max.c_str());
fprintf(fp, "extern tile_info tile_%s_info[%s];\n",
lcname.c_str(), max.c_str());
fprintf(fp, "int tile_%s_count(unsigned int idx);\n", lcname.c_str());
fprintf(fp, "const char *tile_%s_name(unsigned int idx);\n",
lcname.c_str());
fprintf(fp, "tile_info &tile_%s_info(unsigned int idx);\n",
lcname.c_str());
fprintf(fp, "const char *tile_%s_name[%s] =\n{\n",
lcname.c_str(), max.c_str());
fprintf(fp, "int tile_%s_count(unsigned int idx)\n{\n", lcname.c_str());
fprintf(fp, " assert(idx >= %s && idx < %s);\n",
m_start_value.c_str(), max.c_str());
fprintf(fp, " return _tile_%s_count[idx - %s];\n",
lcname.c_str(), m_start_value.c_str());
fprintf(fp, "}\n\n");
fprintf(fp, "const char *_tile_%s_name[%s - %s] =\n{\n",
lcname.c_str(), max.c_str(), m_start_value.c_str());
fprintf(fp, "tile_info tile_%s_info[%s] =\n{\n",
lcname.c_str(), max.c_str());
fprintf(fp, "const char *tile_%s_name(unsigned int idx)\n{\n",
lcname.c_str());
fprintf(fp, " assert(idx >= %s && idx < %s);\n",
m_start_value.c_str(), max.c_str());
fprintf(fp, " return _tile_%s_name[idx - %s];\n",
lcname.c_str(), m_start_value.c_str());
fprintf(fp, "}\n\n");
fprintf(fp, "tile_info _tile_%s_info[%s - %s] =\n{\n",
lcname.c_str(), max.c_str(), m_start_value.c_str());
dc-misc/unseen PLAYER
dc-misc/unseen_monster MONS_UNKNOWN
dc-misc/unseen_monster MCACHE_START
};
// A glorified unsigned int that assists with ref-counting the mcache.
class tile_fg_store
{
public:
tile_fg_store() : m_tile(0) {}
tile_fg_store(unsigned int tile) : m_tile(tile) {}
operator unsigned int() { return m_tile; }
unsigned int operator=(unsigned int tile);
protected:
unsigned int m_tile;