adjusted per monster to hand out the right resists. The current MR_RES_FIRE gives one level of resistance only.
Added a real ghost structure, discarded the old ghost values array. Adjusted bones file format so bones will work out-of-the-box with Hearse. Breaks bones format, older bones will be rejected.
Fixed some maps with bad DEPTHs.
Added more safe answers in Y/N prompts, added a check to make it less likely that Crawl will spin in a tight loop reading input from a closed tty.
(Experimental) !a will override existing foe of friendlies in LOS.
Blademasters no longer pick up stuff to throw (Erik).
Zombies of swimming things are also swimming things. Currently applies only to zombies explicitly placed in .des files, since fish zombies cannot be generated otherwise (can of worms).
Morgue is now saved before showing the inventory and other boring end-of-game stuff.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@3231 c06c8d41-db1a-0410-9941-cceddc491573
RBAGQ2PB7V5YAM5KSHSZR2E3MLKDSRVM5XYGI2TIXP5QMVBOQHDQC
YLURD6WHTJTFIOY3CAK7BXWYRCS4RSIGK7FGMA7WPAMLJ3CXJIXQC
G2IBQUJ2V2OGM4TR6VKC4CLNVLALTDLB5STOBN7637GOUX2SH4ZAC
SPFKVC5KJVGMD4ITZWLWTB6N42IV6AWXGPEEXCYPI7BGFZKY5FHAC
ID373JATLMWAY526Q6Q5FXHRNFWMEOFXPHGPAUUY5OAMPFDN5SJAC
BK6MGPSEAEMU4URBAPKY3VTKK6JC6IZVN5CNOSN2UPTIOWQYEWLQC
5OZIFI7NLISEF4X2GXHWBCUA7VHPPLE45DFOXO33TACCV2SMROWQC
J5EZS3FSHLPKMZSCHEQHNQRRFJMOEZ4OIGHSP6QSCZJW2XYUAVSAC
W74555HMPXUQ72AGKBXC5P3STMMX5DZAW6ZESUDLNVJBCAG43PLAC
6UPCB64Z2W243QR3JQD7WPQMPVNVBPYRG7GTGZK6LTKKBBSKBHZQC
A5H6EHZ5L5Z3BW2MIEJSDZMGTUQIJT6HSQXJVFBN5ZR55SGNNQNQC
VUWJVWO2E2ADJ6CZGDHAQCXZOGI7AMMZZW4QSHREXMVTQDTZQPUAC
ZNGET7722J4PJXQM7IISUIIUFGB6D7WBD4IXR4QQENHERHXOG7KQC
TVC7W7C2XKBQSD2IJFMWFVGXZAOD4EUOW43NAQTOF5KFMAUOJABQC
ZWYVZW5QFM5I2F6BLMNDDTV7FROJUHOO3O2BCBG7WSCKMKXUEMTQC
ZNI3CWU5DWBFSULG4UWOW7AGV2JIBLXE5U3EOF6ESZDLFO2ZDT7QC
DQUTMKIMQUJDOAC3YHRK5W4PDCOKVPQFSV7OWWS75CCUMC5B2PGAC
OPNCHI4UGN7WBIYPAXVV2C4N22ZSWROA435FJCY5UZVXKWRYQ42QC
V53DXVC5T3N6J47H2CNG4MMPRR4PHW4AIS66QNVTKJNNYTTTQL4AC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
J6APXOT4QOGQFONWB7G546VTVF6QG42HVOROMHF7YBDJPR4K26OAC
7AMQN7MITMXBNVDAK5VOXTQ4TZIAOD6ZLOFJG7GQMBTY23Y2BKSAC
7KWDC7XFNMBLSUO2HISIROBINZBX5T67LJEEXTAORXW2YZ7VWFGAC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
DDU4A3JGN5IUIPP5IASOODKPR2WBHSDSV4FITZ6HNXNSXXQACWAQC
5ASC3STDYCNLZFEBN6UTMUCGDETHBR2OCBZCF5VIAZ5RRWLOTDYQC
QDTVLBRGHDTRUVT7I3O72K6TMOYAUSAJBZUHGOEFU2RKJNUPWZSQC
AVCMVFA3MKCXHO6H44UK5KJNIHTGQV7UA7GYXM26VI6TXXU5ZN6QC
R22TTMI6WXWULC7ODKFF3QCB7MOTETQQ6IR4BUCUPOCQKQNCTT5AC
6RJVKSL7RVZIZIZIC4TWIYJQ24RUSB346ODS3NYGDHUIRTC4Z5FQC
GSQ72ULBSL6WBJZUB3GJKAPQDXZIQV7B2TDBA5OP2WVGHVJMCQFQC
U3KGUJJQWQORJIIFH3ADVNIEEX5HOX6KEOXO7DJSL7L3Z6GG3PAQC
YRY2TC3VHOYE47M23UJGUWDGF7H7WGU7WLWI4SUNM4EDNTGUPHGAC
7PRZJ6KZLG26YVTAMXT7YOTQLWZHGWGRTKXZZ52P4XYCQD4GT5WQC
L4FQMODPEE777BQHQIASG2PGH7N7TFXL2JZSPLQL35MQ6W7VH7OAC
MWHMD65QP6UKXO6Q4ZVEAMXY563AJ6KH7J6UEZOB5CRPPSRB762QC
TV3ZC6WOZKSQQJQN26JIVKCHK6UK7WMDBYZDUYRWEAZ4JB4YVNAAC
NUYXKJP5YXHRDUQW5QW7UC3D5U3VPANIOZAOHFCPWMSRYGMA3GCAC
CG4TL4AKSN4J7CMATZFJ5N7PSDCQXLS3QYX7PZ3K67KMMBT675OQC
WMHFDQKUDCUGM3R245LLVZ5NNEZSCXFDSTNMVS2O5EFUHHO7HU3AC
7AREIGBWRJPQI7N7UMSXYWGOI5D6OFUKX656PX3GOZVY3ALY75BAC
NNG27Y5ZQAZX6UD7F7M4F6KEZBEDFXPEEC3LFUSX4ESKT7K6UJQAC
C67GX7W5HBCDPQJRSHWMLM4DUJ3ELFSHH42SVICFJVCJW25T5Z3AC
NW6P7VRKBFBQ2FRDZBXN7APJZPYC4SYCIA3MOOE2KZGX43IXNK2AC
PM65H4V4GNPVIJFUQW57DC3VDB7TRUUNXKVZONQKEFZSK3AXX5GQC
TAJUWPR2BXNVKYH4CN4WN3OR2Z2NESJBEDUB2P2PE6YLX64FQTRAC
QWLHS4KCBWCHYDYFTNRHXC2J3Y5IBVT2JQLV6A4VOCT34SYALPEQC
RZZ6G7WKMBBXHJ54W4CIUKZKPN5L5GB7QNA5QOHHQ5KULFH4OVRAC
KWKVXUJSWKBWPRXD6JVI6K4YHHHNRO525VHPPDQ52XCGQRUHVXQAC
WBAFNYODKTL3YSG3UOJITBJSTFYGJLIWKRNK6NMGIIP5TPC2BDGQC
WFED7ME7LXUZCZY3TWX7PCPW4EAA55W626CM2OOYVJTLI2BWFTVAC
3QLM46S44Z7GDLWPH3VHBMW2RSWZAOLGJMG2BDKNGUOZIM4IX6WAC
ISSEUTHG7EH3QTFLS23GXFIOQXCI5HJPJMK6GWNFMC6NDRD2H34QC
F7Q5PX44SLPANIZXCY67TG2W5JTRVJMHGQW54VJLGB4XRH7R6JBQC
3C2VE43SHCSBY4LTRTFYFLIPRWFUN6DXU6D34QVWDQTSNRBUFG7AC
5TWOIGLM6G4QEASFEKKTK7UBPTL4PXASVEOL5777FPT6RHSUTBBQC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
SJDOBXECX7F3ZPPVR7FPURE53D47PP2TFIF4SB6XPS456PZV3DQAC
7Y5HSDFKA5TPLS2TWTRFMQVX6UXUDHXU5MUMXQSDFAIY4THQ3BIQC
MSQI3TH6T62JAXQGLL52QZCWAMC372TGB6ZNNRDGUGMJKBNNV2VAC
CRCKW7MAFIP2MB6ZNPVZXUHBGSPQNTYHGDVF2TCM2K6XLRUTUW4QC
4Q5OYUKF2SGF7WHMIVYFZVXXDCFUCYY534VLOGKWYRSPYKRXMVDAC
FCZSQBKDNMJZRJS2LWQQWLUFGOXSKXDJZQIHC7L5S7HXCXQPOMMAC
ILOED4VB4I6VPAUTR75ZWX6MXDYXB5DO2EDK2UH67O3HNKWV23RQC
S4W5EBZLFX3HA3JNR524LF5RJ7PAPMSMN3FVRZNLQZY4QNEILGLQC
OP6CTAKWCAU64JXQ3USQYR5E5IFHQHNCACII5UMVRXUTZXJQOAZAC
X5WLJCJVW55SXZVP7IKP7ADCJIGNKN4PKAXFECVR6TNK7XSMZR7QC
QNIQ2NBBIERVCA2YTD3O3P6QPJ5M6VDVGGX7V2BWXTW5553T4PVAC
33ZMPQC6OXTESW7SRW765GRNJUEJRSYONRVZVIEUDAUEJ2PPMB4AC
ER4KHDZQ4VBEZKOUJIEUM5HBPWFGBDSB5KE56HG4UE2X6WN266QQC
JYCMD6WMNHXA53K4LLKVTNX6PLRLU25F6J2TYMPQXM2ENAE66NIAC
IIN7AVA6JYRBXH6ZYRR7BY7TV6PW7ANAQ2A3PD55FKBKKQFEEF2AC
CVOQOT7B2FYC3E6ZPOMC7TCJMLEFFIRPTHNRNW5L65NCTAHPA42AC
VCG3BRIYRTNNWYC3LOXD6KFGXOX37HAFW2HNV7WXVG2V7EUHLDZQC
BWAQ3FHBBM6G3K3KYP75CRTR343RDQZJRYX5ZGYUEXYBAC3APDLAC
5HBRQ2QZTFBQE2Z2CFADUI2D52LO5Z5CNHXHA7BJP3LGO7FJPUCQC
OQ4KB7QCJSK7GSW3DYBARH4DCB75HFKLUSOSOZZZ4IUFKNGFRUDQC
UL7XFKMUX3WIU4O2LZANK4ECJ654UZPDBFGNXUEYZYOLKBYBCG6AC
UABVRWV5U33LQGPNTESOUT72XZCGUNEGIAWTXHJQYXLSJISG4UOAC
V4DWL5WBO2JCODVS5QQNWXDH4DAYZN3D5V3UDCHM2KKOMADOTEDQC
7OZGLL7FSMUNXOTGDHQILMXI2EXH7EXPJZTO4KP6KJYWZANJAKXAC
HIRKGUMNJPWKSVTR6TVBPD3MWNA63CEHCLCIPWEMGDFHVB3NPLDQC
U3SFBWHMMMO2PY6PAX7FMSBSND4RCWGJR42HB47LNQXLOX7ZOB6QC
C5VA63WAQRWPENIMXRPUPZLZJMC77PL2B3A77HYFWDCZU5QDG7VQC
I2B33Z7NZGC33AMDSSK446AZZYWKPHWLAGULVHKKZU4MVB4BNJOAC
ITDUEUO7XAZANPC4GRB3SEDFBOV7GLFPNPTYE5LYNC3CS6BSVZTQC
PFMHSDAXQN4VDSDA6QBDIK2DPJKGYX5HYLTSZNTKMRJYXYLIKGOQC
3V52MSSK7QX7FWLLUW63DTWCBAJEK674EFZLKP45FLZ5KZKVARHAC
6L4EP4ZRWWYLT55PD5KTTJON5J2JB5VV5MWNHF5VPZQZ5BKEYZ4QC
LEY3EZGTCBV6CYX4L727KQ4ZXL2LZLT5WESN3WAF65VRMX4EDP4QC
W5VEC2PBIM5DMU5233HOWAZUEPTGWJRZZIA3H35YYQQW6BTP6XUAC
EOMCPVNQLX3IMLC46EAO67DPBH5KEG2FQTPBLGU62HIRWA3UQ7XQC
Z63Q4DA5J5TZAC5LN55UD4CLADUMU5Z73TGEVE2YUXCHIST2Y4QAC
ZCRK2DJ5VKECRQXZTWT4NUDL2VT5ZHUK7NT6NQPLRJ56TDX5PJSAC
5KJCHLIUFKRPMIVWUAYT6EOF7SW4PTQF6Y5OPEFWXGLE7DUGYLZAC
2TTHWHQ3ZDD3DLB3KRULTBMS3ZREJG472IBVZXIGTP7MBZWAU52QC
TJRYL3NXPW5IUGEV3YOC7JYWEXCZDBFPLT4AUG4P227WVKVB72ZAC
PFEJ4LMDNEKLMGRCMWQ7EIRVU4JMYGICI4G7X4WVWOROVXQCBZ7QC
M5ZDZJBTOJ7SWQPZZQPC24JYZKP26MWSRDHXBWQE2MPPL6WCXOIQC
X2FMEN4E345XD26Z2X7JMJ7VGHOGCGIELMHQRE2ITLVNQACP3NOQC
EGV2HM7SD7UQSWJGLR65NQJTUBAJ7WHLM67FMH4UFP7JRSFKREPAC
3FBKOX4Y5QYPMBOCSAMHNZXCY7Z75YDQDL4EJZHZIGDXL7RMZ7TAC
BW3XFNOS6LDAQLHOZ6RXARCMKCY5JVLVDSXDSSAX4DSYM3FANQBAC
2H32CFFM2FNS63JJPNM2S6HMO543EX72GMPOU5GI6HTMQYPL6I3AC
TPZ3PNJN3TYJY2UDMZYE2K2J5ZQJXKHSWWLPVHMOEFCADK6UAGOAC
ED62QWGKBPORWVKDFOQRKJXEIWZVNGR3O4KWQBDSRNPT36AYOQYAC
JM7UAK777RAVDAVLQLEOBRTGNW2B47S5G55XITJXO243IUNZHVYQC
marshallString(th, ghost.name.c_str(), 20);
marshallByte(th, res.elec);
marshallByte(th, res.poison);
marshallByte(th, res.fire);
marshallByte(th, res.steam);
marshallByte(th, res.cold);
marshallByte(th, res.hellfire);
marshallByte(th, res.asphyx);
marshallByte(th, res.acid);
marshallByte(th, res.sticky_flame);
marshallByte(th, res.pierce);
marshallByte(th, res.slice);
marshallByte(th, res.bludgeon);
}
// how many ghost values?
marshallByte(th, NUM_GHOST_VALUES);
static void unmarshallResists(tagHeader &th, mon_resist_def &res)
{
res.elec = unmarshallByte(th);
res.poison = unmarshallByte(th);
res.fire = unmarshallByte(th);
res.steam = unmarshallByte(th);
res.cold = unmarshallByte(th);
res.hellfire = unmarshallByte(th);
res.asphyx = unmarshallByte(th);
res.acid = unmarshallByte(th);
res.sticky_flame = unmarshallByte(th);
res.pierce = unmarshallByte(th);
res.slice = unmarshallByte(th);
res.bludgeon = unmarshallByte(th);
}
for (int i = 0; i < NUM_GHOST_VALUES; i++)
marshallShort( th, ghost.values[i] );
static void marshallSpells(tagHeader &th, const monster_spells &spells)
{
for (int j = 0; j < NUM_MONSTER_SPELL_SLOTS; ++j)
marshallShort(th, spells[j]);
// How many ghosts?
marshallShort(th, ghosts.size());
for (int j = 0; j < NUM_MONSTER_SPELL_SLOTS; ++j)
spells[j] = static_cast<spell_type>( unmarshallShort(th) );
}
static void marshallGhost(tagHeader &th, const ghost_demon &ghost)
{
marshallString(th, ghost.name.c_str(), 20);
for (int i = 0, size = ghosts.size(); i < size; ++i)
marshallGhost(th, ghosts[i]);
marshallShort(th, ghost.species);
marshallShort(th, ghost.job);
marshallShort(th, ghost.best_skill);
marshallShort(th, ghost.best_skill_level);
marshallShort(th, ghost.xl);
marshallShort(th, ghost.max_hp);
marshallShort(th, ghost.ev);
marshallShort(th, ghost.ac);
marshallShort(th, ghost.damage);
marshallShort(th, ghost.speed);
marshallByte(th, ghost.see_invis);
marshallShort(th, ghost.brand);
marshallResists(th, ghost.resists);
marshallByte(th, ghost.spellcaster);
marshallByte(th, ghost.cycle_colours);
marshallShort(th, ghost.fly);
marshallSpells(th, ghost.spells);
// how many ghost values?
int count_c = unmarshallByte(th);
ghost.species = static_cast<species_type>( unmarshallShort(th) );
ghost.job = static_cast<job_type>( unmarshallShort(th) );
ghost.best_skill = static_cast<skill_type>( unmarshallShort(th) );
ghost.best_skill_level = unmarshallShort(th);
ghost.xl = unmarshallShort(th);
ghost.max_hp = unmarshallShort(th);
ghost.ev = unmarshallShort(th);
ghost.ac = unmarshallShort(th);
ghost.damage = unmarshallShort(th);
ghost.speed = unmarshallShort(th);
ghost.see_invis = unmarshallByte(th);
ghost.brand = static_cast<brand_type>( unmarshallShort(th) );
if (count_c > NUM_GHOST_VALUES)
count_c = NUM_GHOST_VALUES;
for (int i = 0; i < count_c; i++)
ghost.values[i] = unmarshallShort(th);
unmarshallResists(th, ghost.resists);
ghost.spellcaster = unmarshallByte(th);
ghost.cycle_colours = unmarshallByte(th);
ghost.fly = static_cast<flight_type>( unmarshallShort(th) );
if (!dump_char( morgue_name(se.death_time), !dead, true, &se ))
{
mpr("Char dump unsuccessful! Sorry about that.");
if (!crawl_state.seen_hups)
more();
clrscr();
}
case BRANCH_SNAKE_PIT:
if (mons_species(monster->type) == MONS_NAGA
|| mons_species(monster->type) == MONS_SNAKE)
{
return true;
}
return false;
case BRANCH_SNAKE_PIT:
return (mons_species(monster->type) == MONS_NAGA
|| mons_species(monster->type) == MONS_SNAKE);
hurted += (random2avg(steam_base_damage, 2) * 10) / speed;
if (mons_res_fire(monster) < 0)
hurted += (random2(steam_base_damage / 2 + 1) * 10) / speed;
hurted +=
resist_adjust_damage(
monster,
monster->res_steam(),
(random2avg(steam_base_damage, 2) * 10) / speed);
return (monster_habitable_grid(m->type, actual_grid, mons_flies(m),
// Zombified monsters enjoy the same habitat as their original.
const int type = mons_is_zombified(m)? mons_zombie_base(m) : m->type;
return (monster_habitable_grid(type, actual_grid, mons_flies(m),
if (habitat == HT_WATER &&
(grid == DNGN_DEEP_WATER || grid == DNGN_BLUE_FOUNTAIN))
{
return true;
}
case HT_LAVA:
return (grid == DNGN_LAVA);
};
struct mon_resist_def
{
// All values are actually saved as single-bytes, so practical
// range is -128 - 127, and the game only distinguishes values in
// the range -1 to 3.
short elec;
short poison;
short fire;
short steam;
short cold;
short hellfire;
short asphyx;
short acid;
bool sticky_flame;
// Physical damage resists (currently unused)
short pierce;
short slice;
short bludgeon;
mon_resist_def();
mon_resist_def(int flags, short level = 1);
mon_resist_def operator | (const mon_resist_def &other) const;
const mon_resist_def &operator |= (const mon_resist_def &other);
// last updated 12may2000 {dlb}
/* ***********************************************************************
* called from: beam - fight - monstuff
* *********************************************************************** */
bool mons_res_sticky_flame( const monsters *mon );
// last updated 12may2000 {dlb}
/* ***********************************************************************
* called from: beam - monstuff - spells4
* *********************************************************************** */
int mons_res_steam( const monsters *mon );
bool mons_res_sticky_flame( const monsters *mon )
{
return (get_mons_resists(mon).sticky_flame
|| mon->has_equipped(EQ_BODY_ARMOUR, ARM_MOTTLED_DRAGON_ARMOUR));
}
int mons_res_steam( const monsters *mon )
{
int res = get_mons_resists(mon).steam;
if (mon->has_equipped(EQ_BODY_ARMOUR, ARM_STEAM_DRAGON_ARMOUR))
res += 3;
return (res + mons_res_fire(mon) / 2);
}
if (mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON)
return (mon->ghost->values[ GVAL_RES_FIRE ]);
int u = 0, f = get_mons_resists(mon);
const mon_resist_def res = get_mons_resists(mon);
int u = std::min(res.fire + res.hellfire * 3, 3);
// no Big Prize (tm) here either if you set all three flags. It's a pity uh?
//
// Note that natural monster resistance is two levels, this is duplicate
// the fact that having this flag used to be a lot better than armour
// for monsters (it used to make them immune in a lot of cases) -- bwr
if (f & MR_RES_HELLFIRE)
u += 3;
else if (f & MR_RES_FIRE)
u += 2;
else if (f & MR_VUL_FIRE)
u--;
if (mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON)
return (mon->ghost->values[ GVAL_RES_COLD ]);
int u = 0, f = get_mons_resists(mon);
// Note that natural monster resistance is two levels, this is duplicate
// the fact that having this flag used to be a lot better than armour
// for monsters (it used to make them immune in a lot of cases) -- bwr
if (f & MR_RES_COLD)
u += 2;
else if (f & MR_VUL_COLD)
u--;
int u = get_mons_resists(mon).cold;
hit_dice = ghost->values[ GVAL_DEMONLORD_HIT_DICE ];
hit_points = ghost->values[ GVAL_MAX_HP ];
max_hit_points = ghost->values[ GVAL_MAX_HP ];
ac = ghost->values[ GVAL_AC ];
ev = ghost->values[ GVAL_EV ];
speed = (one_chance_in(3) ? 10 : 6 + roll_dice(2, 9));
hit_dice = ghost->xl;
hit_points = ghost->max_hp;
max_hit_points = ghost->max_hp;
ac = ghost->ac;
ev = ghost->ev;
speed = (one_chance_in(3) ? 10 : 8 + roll_dice(2, 9));
hit_dice = ghost->values[ GVAL_EXP_LEVEL ];
hit_points = ghost->values[ GVAL_MAX_HP ];
max_hit_points = ghost->values[ GVAL_MAX_HP ];
ac = ghost->values[ GVAL_AC];
ev = ghost->values[ GVAL_EV ];
speed = ghost->values[ GVAL_SPEED ];
hit_dice = ghost->xl;
hit_points = ghost->max_hp;
max_hit_points = ghost->max_hp;
ac = ghost->ac;
ev = ghost->ev;
speed = ghost->speed;
{
for (int i = 0; i < NUM_MONSTER_SPELL_SLOTS; i++)
{
spells[i] =
static_cast<spell_type>( ghost->values[ GVAL_SPELL_1 + i ] );
#if DEBUG_DIAGNOSTICS
mprf( MSGCH_DIAGNOSTICS, "spell #%d: %d", i, spells[i] );
#endif
}
}
spells = ghost->spells;
/////////////////////////////////////////////////////////////////////////
// mon_resist_def
mon_resist_def::mon_resist_def()
: elec(0), poison(0), fire(0), steam(0), cold(0), hellfire(0),
asphyx(0), acid(0), sticky_flame(false), pierce(0),
slice(0), bludgeon(0)
{
}
mon_resist_def::mon_resist_def(int flags, short level)
: elec(0), poison(0), fire(0), steam(0), cold(0), hellfire(0),
asphyx(0), acid(0), sticky_flame(false), pierce(0),
slice(0), bludgeon(0)
{
for (int i = 0; i < 32; ++i)
{
switch (flags & (1 << i))
{
case MR_RES_STEAM: steam = 3; break;
case MR_RES_ELEC: elec = level; break;
case MR_RES_POISON: poison = level; break;
case MR_RES_FIRE: fire = level; break;
case MR_RES_HELLFIRE: hellfire = level; break;
case MR_RES_COLD: cold = level; break;
case MR_RES_ASPHYX: asphyx = level; break;
case MR_RES_ACID: acid = level; break;
case MR_VUL_ELEC: elec = -level; break;
case MR_VUL_POISON: poison = -level; break;
case MR_VUL_FIRE: fire = -level; break;
case MR_VUL_COLD: cold = -level; break;
case MR_RES_PIERCE: pierce = level; break;
case MR_RES_SLICE: slice = level; break;
case MR_RES_BLUDGEON: bludgeon = level; break;
case MR_VUL_PIERCE: pierce = -level; break;
case MR_VUL_SLICE: slice = -level; break;
case MR_VUL_BLUDGEON: bludgeon = -level; break;
case MR_RES_STICKY_FLAME: sticky_flame = true; break;
default: break;
}
}
}
const mon_resist_def &mon_resist_def::operator |= (const mon_resist_def &o)
{
elec += o.elec;
poison += o.poison;
fire += o.fire;
cold += o.cold;
hellfire += o.hellfire;
asphyx += o.asphyx;
acid += o.acid;
pierce += o.pierce;
slice += o.slice;
bludgeon += o.bludgeon;
sticky_flame = sticky_flame || o.sticky_flame;
return (*this);
}
mon_resist_def mon_resist_def::operator | (const mon_resist_def &o) const
{
mon_resist_def c(*this);
return (c |= o);
}
#ifndef GHOST_H
#define GHOST_H
#include "externs.h"
#include "enum.h"
#include "itemprop.h"
#include "mon-util.h"
struct ghost_demon
{
public:
std::string name;
species_type species;
job_type job;
skill_type best_skill;
short best_skill_level;
short xl;
short max_hp, ev, ac, damage, speed;
bool see_invis;
brand_type brand;
mon_resist_def resists;
bool spellcaster, cycle_colours;
flight_type fly;
monster_spells spells;
public:
ghost_demon();
void reset();
void init_random_demon();
void init_player_ghost();
public:
static std::vector<ghost_demon> find_ghosts();
private:
static int n_extra_ghosts();
static void find_extra_ghosts(std::vector<ghost_demon> &ghosts, int n);
static void find_transiting_ghosts(std::vector<ghost_demon> &gs, int n);
static void announce_ghost(const ghost_demon &g);
private:
void add_spells();
spell_type translate_spell(spell_type playerspell) const;
};
extern std::vector<ghost_demon> ghosts;
#endif
values.init(0);
values[GVAL_SPEED] = 10;
species = SP_UNKNOWN;
job = JOB_UNKNOWN;
best_skill = SK_FIGHTING;
best_skill_level = 0;
xl = 0;
max_hp = 0;
ev = 0;
ac = 0;
damage = 0;
speed = 10;
see_invis = false;
brand = SPWPN_NORMAL;
resists = mon_resist_def();
spellcaster = false;
cycle_colours = false;
fly = FL_NONE;
|| values[ GVAL_BRAND ] == SPWPN_PROTECTION
|| values[ GVAL_BRAND ] == SPWPN_FLAME
|| values[ GVAL_BRAND ] == SPWPN_FROST);
|| brand == SPWPN_PROTECTION
|| brand == SPWPN_FLAME
|| brand == SPWPN_FROST);
// does demon fly? (0 = no, 1 = fly, 2 = levitate)
values[GVAL_DEMONLORD_FLY] = (one_chance_in(3) ? 0 :
one_chance_in(5) ? 2 : 1);
// vacant <ghost best skill level>:
values[GVAL_DEMONLORD_UNUSED] = 0;
// does demon fly?
fly = (one_chance_in(3)? FL_NONE :
one_chance_in(5)? FL_LEVITATE : FL_FLY);
values[GVAL_SPELL_4] = RANDOM_ELEMENT(search_order_misc);
if ( values[GVAL_SPELL_4] == SPELL_DIG )
values[GVAL_SPELL_4] = SPELL_NO_SPELL;
spells[3] = RANDOM_ELEMENT(search_order_misc);
if ( spells[3] == SPELL_DIG )
spells[3] = SPELL_NO_SPELL;
if (values[GVAL_EV] > 40)
values[GVAL_EV] = 40;
values[ GVAL_SEE_INVIS ] = player_see_invis();
values[ GVAL_RES_FIRE ] = player_res_fire();
values[ GVAL_RES_COLD ] = player_res_cold();
values[ GVAL_RES_ELEC ] = player_res_electricity();
values[ GVAL_SPEED ] = player_ghost_base_movement_speed();
if (ev > 60)
ev = 60;
see_invis = player_see_invis();
resists.fire = player_res_fire();
resists.cold = player_res_cold();
resists.elec = player_res_electricity();
speed = player_ghost_base_movement_speed();
values[ GVAL_DAMAGE ] = d;
values[ GVAL_BRAND ] = e;
values[ GVAL_SPECIES ] = you.species;
values[ GVAL_BEST_SKILL ] = best_skill(SK_FIGHTING, (NUM_SKILLS - 1), 99);
values[ GVAL_SKILL_LEVEL ] =
you.skills[best_skill(SK_FIGHTING, (NUM_SKILLS - 1), 99)];
values[ GVAL_EXP_LEVEL ] = you.experience_level;
values[ GVAL_CLASS ] = you.char_class;
damage = d;
brand = static_cast<brand_type>( e );
species = you.species;
best_skill = ::best_skill(SK_FIGHTING, (NUM_SKILLS - 1), 99);
best_skill_level = you.skills[best_skill];
xl = you.experience_level;
job = you.char_class;
values[ GVAL_SPELL_1 ] = search_first_list(SPELL_NO_SPELL);
values[ GVAL_SPELL_2 ] = search_first_list(values[GVAL_SPELL_1]);
values[ GVAL_SPELL_3 ] = search_second_list(SPELL_NO_SPELL);
values[ GVAL_SPELL_4 ] = search_third_list(SPELL_DIG);
spells[ 0 ] = search_first_list(SPELL_NO_SPELL);
spells[ 1 ] = search_first_list(spells[0]);
spells[ 2 ] = search_second_list(SPELL_NO_SPELL);
spells[ 3 ] = search_third_list(SPELL_DIG);
static void write_version( FILE *dataFile, int majorVersion, int minorVersion,
bool extended_version )
{
// write version
tagHeader versionTag;
versionTag.offset = 0;
versionTag.tagID = TAG_VERSION;
marshallByte(versionTag, majorVersion);
marshallByte(versionTag, minorVersion);
// extended_version just pads the version out to four 32-bit words.
// This makes the bones file compatible with Hearse with no extra
// munging needed.
if (extended_version)
{
// Use a single signature 16-bit word to indicate that this is
// Stone Soup and to disambiguate this (unmunged) bones file
// from the munged bones files offered by the old Crawl-aware
// hearse.pl. Crawl-aware hearse.pl will prefix the bones file
// with the first 16-bits of the Crawl version, and the following
// 7 16-bit words set to 0.
marshallShort(versionTag, GHOST_SIGNATURE);
// Write the three remaining 32-bit words of padding.
for (int i = 0; i < 3; ++i)
marshallLong(versionTag, 0);
}
tag_write(versionTag, dataFile);
}
// write version
struct tagHeader versionTag;
versionTag.offset = 0;
versionTag.tagID = TAG_VERSION;
marshallByte(versionTag, majorVersion);
marshallByte(versionTag, minorVersion);
tag_write(versionTag, dataFile);
write_version( dataFile, majorVersion, minorVersion, extended_version );
if (majorVersion == SAVE_MAJOR_VERSION)
return true;
// check for the DCSS ghost signature.
if (readShort(ghostFile) != GHOST_SIGNATURE)
return (false);
if (majorVersion == SAVE_MAJOR_VERSION
&& minorVersion <= GHOST_MINOR_VERSION)
{
// Discard three more 32-bit words of padding.
for (int i = 0; i < 3; ++i)
readLong(ghostFile);
return !feof(ghostFile);
}
beam_temp.thrower = KILL_YOU;
beam_temp.flavour = BEAM_CONFUSION;
beam_temp.thrower =
attacker->atype() == ACT_PLAYER? KILL_YOU : KILL_MON;
beam_temp.flavour = BEAM_CONFUSION;
beam_temp.beam_source =
attacker->atype() == ACT_PLAYER? MHITYOU
: monster_index(atk);
if (mons_res_elec(def))
break;
special_damage = player_staff_damage(SK_AIR_MAGIC);
special_damage =
resist_adjust_damage(defender,
defender->res_elec(),
player_staff_damage(SK_AIR_MAGIC));
if (mons_res_cold(def) > 0)
break;
special_damage = player_staff_damage(SK_ICE_MAGIC);
if (mons_res_cold(def) < 0)
special_damage += player_staff_damage(SK_ICE_MAGIC);
special_damage =
resist_adjust_damage(defender,
defender->res_cold(),
player_staff_damage(SK_ICE_MAGIC));
if (mons_res_fire(def) > 0)
break;
special_damage = player_staff_damage(SK_FIRE_MAGIC);
if (mons_res_fire(def) < 0)
special_damage += player_staff_damage(SK_FIRE_MAGIC);
special_damage =
resist_adjust_damage(defender,
defender->res_fire(),
player_staff_damage(SK_FIRE_MAGIC));
struct ghost_demon
{
public:
std::string name;
FixedVector< short, NUM_GHOST_VALUES > values;
public:
ghost_demon();
void reset();
void init_random_demon();
void init_player_ghost();
public:
static std::vector<ghost_demon> find_ghosts();
private:
static int n_extra_ghosts();
static void find_extra_ghosts(std::vector<ghost_demon> &ghosts, int n);
static void find_transiting_ghosts(std::vector<ghost_demon> &gs, int n);
static void announce_ghost(const ghost_demon &g);
private:
void add_spells();
int translate_spell(int playerspell) const;
};
enum ghost_value_type
{
GVAL_MAX_HP, // 0
GVAL_EV,
GVAL_AC,
GVAL_SEE_INVIS,
GVAL_RES_FIRE,
GVAL_RES_COLD, // 5
GVAL_RES_ELEC,
GVAL_DAMAGE,
GVAL_BRAND,
GVAL_SPECIES,
GVAL_BEST_SKILL, // 10
GVAL_SKILL_LEVEL,
GVAL_EXP_LEVEL,
GVAL_CLASS,
GVAL_SPELL_1, // 14
GVAL_SPELL_2,
GVAL_SPELL_3,
GVAL_SPELL_4,
GVAL_SPELL_5,
GVAL_SPELL_6, // 19
GVAL_SPEED,
NUM_GHOST_VALUES, // should always be last value
// these values are for demonlords, which override the above:
GVAL_DEMONLORD_SPELLCASTER = 9,
GVAL_DEMONLORD_FLY, // 10
GVAL_DEMONLORD_UNUSED, // 11
GVAL_DEMONLORD_HIT_DICE, // 12
GVAL_DEMONLORD_CYCLE_COLOUR // 13
};
<< ((ghost.values[GVAL_EXP_LEVEL] < 4) ? " weakling" :
(ghost.values[GVAL_EXP_LEVEL] < 7) ? "n average" :
(ghost.values[GVAL_EXP_LEVEL] < 11) ? "n experienced" :
(ghost.values[GVAL_EXP_LEVEL] < 16) ? " powerful" :
(ghost.values[GVAL_EXP_LEVEL] < 22) ? " mighty" :
(ghost.values[GVAL_EXP_LEVEL] < 26) ? " great" :
(ghost.values[GVAL_EXP_LEVEL] < 27) ? "n awesomely powerful"
: " legendary")
<< ((ghost.xl < 4) ? " weakling" :
(ghost.xl < 7) ? "n average" :
(ghost.xl < 11) ? "n experienced" :
(ghost.xl < 16) ? " powerful" :
(ghost.xl < 22) ? " mighty" :
(ghost.xl < 26) ? " great" :
(ghost.xl < 27) ? "n awesomely powerful"
: " legendary")