chooses a different, random beam flavour (which undoudtedly needs to have their relative weights changed after playtesting) for each square it passes through, but in the future it might do things like bounce off walls at weird angles or animate weapons left laying on the ground.
Added CLOUD_CHAOS, though it doesn't do anything yet.
Monsters which are marked summoned or otherwise given ENCH_ABJ can also be marked with the type of summoning that happened, which is stored in the until-now-unused ENCH_SUMMON. This is useful for figuring out if a monster has ENCH_ABJ but isn't really summoned (like fire vortices created by Fire Storm or dancing weapons created by Tukima's Dance) so that they won't be affected by abjuration. It's also currently used to do a different "dissapears in a puff of smoke" messages for summoned monsters based on the summoning type, so that monsters summoned by Shadow Creature "dissolve into shadows" and don't leave behind any clouds, and temporary god gift monsters from good gods "dissolve into sparkling lights". In the future it might be used to do temporarily animated corpses, which turn back into a corpse when killed or when the animation runs out.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7778 c06c8d41-db1a-0410-9941-cceddc491573
AYU5OVG2HZO46KDAPKUWAVHS5HTYFKUWIMIRMTHAXVVFEDJE7YPAC
433PR5ZCMUQOBYD3CVSBY3DOCP4NBS5TFSMWFVB2MGREG4VK2EEQC
G6AT74PNGPB5ZEITF4EXNTAB7MNZFWKRE7KT7DUV4TSWVHQGYDJQC
U5BUJF7RAD3Z44WG5LE3NLVSFZALT5W6MHKQ3BSVAJ4NZ7PU7Q5QC
56D656WZS2LWVTXGWPR5FFJ7MDHP25XGPTBMYM4NHT4TKSJILX3QC
SH5BS5AJPUFPXQHM5MZPIY3CCVT4EAIRLSAQWZYL5WX2J7FPBSQQC
53BVN4ZHKGUAJE53HM6FC6GKUGXOU5QBUT7CLXV2ONS6S5NPW55AC
LACOILN7WCNIM3GTLY56TQOMC3MFPW2XX3RHDWXRSMBQQPI4AQXQC
EJYL6BLIGHOMKK35VYL2X2MT2HILY2XGKIP4NYU6Q7R5YTYEAT5QC
44XY2RJGTBXIDIRRI4TAH7ZPS7F6ZNKTY2HNTRDQLB5BAUYAGQXQC
LLA7OZDQJ3S2YKGNNDD6K3VP3FPMQLZX3IUO4WDJQVJHGKGCCUZQC
SM6YRPYZS6LMDQA6X3VAOK2PGMUFKPD7JMWJISOQSMX2CBR4ISPAC
CDFS7Z74W5HKPQIHQICOG442KQFXUSBGGLDDQLE3MG74T44YU6AQC
T4FNOPMWYYJHJBTTY33PB43HTJPKEC46L62YERTWIX73HYZSELXQC
CCRQESB4ADT4WA7FGLNZZXAJ6G5QMCTYCZIWORBN45P6ZPILC34AC
KVTA7IUBD2O7ZEUU5T5VP7D3XVLFLYICXUPP5WCPAODBXKK4DNNQC
KFULGQQOHWUTXOM3BXCCYPGGVGGY4Z6265XUFRCBPNLTZAEHJZSQC
NYURIMPCM2RADLMIQSN76OPKXQSK4XBLFNXD2OO53KGZI3MA6AQAC
UKBVBVJK23OUOOKQJRGLZWEZYED5KZ4NLODW6U67UEBYCFWGGQOAC
WT66JDIRTLLP37SHTV4GI3V64JFJ4D25LNRLGCHFG6CLEFKJ3QGQC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
3DQXSE4YGFBBDUWK4YEOFWW4UPWILWELFSLP37SL6BERGAZJC5YAC
K7J2IGELTIQL5KAMBV62MFVIVMEZEWCOLZ7GHFXHYPANYIF7BRZAC
DZD6YG52TXNI4CJ2FRGFULBH6G5MDLRVQV3X3V35AW533Z3TVBKAC
4SWAT5KCKQV527NKELAXFQ5XA4Q5HONQXD4VBXMUZNPVPQKPCPNAC
YF6CE2VBFK6K4V34PKBVYVQUTJRDDDCF2M5RMUGW6V6N2M4SUPLAC
X5WLJCJVW55SXZVP7IKP7ADCJIGNKN4PKAXFECVR6TNK7XSMZR7QC
VQZEJTCSRZ5RVLCCKUCIS3IVZPFYRC26I74X4WIJAPEY7NYID2UQC
XWEI2LM5HPH3F4Y5TS7B6FWXQLERWJP2MHW36KGYW5TIAOORHYUAC
BMGB25AWEDOAWKDB7H22R6D4SL32CSBSOBWBIEN3GFGDLEDGEWJAC
JBB7GZTVO3UJSPFVELSP4WPJZ5SC5LY36FJJ7WF2BJGZTVPNIV3AC
5ETBQI75XWCYG5UALQR6TKD7FCJYTCVQEN64D6OHXVOGO3QB3AKAC
CUM44NOPIB7LGTRY2O2R5MYXAB27R3TFM6LUBEQHZFXLZWJ55QZAC
JYEEOUYQ7ZPKOGWUV7VCORBVSOLF2UCBFBH3TR75RGOSS6PNKYUAC
52OLLMBMDNX2WBYVSBDJVRC45QCXDIG4XQENYJAECOVG6ICAKVLAC
7PRZJ6KZLG26YVTAMXT7YOTQLWZHGWGRTKXZZ52P4XYCQD4GT5WQC
GMCNF7YBSN7WQJNHSF3RV2NTHTVP4TABCNP7S26UEIHPAKNCPWGAC
KAOE5HB3THUKVGFZRO5EZESHEB3Q34WUO5DFMLWIKOBF47LZTIYAC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
BNRY5YIXLFE2TDNU2JQHWWXJQVWNSEWQ52DU7XUWIT5DZWKGBDDAC
BFCFMN2BXNLXJCYYCL2V2XTDQQNM3PJPSRB6CU76FM3332NC7GMAC
2YL37AGHLFOMIF3GCTVQGGV2RNNWETWM6ZMUHO3QEWDVBFFSFAKQC
BYURAML2EPTULHH22Q5RPXYGDEYAJYESR6C72UMNPPYHTCJZUPFAC
MSMWAL6JZAWNGZXCNXPATUMAU6TVXBWWFY666P7UBSZ5LPYJYUCQC
C5VA63WAQRWPENIMXRPUPZLZJMC77PL2B3A77HYFWDCZU5QDG7VQC
Y2NYY7HWFZ2LQDK3ACSLGS37F2J2IJ5LRGCIMZYXLEOSVPD3A4DAC
NNG27Y5ZQAZX6UD7F7M4F6KEZBEDFXPEEC3LFUSX4ESKT7K6UJQAC
2TFYJ7D72JY4DYQW3GSPEONA2WYIVHAJXTIQ2QRDIWF65XN2QFGAC
QKGDOYIYKE6B36ION5O2DRW65DWWPZMYNWJVH7LJJ7FPGGM2MYAQC
TGJZXTUIAKCFZQJ54ZQEBGFBVZSJCAX6AWDRSH3TP7UJRLGUM5SAC
B62ICMDTN5V7R7RBL4JALFVKEMVOOVLRSJASRNYS6CGFWBEEF5JQC
DOZORMA366M4HB5JKSS27BMCR6ET7QNZNND2B7KV3NVEEPR5H7EAC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
P5KSBMFHDCAFUGHSOCLDG7J7XKCGJBCSDICYOMOYCEBBBXM55CEAC
542UIZKI65UDRNEMGFFDBWYD5XC7AYLTZ3JZQRR2GHYJALD3YY6QC
PDOFPXD2X6VI23AHKCGQ5RVDBG74CNP2E3YOHKXLOARHHBXEK3HQC
V7IKAPO5OY7CJTT62GMHQOD3EQW42FTTY3KDBOTJUODPS5WMBCHAC
OSGS3PH2L5CBTDVZCZS6OCFQNA4A7RMEXBYJQB7DDZBYYJW7QSSAC
2SMZGNBB352OJBIT2UE3NONODTTMV3FJJFBQUN4VNLLNYJKTJKBQC
4LNIHTHZTCOEZEHZ4GW6WCZH4UCDWKK5UVUKEDODEBBS4YH2KONQC
GPEJOT73KMACP33IPAKFR5ROGHCOIP22VXZMQNYTGLEA2OSZUM2AC
KPSCSVGHKEQ4ENM3QQU2U3GYMV52NDFO5L6ML7YDPUKV3365OA3QC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
5V47S4NNTHWTSAHV3YLO2VGH7JTUIYJ3GBPDN5ZM4UQALT2ZEXDQC
QDTVLBRGHDTRUVT7I3O72K6TMOYAUSAJBZUHGOEFU2RKJNUPWZSQC
UAJN2CFA2QHYDHW2UFAVPPHDQFCD54RKM6V2UC4AMEDJUBBLNWIQC
33ZMPQC6OXTESW7SRW765GRNJUEJRSYONRVZVIEUDAUEJ2PPMB4AC
X4OCLD5YEXCYVQNMOQORLIO72AKUEMT3BT6FB3TW2HARKN5X7MEQC
5XSXMOBGXFLTIQE6WDXWWFVDOTUPZSIQ2FWT3YI5QMVU6D76IUYQC
JZTWTPXIUEVACX5B6FYQRVRJD3KQN653C4G4GXT2VSMX4EP7WS3AC
Q652MJM34TH2ZV6CPA2RERMJMDMK2TQEAALRMXK2G6Y25UWKRJ3QC
AIVXE6QBRVCZAASKQRZO6LBDGTYEYSSD2DZCWRX4VLSKE3GCNIDAC
ZP2KE7A2LE7Z2S7AC45WE4CXDSEVDTWIMV2EM4IBUKXYJIDU6R7QC
HFEFKHVV2ULXS6ZEFNX6ZXXUJKME5L2PITQ3VRTKMRUOU3DHXXWQC
EHL7B5UIYYHSFX3KXQ43C4GNFJSEUEXFF7U3IL7XU6E5R675WS7AC
ATDAT2AONG2BDLZFBJZB4WVNRUFQAU7RDIVUBAZ6STAV62NX5R4AC
PR42BCP5BPRFD2MP5H6CIJP7E57Q6TKL6SOXZWFKMFVR2OZWHT7AC
5FHWTG7M6FW4B3I33YI7QSM3OZIB6ZGC6TI6JISSLY5Y43HI56VAC
F2MGW5DMHF7AF7R7KX3H6BYJGZ57CVTDCZWUHSFJXS52IVOC3NZQC
25CH7HH4LKXFIZ75YNMXS3TSXO6O27DYSOPLOD45K4OCNFWLS4LQC
FLAGBNUNSIQNFDN53CDWABJRTTFWDL4PG34AI474ZKPXDEPYHOAQC
LY7DLLD7IKL6ZQPVROLDJ46XRM5CMAAEBRFDKJ4M53CPC5GFCGSQC
S34LKQDIQJLIWVIPASOJBBZ6ZCXDHP5KPS7TRBZJSCDRVNCLK6UAC
AS2IQQJNNCEQNXXKTGYHLB7RO3ZKCF4F7GK6FJH66BOOKDDRGNIQC
WA2OSEGWVCESURYWNERNYWQKHE6SU4XQ4Q4HJY5B6ZPGNFUKQEEQC
ZGUJWUFJ4NFFJ6PGXLFGQWCWBCZHPWGWI44NJHJEVPRG5L36PADQC
GVW4OBPGXY2Q75HB7QHADZIOHKL22FI2BSJ2TM4K5SBJENBFTQKAC
TQLWCGVXVZ75H7MDBJD3DJDUFNW62WOAEDJUVKCHQTAXKBP47CSAC
OFH2B2UZBK43QLFQBZ54FOCFLFNE54BZVDNCEUGDTBCUGNVZULIQC
PI5BATR2SER3RFE76IUGHM2AGXVFOUM3PLU7WC2K2Q2BA5K2E73QC
BJPPSWEN35BG4KP3XTXPDMAJ2GAUMHXKHCNALAZ4B4OS6B3KDSUQC
UZ5623MOLKBTGBSRBJ4OBOEI4IEZSPV3NCV2DRMUZ3CHHJQVHIIAC
LT7MICXP753TFF6I4LTWHZWCYEXO3LBRQ3H2TOXZFBXVHZTIYGNQC
4CIYU7SAAGQJ6BH2WWS4EJWUS6GX25IV24GLYSPGDNWNASVJSIYAC
OYANFNGKCXG2NLQMYW4TNFU3LFK3533XQ3HFGI3LNMY4JGMDMK5QC
2SNCC2NXKFVBYTWH7THU2QELHONTOBRNCWH6FWYORKKCWZAXTTVAC
SIDH2P7NBIG5KEOE27XHD3ZT2NQ2OJZFN6VZXWNWYFFY5YVXSSVQC
HAM54HXIO2245W6REO4RZDY2QMIH476AWWJSMYAMSYYNEBBJSHWAC
RDZUMV3A5TREQHLPPJWDWVXBNIOWC3CQJJ35TYFBQQVQNTU7SPXQC
int bow_brand = SPWPN_NORMAL;
const int ammo_brand = get_ammo_brand(item);
const bool poison = (ammo_brand == SPMSL_POISONED);
int bow_brand = SPWPN_NORMAL;
const int ammo_brand = get_ammo_brand(item);
bool poison = (ammo_brand == SPMSL_POISONED);
}
bool mons_clonable(const monsters* mon, bool needs_adjacent)
{
// No uniques, pandemonium lords or player ghosts. Also, figuring
// out the name for the clone of a named monster isn't worth it.
if (mons_is_unique(mon->type) || mon->is_named() || mon->ghost.get())
return (false);
if (needs_adjacent)
{
// Is there space for the clone?
bool square_found = false;
for (int i = 0; i < 8; i++)
{
const coord_def p = mon->pos() + Compass[i];
if (in_bounds(p) && p != you.pos() && mgrd(p) == NON_MONSTER
&& monster_habitable_grid(mon, grd(p)))
{
square_found = true;
break;
}
}
if (!square_found)
return (false);
}
// Is the monster carrying an artefact?
for (int i = 0; i < NUM_MONSTER_SLOTS; i++)
{
const int index = mon->inv[i];
if (index == NON_ITEM)
continue;
if (is_artefact(mitm[index]))
return (false);
}
return (true);
}
int clone_mons(const monsters* orig, bool quiet, bool* obvious,
coord_def pos)
{
// Is there an open slot in menv?
int midx = NON_MONSTER;
for (int i = 0; i < MAX_MONSTERS; i++)
if (menv[i].type == -1)
{
midx = i;
break;
}
if (midx == NON_MONSTER)
return (NON_MONSTER);
if (!in_bounds(pos))
{
// Find an adjacent square.
int squares = 0;
for (int i = 0; i < 8; i++)
{
const coord_def p = orig->pos() + Compass[i];
if (in_bounds(p) && p != you.pos() && mgrd(p) == NON_MONSTER
&& monster_habitable_grid(orig, grd(p)))
{
if (one_chance_in(++squares))
pos = p;
}
}
if (squares == 0)
return (NON_MONSTER);
}
ASSERT(mgrd(pos) == NON_MONSTER && you.pos() != pos);
monsters &mon(menv[midx]);
mon = *orig;
mon.position = pos;
mgrd(pos) = midx;
// Duplicate objects, or unequip them if they can't be duplicated.
for (int i = 0; i < NUM_MONSTER_SLOTS; i++)
{
const int old_index = orig->inv[i];
if (old_index == NON_ITEM)
continue;
const int new_index = get_item_slot(0);
if (new_index == NON_ITEM)
{
mon.unequip(mitm[old_index], i, 0, true);
mon.inv[i] = NON_ITEM;
continue;
}
mon.inv[i] = new_index;
mitm[new_index] = mitm[old_index];
}
bool _obvious;
if (obvious == NULL)
obvious = &_obvious;
*obvious = false;
if (you.can_see(orig) && you.can_see(&mon))
{
if (!quiet)
simple_monster_message(orig, " is duplicated!");
*obvious = true;
}
mark_interesting_monst(&mon, mon.behaviour);
if (you.can_see(&mon))
{
seen_monster(&mon);
viewwindow(true, false);
}
return (midx);
int corpse_class = mons_species(monster->type);
bool force = false;
int corpse_class = mons_species(monster->type);
// If this was a corpse that was temporarily animated then turn the
// monster back into a corpse.
if (mons_class_is_zombified(monster->type)
&& (summon_type == SPELL_ANIMATE_DEAD
|| summon_type == SPELL_ANIMATE_SKELETON
|| summon_type == MON_SUMM_ANIMATE))
{
force = true;
corpse_class = mons_zombie_base(monster);
}
const bool poison = (mons_corpse_effect(monster->type) == CE_POISONOUS
if (force && !silent)
{
if (you.can_see(monster))
simple_monster_message(monster, " turns back into a corpse!");
else
mprf("%s appears out of nowhere!",
mitm[o].name(DESC_CAP_A).c_str());
}
const bool poison = (mons_corpse_effect(corpse_class) == CE_POISONOUS
}
void _monster_die_cloud(const monsters* monster, bool corpse, bool silent,
bool summoned, int summon_type)
{
// Chaos spawn always leave behind a cloud of chaos.
if (monster->type == MONS_CHAOS_SPAWN)
{
summoned = true;
corpse = false;
}
if (!summoned)
return;
std::string prefix;
std::string msg = " disappears in a puff of smoke!";
cloud_type cloud = random_smoke_type();
int dur = 1 + random2(3);
if (corpse)
{
if (mons_weight(mons_species(monster->type)) == 0)
return;
prefix = "'s corpse";
}
switch(summon_type)
{
case SPELL_SHADOW_CREATURES:
msg = " disolves into shadows!";
cloud = CLOUD_NONE;
break;
case MON_SUMM_CHAOS:
msg = " degenerates into a cloud of primal chaos!";
cloud = CLOUD_CHAOS;
break;
case MON_SUMM_WRATH:
case MON_SUMM_AID:
if (is_good_god(monster->god))
{
msg = " disolves into sparkling lights!";
cloud = CLOUD_NONE;
}
break;
}
if (monster->god == GOD_XOM && one_chance_in(10)
|| cloud != CLOUD_NONE && monster->type == MONS_CHAOS_SPAWN)
{
msg = " degenerates into a cloud of primal chaos!";
cloud = CLOUD_CHAOS;
}
if (mons_is_holy(monster) && summon_type != SPELL_SHADOW_CREATURES
&& summon_type != MON_SUMM_CHAOS)
{
msg = " disolves into sparkling lights!";
cloud = CLOUD_NONE;
}
if (!silent)
simple_monster_message(monster, (prefix + msg).c_str());
if (cloud != CLOUD_NONE)
place_cloud( cloud, monster->pos(), dur,
monster->kill_alignment() );
if (!silent)
{
simple_monster_message( monster,
" disappears in a puff of smoke!" );
}
place_cloud( random_smoke_type(),
monster->pos(), 1 + random2(3),
monster->kill_alignment() );
if (!wizard)
_monster_die_cloud(monster, false, silent, summoned,
summon_type);
if (monster->has_ench(ENCH_ABJ))
{
if (mons_weight(mons_species(monster->type)))
{
simple_monster_message(monster,
"'s corpse disappears in a puff of smoke!");
place_cloud( random_smoke_type(),
monster->pos(), 1 + random2(3),
monster->kill_alignment() );
}
}
else
{
_monster_die_cloud(monster, true, silent, summoned, summon_type);
if (!summoned)
abjuration_duration(abj), pos(p), foe(mfoe), flags(monflags),
god(which_god), number(monnumber), colour(moncolour),
abjuration_duration(abj), summon_type(0), pos(p), foe(mfoe),
flags(monflags), god(which_god), number(monnumber), colour(moncolour),
power(monpower), proximity(prox), level_type(ltype), map_mask(0)
{
}
mgen_data(monster_type mt,
beh_type beh,
int abj,
int st,
const coord_def &p = coord_def(-1, -1),
unsigned short mfoe = MHITNOT,
unsigned monflags = 0,
god_type which_god = GOD_NO_GOD,
monster_type base = MONS_PROGRAM_BUG,
int monnumber = 0,
int moncolour = BLACK,
int monpower = you.your_level,
proximity_type prox = PROX_ANYWHERE,
level_area_type ltype = you.level_type)
: cls(mt), base_type(base), behaviour(beh),
abjuration_duration(abj), summon_type(st), pos(p), foe(mfoe),
flags(monflags), god(which_god), number(monnumber), colour(moncolour),
};
// Non-spell "summoning" types to give to monsters::mark_summoned(), or as
// the fourth paramater of mgen_data's second constructor.
//
// Negative values since spells are non-negative.
enum mon_summon_type
{
MON_SUMM_CLONE = -10000, // Cloned from another monster
MON_SUMM_ANIMATE, // Item/feature/substance which was animated
MON_SUMM_CHAOS, // Was made from pure chaos
MON_SUMM_MISCAST, // Spell miscast
MON_SUMM_ZOT, // Zot trap
MON_SUMM_WRATH, // Divine wrath
MON_SUMM_AID // Divine aid
return (m->has_ench(ENCH_ABJ));
const mon_enchant abj = m->get_ench(ENCH_ABJ);
if (abj.ench == ENCH_NONE)
{
if (duration != NULL)
*duration = -1;
if (summon_type != NULL)
*summon_type = 0;
return (false);
}
if (duration != NULL)
*duration = abj.duration;
const mon_enchant summ = m->get_ench(ENCH_SUMMON);
if (summ.ench == ENCH_NONE)
{
if (summon_type != NULL)
*summon_type = 0;
return (true);
}
if (summon_type != NULL)
*summon_type = summ.degree;
switch(summ.degree)
{
// Temporarily dancing weapons are really there.
case SPELL_TUKIMAS_DANCE:
// A corpse/skeleton which was temporarily animated.
case SPELL_ANIMATE_DEAD:
case SPELL_ANIMATE_SKELETON:
// Fire vortices are made from real fire.
case SPELL_FIRE_STORM:
// Clones aren't really summoned (though their equipment might be).
case MON_SUMM_CLONE:
// Some object which was animated, and thus not really summoned.
case MON_SUMM_ANIMATE:
return (false);
}
return (true);
std::string setup_chaos_ammo(bolt &pbolt, item_def ammo)
{
ASSERT(!is_artefact(ammo));
const bool poisoned = (get_ammo_brand(ammo) == SPMSL_POISONED);
// Don't choose BEAM_POISON or BEAM_HEALING if we have poisoned ammo.
const int pois_weight = poisoned ? 0 : 10;
const int heal_weight = poisoned ? 0 : 10;
const beam_type flavour = static_cast<beam_type>(
random_choose_weighted( pois_weight, BEAM_POISON,
heal_weight, BEAM_HEALING,
10, BEAM_FIRE,
10, BEAM_COLD,
10, BEAM_ELECTRICITY,
10, BEAM_NEG,
10, BEAM_ACID,
10, BEAM_HELLFIRE,
10, BEAM_NAPALM,
10, BEAM_HELLFROST,
10, BEAM_SLOW,
10, BEAM_HASTE,
10, BEAM_PARALYSIS,
10, BEAM_CONFUSION,
10, BEAM_INVISIBILITY,
10, BEAM_POLYMORPH,
10, BEAM_BANISH,
10, BEAM_DISINTEGRATION,
0 ));
std::string name;
int colour;
if (poisoned)
name = "poison ";
switch(flavour)
{
case BEAM_POISON:
name += "poison";
colour = EC_POISON;
break;
case BEAM_HEALING:
name += "healing";
colour = EC_HEAL;
break;
case BEAM_FIRE:
name += "flame";
colour = EC_FIRE;
break;
case BEAM_COLD:
name += "frost";
colour = EC_ICE;
break;
case BEAM_ELECTRICITY:
name += "lightning";
colour = EC_ELECTRICITY;
break;
case BEAM_NEG:
name += "negative energy";
colour = EC_NECRO;
break;
case BEAM_ACID:
name += "acid";
colour = YELLOW;
break;
case BEAM_HELLFIRE:
name += "hellfire";
colour = EC_FIRE;
break;
case BEAM_NAPALM:
name += "sticky fire";
colour = EC_FIRE;
break;
case BEAM_HELLFROST:
name += "hellfrost";
colour = EC_ICE;
break;
case BEAM_SLOW:
name += "slowing";
colour = EC_ENCHANT;
break;
case BEAM_HASTE:
name += "hasting";
colour = EC_ENCHANT;
break;
case BEAM_PARALYSIS:
name += "paralysis";
colour = EC_ENCHANT;
break;
case BEAM_CONFUSION:
name += "confusion";
colour = EC_ENCHANT;
break;
case BEAM_INVISIBILITY:
name += "invisibility";
colour = EC_ENCHANT;
break;
case BEAM_POLYMORPH:
name += "polymorphing";
colour = EC_MUTAGENIC;
break;
case BEAM_BANISH:
name += "banishment";
colour = EC_WARP;
break;
case BEAM_DISINTEGRATION:
name += "disintegration";
colour = EC_DEATH;
break;
default:
ASSERT(!"Invalid chaos ammo flavour.");
break;
}
pbolt.name = "bolt of ";
pbolt.name += name;
pbolt.flavour = flavour;
pbolt.colour = colour;
pbolt.type = dchar_glyph(DCHAR_FIRED_BOLT);
// Get name for a plain arrow/bolt/dart/needle.
ammo.special = 0;
std::string ammo_name = ammo.name(DESC_NOCAP_A);
ammo_name += " of ";
ammo_name += name;
return ammo_name;
}
// Default to whatever colour magic is today.
if (colour == -1)
colour = element_colour(EC_MAGIC);
}
static beam_type _chaos_beam_flavour()
{
const beam_type flavour = static_cast<beam_type>(
random_choose_weighted(
10, BEAM_FIRE,
10, BEAM_COLD,
10, BEAM_ELECTRICITY,
10, BEAM_POISON,
10, BEAM_NEG,
10, BEAM_ACID,
10, BEAM_HELLFIRE,
10, BEAM_NAPALM,
10, BEAM_HELLFROST,
10, BEAM_SLOW,
10, BEAM_HASTE,
10, BEAM_HEALING,
10, BEAM_PARALYSIS,
10, BEAM_CONFUSION,
10, BEAM_INVISIBILITY,
10, BEAM_POLYMORPH,
10, BEAM_BANISH,
10, BEAM_DISINTEGRATION,
0 ));
return (flavour);
// Random beams: randomize before affect().
bool random_beam = false;
if (pbolt.flavour == BEAM_RANDOM)
{
random_beam = true;
pbolt.flavour = static_cast<beam_type>(
random_range(BEAM_FIRE, BEAM_ACID));
}
if (random_beam)
{
pbolt.flavour = BEAM_RANDOM;
pbolt.effect_known = false;
}
// Actually draw the beam/missile/whatever,
// if the player can see the cell.
// Reset chaos beams so that it won't be considered an invisible
// enchantment beam for the purposes of animation.
if (pbolt.real_flavour == BEAM_CHAOS)
pbolt.flavour = pbolt.real_flavour;
// Actually draw the beam/missile/whatever, if the player can see
// the cell.
// Random beams: randomize before affect().
if (beam.flavour == BEAM_RANDOM)
{
random_beam = true;
// Random/chaos beams: randomize before affect().
if (beam.real_flavour == BEAM_RANDOM)
flavour(BEAM_MAGIC), drop_item(false), item(NULL), source(),
target(), pos(), damage(0,0), ench_power(0), hit(0),
thrower(KILL_MISC), ex_size(0), beam_source(MHITNOT), name(),
is_beam(false), is_explosion(false), is_big_cloud(false),
aimed_at_spot(false), aux_source(), affects_nothing(false),
effect_known(true), obvious_effect(false), fr_count(0),
foe_count(0), fr_power(0), foe_power(0), fr_hurt(0),
foe_hurt(0), fr_helped(0), foe_helped(0),
flavour(BEAM_MAGIC), real_flavour(BEAM_MAGIC), drop_item(false),
item(NULL), source(), target(), pos(), damage(0,0),
ench_power(0), hit(0), thrower(KILL_MISC), ex_size(0),
beam_source(MHITNOT), name(), is_beam(false),
is_explosion(false), is_big_cloud(false), aimed_at_spot(false),
aux_source(), affects_nothing(false), effect_known(true),
obvious_effect(false),
fr_count(0), foe_count(0), fr_power(0), foe_power(0),
fr_hurt(0), foe_hurt(0), fr_helped(0),foe_helped(0),