Still todo:
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@5177 c06c8d41-db1a-0410-9941-cceddc491573
FLAGBNUNSIQNFDN53CDWABJRTTFWDL4PG34AI474ZKPXDEPYHOAQC
FPKIWVHZ3HCA6BLIACTI25WSWIFD6XJPIIM3VYKT5OX3TTMALQOAC
4QNFSNLH7PRJPQII4LN63KBSCAITKYAFJ6EV7AKNS3MFO2IMWYGQC
MGTFQEBJ32KN7DEQJRRSZUDTQQB7HOFIARDG5HPV5CSFUVJHFAOQC
3JMYZAITZNV5TPYISUMMYGJRYKFDZP34YAG72IB27BISVSZU76VQC
AGFYW7AYBL6G4MGD3VOV7PZYJBN5Z3CETCDLKYNXKSCVODKLXIRAC
X2RVB2O2TUAT336F5ZN3SRNB2EKPHSJKRD6FHI6YM3AYRDV7XJUAC
MZHQNUC3SDNLYDFO4KQRA7ZNJQ7HKAWATUVGRELKS7DHWIBVVLYQC
KBVTXJP6BGK4LE3VKCIDBJHRBJXJNWZCN5MKJEYCLT5SVZFQMLRAC
JYBCZ5MLYILAXVZ2XTTTVLPVFVRF3JHDQMUBKU6XDBCNZKSCYPLQC
BBT5X7MV6GR4GXLEHYLXSCDKQUJOLQ2AC6MSL7ODR22FQACRGYPQC
RQFQSU37Y3ZBFR634JWYHE77LIOOINGBRNL4KUHPPRA3ZR6W5QIAC
7HYUCUM7VRDLLOPHIEYMKGNXYFBCGCBQN4BOAFVD7U646KLEPHQQC
ZGUJWUFJ4NFFJ6PGXLFGQWCWBCZHPWGWI44NJHJEVPRG5L36PADQC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
JCWJWGMQIKQGSSFJUQRKNIWW3HBOJSHYDTOPPE5BWOJTIJTDYUTAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
CHO4U5JC3RNTLXVIDXXJYZMOBZJ4VXW2GVJWDOTBRKK3AJ36LDLQC
NQMXQ6OQVUSC7Y7F7IL252QW4A5JED224EECNHWAM4ZZYVNY745AC
2U47I7M3TKXUM3KHMO3UH7KGMRKOGHJQFVYPC4CTAWBV22T2HTEQC
DDU4A3JGN5IUIPP5IASOODKPR2WBHSDSV4FITZ6HNXNSXXQACWAQC
LS3DAZVRDCXVN2BKBC6RGCKO3R43Z7HKG4GXJWLBK4AKBL2G6QDQC
OAQEGSRMAOE4UHILW4LSDKERKTPOJPGPJQ3R2FB5QFWFB764UGHQC
BGJ7P65JV2OFVXMGAJDHV5Y36TR7JOFDWJUZJBHUBD7SCQMDRBEAC
YXNQKP2F4I3PCURJS7RD7SVOWMNPPW3LKMVRRBHHGILWSRKGCKDQC
UZ5623MOLKBTGBSRBJ4OBOEI4IEZSPV3NCV2DRMUZ3CHHJQVHIIAC
4PGOIN7EO5PXZHDRHBIWFTT4UI6QTINSWVN333R7S6VHFMOYQYIAC
E5DMZFW6WCFAKTKKOQPYTQXZ2CGLWMVH64LRXDUI2UIG4VYUHIVQC
5JS3QSE3EIXSBVI4DATH2EIFD7QN3POAFEUM7MK4NRMPH5JOPAAQC
WQLOHSNCA3VOMDJF6IINJYKSYVYZEBPJJWBB33QSNE4RP5HEXPMAC
P33QUZKDQZ2XKFPFI4HP5A7KG76PTBFGB3ZSGMBN3X6JYOOMYLLQC
3ZWALZFSTSIVYXY4BAY6ANGINTDACZC6RSSJTEMQSTSUIE66YOBQC
Y2NYY7HWFZ2LQDK3ACSLGS37F2J2IJ5LRGCIMZYXLEOSVPD3A4DAC
M2HMYLYYXSP5XGX6MCI77IT6UW5K4YSEUJWHPQPYXVSW5L36BJ2AC
6GDKXNFXPKQ6AVNOSMJECN7CLELM2KCMVRM2A7BARLK2NNILN6SAC
WMR7GLZK7374CFGJQNZKBAUTCZZSEKANVBKJOA5DHDD3KGC3FP7QC
4DEFHDNO2GUBYL4EGYEAR2IP3KBDXRU7UL7L4P7HEZY2UNR6IYJAC
MDAJYB6STTZPNHRQ2X66MMMSONMKXTESLHJSFPGN7H3D3TOVBAVAC
ENOQQ6DEA6ECRNTBGYYNK7G3DFEILMKQBNKP4SUQIZW2L6HWVR7QC
VEPHAIXR3GSPHBLOW5DWFFU4ULEMVWRQG4G5PKSKRA2I6RHYROUAC
W2G5DXQQOT5MGRUS4UUUKGPMIXOQWAAUV5REUJM7LAUQJGKCS23QC
UB67ZWGT7FOPKZ7SO5PAO3V4PUBPWPWXKQIQIUABNB533XP4JUMQC
5KJCHLIUFKRPMIVWUAYT6EOF7SW4PTQF6Y5OPEFWXGLE7DUGYLZAC
RNWWXK3UNYV6L3JCMBHMZOYHXVBYQIELNE45YWZ3MYCTNFICNVEQC
QVVC7AYGVA6U64PTNA7L27422NLMO327P22BQKXEVIMPZHIHO7MQC
5V47S4NNTHWTSAHV3YLO2VGH7JTUIYJ3GBPDN5ZM4UQALT2ZEXDQC
GDRQMRZTPLRZYBEIJ5AXH3NVKKOQEB5HNG6VFBVZF6JWO7XCOBKQC
R3ZUGT5VJ2DG5NFPG4RBWDWTULDE7L4REYSGVPHJPDXFG6OBIXYAC
5TG5LXU4DX65KMWCZ7YJHOB3VAETQAVBUHEUSQTPMA327XV2HQWAC
GT7BSR54BVJKHUCLEBTELGBMNBFFDQW52EVC4XKVEMUVG2UGZMDAC
QUBQZMAVSWJ7JVOL7CBSOXBEVW2WYK2MDFA2JCZWX62R2GEKP3ZQC
ASLW3Z5PAVZSWJEMMMVZT226P44EKSAD47QS72JIFJESAI3RPN3AC
YPALSPBPRHBZ6AA7Q2JVYWM53XIPB536EJGHUMESY4GKF4XFILZQC
ASCTVJSN3NXYQHRVXAORA43CV6H5V2572IMK4UGRHKBAGJOWHC4AC
SJP5BHX6MFWF3OSQPEF4WUWZWPUGMOVURTT2CUVT6H3A66LETXUAC
SRQJVKQVUY7QGCEBA2VQTWEJ7ADIUSY7L46HJQSQNM5DXYRRH5KAC
CIPVRZGLOZHCERK6YPOBV3P2E4IAB4H6D5EHLRQE2O5E4P4VCBUAC
RMCZDJKEYYT6TTZNJGBVZTG74CVLF72NWKON6IJ2HNTCA23INPJQC
XL4JOPPTQXBCNPLXXTNZFZXW25ISGZRYICSDHWD4SM37T7A4PLEAC
4UXFU3FZOCBSLDQ4S7MJKAE2H7VUHCNRDQMIY6NJ3PHYXWNGISDQC
SXLHOSCHX4BPRYRR35DI5GWISPIDKRFUSRVCYYHUUAYLAYFHSPBQC
TX3LTXGB7TJ2QHLW2TEW6XTCTOW5A3KTZGBPBRTDTUYOZFFT3NLAC
MUTWHW6LSJKATZA6LMVXT2K3UMMYJLUQRDSRXTGUBDAGOA6JO4LQC
HPE7PVDIOJDELSCDLCMFYFSDKOEJN35IZPWT57U3AIAPU45QOP6QC
HJV7BZBM752K5I47ILBQJJXSPODBBLGKDX5DWJTRDXPJ3V7AEVWAC
ZJIGDAAKOHJWPD7TMNTNKP7ZT4K4GHD7UGSAWERTIJA3BGL5BETQC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
72CQFK27NR37P2WQ32U4PEXXKMRIO7JEMJN2ZCPNVPZMT7UPFJJAC
TQLWCGVXVZ75H7MDBJD3DJDUFNW62WOAEDJUVKCHQTAXKBP47CSAC
WL5WZXFJ6TONUQRSHUY4GQ5USU47ILWNN5X2JDQZO4CRJJZSRQIAC
FA2V3G4NYTWJWUT7EWH75L3YOUX6YVOZ5LNRSFLO2XF273JKSUTAC
BJPPSWEN35BG4KP3XTXPDMAJ2GAUMHXKHCNALAZ4B4OS6B3KDSUQC
KFULGQQOHWUTXOM3BXCCYPGGVGGY4Z6265XUFRCBPNLTZAEHJZSQC
3UYAIGVJBYPSAUTDRTQXRXNFGKKSCYGIFZ3YRZJGPDKJEMOTQOUQC
Q2XCGRT36NCRQKWNL53EAS3ADON5SJQ5GEMJMX5S3QAG553HFVFQC
CUB27EJDQG66FF2YCKOV4HU3LAJVJIHUJ5QYLURRDIEVGPK666DQC
3KAINFIXO7WNWGUGZB43EUNFRS2ZPBLQZDTY456QACMRHYIJ7WDAC
PFEJ4LMDNEKLMGRCMWQ7EIRVU4JMYGICI4G7X4WVWOROVXQCBZ7QC
PI5BATR2SER3RFE76IUGHM2AGXVFOUM3PLU7WC2K2Q2BA5K2E73QC
KAOE5HB3THUKVGFZRO5EZESHEB3Q34WUO5DFMLWIKOBF47LZTIYAC
7YUGK5Q64KG5O7GJGTUBRRLHAHBCJ5YOE23YUPT6UBKUSB67CYAQC
PR42BCP5BPRFD2MP5H6CIJP7E57Q6TKL6SOXZWFKMFVR2OZWHT7AC
25CH7HH4LKXFIZ75YNMXS3TSXO6O27DYSOPLOD45K4OCNFWLS4LQC
2SNCC2NXKFVBYTWH7THU2QELHONTOBRNCWH6FWYORKKCWZAXTTVAC
Z3YHSEJ2ELRDG5DIDLP4MQSHNDRCTD5BSMVRBWOLF2S7TLRBGSBAC
KN5WFFRSNGHIGI5IUYRBOA4R4K7XK3AEAAMN6ELDFTSYKPN7QX7AC
MK5AO6R2WMXE5TA72B4NAT6VBITBHXOSQ3ARWJXCWD4CWMI6GYTAC
5K2ANIEXD3CPJM4XNKNPZINP2G4NT7SJBKRN62WNBUKJXFERTILQC
W74555HMPXUQ72AGKBXC5P3STMMX5DZAW6ZESUDLNVJBCAG43PLAC
MJWFTUS66PTCNEYXEJA3CUJFXNWXIKDD6H3V24PW7HK64NSVOFSAC
RIMJO42HB75SAZH44KZ2UH2QULOPIJLMEN4CR2CYNR2EKEKLFHSQC
WA2OSEGWVCESURYWNERNYWQKHE6SU4XQ4Q4HJY5B6ZPGNFUKQEEQC
TPSCOEB3X6LNZ7F5UBMHDZ4IUE4H3RLX6IGNW65VSJBDMNNZ3FMAC
YX2LDGNQNB6AQRKAVXNYQ473X6EVPQEBT5AJKBIIWFIMS3U2BNQQC
DUBEHQIQABGLXLFIVZ6WXBMFGLFKFRBOCK5LZ6ECUSRM3V2V35NAC
5BJPWUPLJFS34FUTFJVKA4A52YMIGV6EWDXLNSDCWBJWBGVSQFGQC
C5U3HSOOQ7BKXKXIDS7MLVXUKDTHAWJ5NXNX6YDXTM3GWY5UWX4QC
5BPJZOGZ6VTUNTJXBTP22KIPGT5NNNSXZVW5J2BGQYBP4MTCZ3CQC
MFCHFDPW4YX4QZWUOJIT3UG6OHIJPWZRXLYZQCSAUQFCEPYOYHEAC
P5ID2SF6YHSZ75EEU4CQ25HCZ74CWU2JQ2FH536KZEKD4DO3M3FQC
KBNY5FWKTEAKABFCLPC3QFKFSVZKAGXINPCIFV6WDSWFO4VCKNTAC
DAVTHXRQBYQKWHKUKJVJ5EJXIFGVWMEHINLM3JE4FMV6AAYIBOVAC
YCL3W2PFE6ILTGBFODCSXNPDIA46KVSZP2TI7HDMYAOEJT65RIEAC
WXSNNK2RXP3DQFAEQGQUZJHFWXJC7ZKG2WURZGL566UDM4YXFSWQC
KKEPQAZMWQFWPQ4P4KT5PWG2YFPG7H4JHL5K7USVHQ3Y6L4NWURQC
CGYTZT5QWIEGYKUOLOK7MFXSLJKLYRZONER5ZCDZO5XYWSLG475QC
KX6HOBTF5OBZLH2VNEFHH6YAX66FSE6JGBY5I2WIAW5IEJUGNL6AC
SMYBWDAHD74PCW5WLNAWZA3FL6AXFEMVLOMD3OKY2Z4VWQGFNLQAC
UZ6N6HOUPGVSPC5NQROEEDWMEGJA5XUWUY2AKH5QG65AZ25PVXDAC
5P6MEKBISK6NI4MULM75HHFBQW5MXITSZJDGLLIDKJ7G24F7XYNAC
int power =
(you.skills[SK_SPELLCASTING] / 2)
+ (fail_rate_check? 0 : player_mag_abil(false));
int power = (you.skills[SK_SPELLCASTING] / 2)
+ (fail_rate_check? 0 : player_mag_abil(false));
beam.ex_size = 2 + (random2(powc) > 75);
beam.flavour = BEAM_LAVA;
beam.type = dchar_glyph(DCHAR_FIRED_ZAP);
beam.colour = RED;
beam.beam_source = MHITYOU;
beam.thrower = KILL_YOU_MISSILE;
beam.name = "great blast of fire";
beam.ex_size = 2 + (random2(powc) > 75);
beam.flavour = BEAM_LAVA;
beam.type = dchar_glyph(DCHAR_FIRED_ZAP);
beam.colour = RED;
beam.beam_source = MHITYOU;
beam.thrower = KILL_YOU_MISSILE;
beam.ench_power = powc; // used for radius
beam.name = "great blast of fire";
beam.hit = 20 + powc / 10;
beam.damage = calc_dice( 9, 20 + powc );
beam.ench_power = powc; // used for radius
beam.hit = 20 + powc / 10;
beam.damage = calc_dice( 9, 20 + powc );
beam.name = "lightning arc";
beam.aux_source = "chain lightning";
beam.beam_source = MHITYOU;
beam.thrower = KILL_YOU_MISSILE;
beam.range = 8;
beam.rangeMax = 8;
beam.hit = AUTOMATIC_HIT;
beam.type = dchar_glyph(DCHAR_FIRED_ZAP);
beam.flavour = BEAM_ELECTRICITY;
beam.name = "lightning arc";
beam.aux_source = "chain lightning";
beam.beam_source = MHITYOU;
beam.thrower = KILL_YOU_MISSILE;
beam.range = 8;
beam.rangeMax = 8;
beam.hit = AUTOMATIC_HIT;
beam.type = dchar_glyph(DCHAR_FIRED_ZAP);
beam.flavour = BEAM_ELECTRICITY;
// Nor can highly enchanted items
if ( arm.plus >= 2
&& (arm.sub_type >= ARM_CLOAK && arm.sub_type <= ARM_BOOTS
|| is_shield(arm)) )
// Nor can highly enchanted items.
if (arm.plus >= 2
&& (arm.sub_type >= ARM_CLOAK && arm.sub_type <= ARM_BOOTS
|| is_shield(arm)))
return (item.special < 100) && ((item.base_type == OBJ_CORPSES &&
item.sub_type == CORPSE_BODY) ||
(item.base_type == OBJ_FOOD &&
item.sub_type == FOOD_CHUNK));
return (item.special < 100) && (item.base_type == OBJ_CORPSES
&& item.sub_type == CORPSE_BODY
|| item.base_type == OBJ_FOOD
&& item.sub_type == FOOD_CHUNK);
exDamBonus = exDamBonus > 0? random2(exDamBonus + 1)
: -random2(-exDamBonus + 1);
exHitBonus = lnchHitBonus > 0? random2(lnchHitBonus + 1)
: -random2(-lnchHitBonus + 1);
exDamBonus = (exDamBonus > 0 ? random2(exDamBonus + 1)
: -random2(-exDamBonus + 1));
exHitBonus = (lnchHitBonus > 0 ? random2(lnchHitBonus + 1)
: -random2(-lnchHitBonus + 1));
// blowguns take a _very_ steady hand; a lot of the bonus
// comes from dexterity. (Dex bonus here as well as below)
// Blowguns take a _very_ steady hand; a lot of the bonus
// comes from dexterity. (Dex bonus here as well as below).
/* Note: weapons & ammo of eg fire are not cumulative
* ammo of fire and weapons of frost don't work together,
* and vice versa */
// Note: weapons & ammo of eg fire are not cumulative
// ammo of fire and weapons of frost don't work together,
// and vice versa.
// dwarves/orcs with dwarven/orcish weapons
if ( (get_equip_race(item) == ISFLAG_DWARVEN
&& player_genus(GENPC_DWARVEN)) ||
(get_equip_race(item) == ISFLAG_ORCISH
&& you.species == SP_HILL_ORC))
// Dwarves/orcs with dwarven/orcish weapons.
if (get_equip_race(item) == ISFLAG_DWARVEN
&& player_genus(GENPC_DWARVEN)
|| get_equip_race(item) == ISFLAG_ORCISH
&& you.species == SP_HILL_ORC)
// zapping() updates beam
if (!zapping( static_cast<zap_type>(type_zapped),
30 + roll_dice(2, you.skills[SK_EVOCATIONS]), beam ))
// Check whether we may hit friends, use "safe" values for random effects
// (highest possible range, and unresistable beam flavour).
if (!player_tracer(random ? ZAP_DEBUGGING_RAY : type_zapped,
2 * (you.skills[SK_EVOCATIONS] - 1), beam,
random ? 17 : 0))
bool zapping(zap_type ztype, int power, bolt &pbolt)
static void _beam_set_default_values(bolt &beam, int power)
{
beam.range = 8 + random2(5); // default for "0" beams (I think)
beam.rangeMax = 0;
beam.hit = 0; // default for "0" beams (I think)
beam.damage = dice_def( 1, 0 ); // default for "0" beams (I think)
beam.type = 0; // default for "0" beams
beam.flavour = BEAM_MAGIC; // default for "0" beams
beam.ench_power = power;
beam.obvious_effect = false;
beam.is_beam = false; // default for all beams.
beam.is_tracer = false; // default for all player beams
beam.thrower = KILL_YOU_MISSILE; // missile from player
beam.aux_source.clear(); // additional source info, unused
}
// If needs_tracer is true, we need to check the beam path for friendly
// monsters for *player beams* only! If allies are found, the player is
// prompted to stop or continue.
bool zapping(zap_type ztype, int power, bolt &pbolt, bool needs_tracer,
std::string msg)
// all of the following might be changed by zappy():
pbolt.range = 8 + random2(5); // default for "0" beams (I think)
pbolt.rangeMax = 0;
pbolt.hit = 0; // default for "0" beams (I think)
pbolt.damage = dice_def( 1, 0 ); // default for "0" beams (I think)
pbolt.type = 0; // default for "0" beams
pbolt.flavour = BEAM_MAGIC; // default for "0" beams
pbolt.ench_power = power;
pbolt.obvious_effect = false;
pbolt.is_beam = false; // default for all beams.
pbolt.is_tracer = false; // default for all player beams
pbolt.thrower = KILL_YOU_MISSILE; // missile from player
pbolt.aux_source.clear(); // additional source info, unused
// All of the following settings might be changed by _zappy().
_beam_set_default_values(pbolt, power);
// For player bolts, check whether tracer goes through friendlies.
// NOTE: Whenever zapping() is called with a randomized value for power,
// player_tracer should be called directly with the highest power possible
// respecting current skill, experience level etc.
if (needs_tracer && pbolt.thrower == KILL_YOU_MISSILE
&& !player_tracer(ztype, power, pbolt))
{
return (false);
}
if (pbolt.thrower == KILL_YOU_MISSILE)
{
pbolt.is_tracer = true;
// XXX: rangeMax needs to be set appropriately for the tracer!
pbolt.attitude = ATT_FRIENDLY;
pbolt.source_x = you.x_pos;
pbolt.source_y = you.y_pos;
fire_beam(pbolt);
if (!msg.empty())
mpr(msg.c_str());
if (pbolt.fr_count > 0 && !yesno("Really fire through this friendly "
"creature?", true, 'n'))
{
canned_msg(MSG_OK);
you.turn_is_over = false;
return (false);
}
pbolt.is_tracer = false;
}
// pbolt needs to be initialized for tracing: with the the maximum range,
// and the flavour to allow for completely resistant monsters.
static void _get_max_range( zap_type z_type, int power, bolt &pbolt )
{
// sorted by range
switch (z_type)
{
case ZAP_SMALL_SANDBLAST:
pbolt.rangeMax = 2;
pbolt.flavour = BEAM_FRAG; // extra AC resist
break;
case ZAP_SANDBLAST:
if (power > 50)
power = 50;
// pbolt.range = 2 + random2(power) / 20;
pbolt.rangeMax = 2 + (power-1) / 20; // max 4
pbolt.flavour = BEAM_FRAG; // extra AC resist
break;
case ZAP_FLAME_TONGUE:
if (power > 25)
power = 25;
// pbolt.range = 1 + random2(2) + random2(power) / 10;
pbolt.rangeMax = 2 + (power-1) / 10; // max 4
pbolt.flavour = BEAM_FIRE;
break;
case ZAP_CLEANSING_FLAME:
pbolt.name = "golden flame";
pbolt.rangeMax = 7;
pbolt.flavour = BEAM_HOLY;
pbolt.is_explosion = true;
break;
case ZAP_MAGMA:
pbolt.rangeMax = 8;
pbolt.flavour = BEAM_LAVA;
pbolt.is_beam = true;
break;
case ZAP_IRON_BOLT:
pbolt.rangeMax = 9;
pbolt.flavour = BEAM_MMISSILE; // unresistable
break;
case ZAP_CRYSTAL_SPEAR:
pbolt.rangeMax = 9;
pbolt.flavour = BEAM_MMISSILE; // unresistable
break;
case ZAP_SPIT_POISON:
if (power > 50)
power = 50;
// pbolt.range = 3 + random2( 1 + power / 2 );
pbolt.rangeMax = 3 + power / 2;
if (pbolt.rangeMax > 9)
pbolt.rangeMax = 9;
pbolt.flavour = BEAM_POISON;
break;
case ZAP_BREATHE_FIRE:
if (power > 50)
power = 50;
// pbolt.range = 3 + random2( 1 + power / 2 );
pbolt.rangeMax = 3 + power / 2;
if (pbolt.rangeMax > 9)
pbolt.rangeMax = 9;
pbolt.flavour = BEAM_FIRE;
pbolt.is_beam = true;
break;
case ZAP_BREATHE_FROST:
if (power > 50)
power = 50;
// pbolt.range = 3 + random2( 1 + power / 2 );
pbolt.rangeMax = 3 + power / 2;
if (pbolt.rangeMax > 9)
pbolt.rangeMax = 9;
pbolt.flavour = BEAM_COLD;
pbolt.is_beam = true;
break;
case ZAP_BREATHE_ACID:
if (power > 50)
power = 50;
// pbolt.range = 3 + random2( 1 + power / 2 );
pbolt.rangeMax = 3 + power / 2;
if (pbolt.rangeMax > 9)
pbolt.rangeMax = 9;
pbolt.flavour = BEAM_ACID;
pbolt.is_beam = true;
break;
case ZAP_BREATHE_POISON: // leaves clouds of gas
if (power > 50)
power = 50;
// pbolt.range = 3 + random2( 1 + power / 2 );
pbolt.rangeMax = 3 + power / 2;
if (pbolt.rangeMax > 9)
pbolt.rangeMax = 9;
pbolt.flavour = BEAM_POISON;
pbolt.is_beam = true;
break;
case ZAP_BREATHE_POWER:
if (power > 50)
power = 50;
// pbolt.range = 6 + random2( 1 + power / 2 );
pbolt.rangeMax = 6 + power / 2;
if (pbolt.rangeMax > 9)
pbolt.rangeMax = 9;
pbolt.flavour = BEAM_MMISSILE; // unresistable
pbolt.is_beam = true;
break;
case ZAP_BREATHE_STEAM:
pbolt.rangeMax = 9;
pbolt.flavour = BEAM_STEAM;
pbolt.is_beam = true;
break;
case ZAP_STRIKING:
case ZAP_MAGIC_DARTS:
case ZAP_STONE_ARROW:
case ZAP_MYSTIC_BLAST:
pbolt.rangeMax = 12;
pbolt.flavour = BEAM_MMISSILE; // unresistable
break;
case ZAP_STING:
case ZAP_POISON_ARROW:
pbolt.rangeMax = 12;
pbolt.flavour = BEAM_POISON;
break;
case ZAP_FLAME:
case ZAP_STICKY_FLAME:
pbolt.rangeMax = 12;
pbolt.flavour = BEAM_FIRE;
break;
case ZAP_FROST:
pbolt.rangeMax = 12;
pbolt.flavour = BEAM_COLD;
break;
case ZAP_ICE_BOLT:
pbolt.rangeMax = 12;
pbolt.flavour = BEAM_ICE; // half resistable
break;
case ZAP_ELECTRICITY:
pbolt.rangeMax = 13;
pbolt.flavour = BEAM_ELECTRICITY; // beams & reflects
pbolt.is_beam = true;
break;
case ZAP_DISRUPTION:
case ZAP_DISINTEGRATION:
pbolt.name = "0";
pbolt.rangeMax = 14;
pbolt.flavour = BEAM_DISINTEGRATION;
break;
case ZAP_PAIN:
pbolt.name = "0";
pbolt.rangeMax = 14;
pbolt.flavour = BEAM_PAIN;
break;
case ZAP_DISPEL_UNDEAD:
pbolt.name = "0";
pbolt.rangeMax = 14;
pbolt.flavour = BEAM_DISPEL_UNDEAD;
break;
case ZAP_FIRE:
pbolt.rangeMax = 16;
pbolt.flavour = BEAM_FIRE;
pbolt.is_beam = true;
break;
case ZAP_BONE_SHARDS:
pbolt.rangeMax = 16;
pbolt.flavour = BEAM_MAGIC; // unresisted
pbolt.is_beam = true;
break;
case ZAP_COLD:
pbolt.rangeMax = 16;
pbolt.flavour = BEAM_COLD;
pbolt.is_beam = true;
break;
case ZAP_NEGATIVE_ENERGY:
pbolt.rangeMax = 16;
pbolt.flavour = BEAM_NEG; // drains levels
pbolt.is_beam = true;
break;
case ZAP_BEAM_OF_ENERGY: // bolt of innacuracy
pbolt.range = 16;
pbolt.flavour = BEAM_ENERGY; // unresisted
pbolt.is_beam = true;
break;
case ZAP_VENOM_BOLT:
pbolt.rangeMax = 17;
pbolt.flavour = BEAM_POISON;
pbolt.is_beam = true;
break;
case ZAP_LIGHTNING:
pbolt.rangeMax = 17;
pbolt.flavour = BEAM_ELECTRICITY; // beams & reflects
pbolt.is_beam = true;
break;
// enchantments
case ZAP_ENSLAVEMENT:
pbolt.name = "0";
pbolt.rangeMax = 11;
pbolt.flavour = BEAM_CHARM;
break;
case ZAP_BANISHMENT:
pbolt.name = "0";
pbolt.rangeMax = 11;
pbolt.flavour = BEAM_BANISH;
break;
case ZAP_DEGENERATION:
pbolt.name = "0";
pbolt.rangeMax = 11;
pbolt.flavour = BEAM_DEGENERATE;
break;
case ZAP_ENSLAVE_UNDEAD:
pbolt.name = "0";
pbolt.rangeMax = 11;
pbolt.flavour = BEAM_ENSLAVE_UNDEAD;
break;
case ZAP_CONTROL_DEMON:
pbolt.name = "0";
pbolt.rangeMax = 11;
pbolt.flavour = BEAM_ENSLAVE_DEMON;
break;
case ZAP_SLEEP:
pbolt.name = "0";
pbolt.rangeMax = 11;
pbolt.flavour = BEAM_SLEEP;
break;
case ZAP_BACKLIGHT:
pbolt.name = "0";
pbolt.rangeMax = 11;
pbolt.flavour = BEAM_BACKLIGHT;
break;
case ZAP_SLOWING:
pbolt.name = "0";
pbolt.rangeMax = 12;
pbolt.flavour = BEAM_SLOW;
break;
case ZAP_HASTING:
pbolt.name = "0";
pbolt.rangeMax = 12;
pbolt.flavour = BEAM_HASTE;
break;
case ZAP_PARALYSIS:
pbolt.name = "0";
pbolt.rangeMax = 12;
pbolt.flavour = BEAM_PARALYSIS;
break;
case ZAP_CONFUSION:
pbolt.name = "0";
pbolt.rangeMax = 12;
pbolt.flavour = BEAM_CONFUSION;
break;
case ZAP_INVISIBILITY:
pbolt.name = "0";
pbolt.rangeMax = 12;
pbolt.flavour = BEAM_INVISIBILITY;
break;
case ZAP_HEALING:
pbolt.name = "0";
pbolt.rangeMax = 12;
pbolt.flavour = BEAM_HEALING;
break;
case ZAP_TELEPORTATION:
pbolt.name = "0";
pbolt.rangeMax = 13;
pbolt.flavour = BEAM_TELEPORT;
break;
case ZAP_POLYMORPH_OTHER:
pbolt.name = "0";
pbolt.rangeMax = 13;
pbolt.flavour = BEAM_POLYMORPH;
break;
case ZAP_AGONY:
pbolt.name = "0agony";
pbolt.rangeMax = 14;
pbolt.flavour = BEAM_PAIN;
break;
case ZAP_DIGGING:
pbolt.name = "0";
// pbolt.range = 3 + random2( power / 5 ) + random2(5);
pbolt.rangeMax = 6 + power / 5;
pbolt.flavour = BEAM_DIGGING;
pbolt.is_beam = true;
break;
// explosions
case ZAP_FIREBALL:
pbolt.name = "fireball";
pbolt.rangeMax = 12;
pbolt.flavour = BEAM_FIRE; // fire
pbolt.is_explosion = true;
break;
case ZAP_ICE_STORM:
pbolt.name = "great blast of cold";
pbolt.rangeMax = 13;
pbolt.ench_power = power; // used for radius
pbolt.flavour = BEAM_ICE; // half resisted
pbolt.is_explosion = true;
break;
case ZAP_ORB_OF_FRAGMENTATION: // cap 150
pbolt.name = "metal orb";
pbolt.rangeMax = 16;
pbolt.flavour = BEAM_FRAG; // extra AC resist
pbolt.is_explosion = true;
break;
case ZAP_HELLFIRE:
pbolt.rangeMax = 16;
pbolt.flavour = BEAM_HELLFIRE;
pbolt.is_explosion = true;
break;
case ZAP_ORB_OF_ELECTRICITY: // cap 150
pbolt.name = "orb of electricity";
pbolt.rangeMax = 20;
pbolt.flavour = BEAM_ELECTRICITY;
pbolt.is_explosion = true;
break;
case ZAP_DEBUGGING_RAY:
default: // buggy beam
pbolt.rangeMax = 16;
pbolt.flavour = BEAM_MMISSILE; // unresistable
break;
}
}
// FIXME: Also needs to check for fleeing monster with TSO and neutrals for
// all good gods.
bool player_tracer( zap_type ztype, int power, bolt &pbolt, int range)
{
_beam_set_default_values(pbolt, power);
pbolt.name = "unimportant";
_get_max_range(ztype, power, pbolt);
// override range if necessary
if (range > 0)
pbolt.rangeMax = range;
pbolt.is_tracer = true;
pbolt.source_x = you.x_pos;
pbolt.source_y = you.y_pos;
pbolt.beam_source = 0;
pbolt.can_see_invis = player_see_invis();
pbolt.smart_monster = true;
pbolt.attitude = ATT_FRIENDLY;
// init tracer variables
pbolt.foe_count = pbolt.fr_count = 0;
pbolt.foe_power = pbolt.fr_power = 0;
pbolt.fr_helped = pbolt.fr_hurt = 0;
pbolt.foe_helped = pbolt.foe_hurt = 0;
pbolt.foe_ratio = 100;
fire_beam(pbolt);
// Should only happen if the player answered 'n' to one of those
// "Fire through friendly?" prompts.
if (pbolt.fr_count > 0)
{
canned_msg(MSG_OK);
you.turn_is_over = false;
return (false);
}
// Set to non-tracing for actual firing.
pbolt.is_tracer = false;
return (true);
}
// check can see player
if (beam.can_see_invis || !you.invisible() || _fuzz_invis_tracer(beam))
// Check whether thrower can see player, unless thrower == player.
if (beam.thrower != KILL_YOU_MISSILE
&& (beam.can_see_invis || !you.invisible()
|| _fuzz_invis_tracer(beam)))
// enchant case -- enchantments always hit, so update target immed.
if (mons_atts_aligned(beam.attitude, mons_attitude(mon)))
// Enchant case -- enchantments always hit, so update target immed.
if (!mons_atts_aligned(beam.attitude, mons_attitude(mon)))
beam.fr_count += 1;
beam.fr_power += mons_power(mons_type);
bool count_friend = true;
if (beam.thrower == KILL_YOU_MISSILE)
{
snprintf(info, INFO_SIZE, "Really fire through %s?",
mon->name(DESC_NOCAP_THE).c_str());
if (!yesno(info))
{
beam.fr_count = 1;
return (BEAM_STOP);
}
else
count_friend = false;
}
if (count_friend)
{
beam.fr_count += 1;
beam.fr_power += mons_power(mons_type);
}
// nasty enchantments will annoy the monster, and are considered
// naughty (even if a monster might resist)
// Nasty enchantments will annoy the monster, and are considered
// naughty (even if a monster might resist).
beam.foe_count += 1;
beam.foe_power += 2 * hurt_final * mons_power(mons_type) / hurt;
if (beam.thrower != KILL_YOU_MISSILE)
{
// Counting foes is only important for monster tracers.
beam.foe_count += 1;
beam.foe_power += 2 * hurt_final * mons_power(mons_type)
/ hurt;
}
beam.fr_count += 1;
beam.fr_power += 2 * hurt_final * mons_power(mons_type) / hurt;
bool count_friend = true;
if (beam.thrower == KILL_YOU_MISSILE)
{
snprintf(info, INFO_SIZE, "Really fire through %s?",
mon->name(DESC_NOCAP_THE).c_str());
if (!yesno(info))
{
beam.fr_count = 1;
return (BEAM_STOP);
}
else
{
// Don't count friends we don't want counted.
count_friend = false;
}
}
if (count_friend)
{
beam.fr_count += 1;
beam.fr_power += 2 * hurt_final * mons_power(mons_type)
/ hurt;
}
pbolt.flavour = BEAM_FRAG; // sets it from pure damage to shrapnel (which is absorbed extra by armour)
pbolt.flavour = BEAM_FRAG; // Sets it from pure damage to shrapnel
// (which is absorbed extra by armour).
mpr("You spit poison.");
zapping( ZAP_SPIT_POISON,
you.experience_level
+ player_mutation_level(MUT_SPIT_POISON) * 5
+ (you.species == SP_NAGA) * 10,
beam );
zapping(ZAP_SPIT_POISON, pow, beam);
// don't check for hell serpents - they get hell fire,
// never regular fire (GDL)
mprf("You breathe fire%c", (power < 15)?'.':'!');
snprintf(info, INFO_SIZE, "You breathe fire%c",
(power < 15) ? '.':'!');
break;
// no longer in use, maybe keep for other cases (or remove!)
/*
case ABIL_ZIN_PESTILENCE:
mpr( "You call forth a swarm of pestilential beasts!" );
if (!summon_swarm( you.skills[SK_INVOCATIONS] * 8, false, true ))
mpr( "Nothing seems to have answered your call." );
exercise( SK_INVOCATIONS, 2 + random2(4) );
break;
case ABIL_ZIN_HOLY_WORD:
holy_word(you.skills[SK_INVOCATIONS] * 8, HOLY_WORD_GENERIC, you.x_pos,
you.y_pos, true);
exercise(SK_INVOCATIONS, 3 + random2(5));
break;
case ABIL_ZIN_SUMMON_GUARDIAN:
summon_ice_beast_etc(you.skills[SK_INVOCATIONS] * 4, MONS_ANGEL, true);
exercise(SK_INVOCATIONS, 8 + random2(10));
break;
case ABIL_TSO_REPEL_UNDEAD:
turn_undead(you.piety);
if (!you.duration[DUR_REPEL_UNDEAD])
mpr( "You feel a holy aura protecting you." );
you.duration[DUR_REPEL_UNDEAD] += 8
+ roll_dice(2, 2 * you.skills[SK_INVOCATIONS]);
if (you.duration[ DUR_REPEL_UNDEAD ] > 50)
you.duration[ DUR_REPEL_UNDEAD ] = 50;
exercise(SK_INVOCATIONS, 1);
break;
case ABIL_TSO_ANNIHILATE_UNDEAD:
if ( !spell_direction(spd, beam) )
{
return (false);
}
zapping(ZAP_DISPEL_UNDEAD, you.skills[SK_INVOCATIONS] * 6, beam);
exercise(SK_INVOCATIONS, 2 + random2(4));
beam.type = dchar_glyph(DCHAR_FIRED_BURST);
beam.damage = dice_def( 3, 30 );
beam.flavour = BEAM_ELECTRICITY;
beam.target_x = you.x_pos;
beam.target_y = you.y_pos;
beam.name = "blast of lightning";
beam.colour = LIGHTCYAN;
beam.thrower = KILL_YOU;
beam.aux_source = "Makhleb's lightning strike";
beam.ex_size = 1 + you.skills[SK_INVOCATIONS] / 8;
beam.is_tracer = false;
beam.type = dchar_glyph(DCHAR_FIRED_BURST);
beam.damage = dice_def( 3, 30 );
beam.flavour = BEAM_ELECTRICITY;
beam.target_x = you.x_pos;
beam.target_y = you.y_pos;
beam.name = "blast of lightning";
beam.colour = LIGHTCYAN;
beam.thrower = KILL_YOU;
beam.aux_source = "Makhleb's lightning strike";
beam.ex_size = 1 + you.skills[SK_INVOCATIONS] / 8;
beam.is_tracer = false;