penetration (not phasing) for launchers and shadow, penetration, dispersal, exploding, steel and silver for ammo. Never randomly generated.
If a launcher of venom is used to launch flame or ice ammo then the resulting bolt will be poisoned, just like poisoned ammo launched from a launcer of flame or frost.
Put missile beam setup code that's common to monsters and the player in setup_missile_beam().
Removed mons_thrown_object_destroyed(), thrown_object_destroyed() is now used for both monsters and the player.
The bolt struct has several new callback fields that can be set to alter the beam's behaviour; currently only used by the brands implemented in this commit, but they should be general enough to be used by anything.
The bolt struct has the new field "special_explosion" which can be used to cause an explosion with flavour and/or damage dice different than the rest of the beam.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@8449 c06c8d41-db1a-0410-9941-cceddc491573
V633AMMPMHJB5ZLP5IHFXCT6FCENVTPX25TY7T5MF2QZLDDN24HAC O2JZ3E7K4CHLODQA23ZAP7CTX636PTFLOE4CLQL6AJPN4ON5SGLQC 2P6H6IUP2MYDWNF4VZFITNCNBCVDFHJXOPTV2TQXAPOOLPJKIDNQC MFP3WAGO2JIOT4QSEYPM4OJV5NVXMUOPL75OIE7YZ5RWOYQPIZ7AC 6RKGEX37UA6R2NYUFNTYUJXXJOI67YTRB6TGOHMPG2IFXD6SVGFAC 7CZXCSI3A4XRQ5RK2B7AZOS3JIQBD2EBSRIWBNMUU3WMVQ6IRFNQC UDDZ7BNFAK3BDG5UIOMEDWGH4XRJOWV4AERTZOJ7VT6IOKBP4EIQC JLCVRRM3BR37DZJV7ED4CRRWXFYIOFTIM32DYM3DXBOS3WYZNWMQC Y3CZBT22Z4SMP4H2HW2U4F4X5KP2I5SGOBXATDEIDV6S3ANGQ2HAC SKIHTFLZCN33YOLY6DBH5AD45EIUFX3CS44CMITAP7JVHRZN5RSQC OQECLU7MBB6HZQPTVNUE27GDBZZ2IRND4FREQ2JUX5I3B6WZXEPQC XBXO44GTW26ELSWP4ZRCRIFOZO7JULKLV3IXAMGR2YZ5B7KVSIDAC QFWRKRPFS7TWZYFMIXWU24RS6DAUQPJS47O4HY456PXQJDOYNDWQC Y756PLIQ6IS4CY6R5PNBKI5PORSGSXP2KWO4J22A4DV6VSDDKZGAC NRIZKLUO26UHNKB4IERXI6ECMD2IJYZACQNIUU3SH6BPLGHAJYVAC K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC PBKRKGKARGZSLVFVDTK5NWDXQD26NHNN67LDSSB75CLEWBR6TLEQC TGJZXTUIAKCFZQJ54ZQEBGFBVZSJCAX6AWDRSH3TP7UJRLGUM5SAC W74555HMPXUQ72AGKBXC5P3STMMX5DZAW6ZESUDLNVJBCAG43PLAC FA2V3G4NYTWJWUT7EWH75L3YOUX6YVOZ5LNRSFLO2XF273JKSUTAC Y2NYY7HWFZ2LQDK3ACSLGS37F2J2IJ5LRGCIMZYXLEOSVPD3A4DAC SUWIERONPDATHPDMZRYO6GYIXSW6XIS5V5MK5IV23DWQH2LL7VIAC CDFS7Z74W5HKPQIHQICOG442KQFXUSBGGLDDQLE3MG74T44YU6AQC RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC AYU5OVG2HZO46KDAPKUWAVHS5HTYFKUWIMIRMTHAXVVFEDJE7YPAC JYEEOUYQ7ZPKOGWUV7VCORBVSOLF2UCBFBH3TR75RGOSS6PNKYUAC CUM44NOPIB7LGTRY2O2R5MYXAB27R3TFM6LUBEQHZFXLZWJ55QZAC SIDH2P7NBIG5KEOE27XHD3ZT2NQ2OJZFN6VZXWNWYFFY5YVXSSVQC SH5BS5AJPUFPXQHM5MZPIY3CCVT4EAIRLSAQWZYL5WX2J7FPBSQQC 2OY3EXIBFR22QCCKPZOA37YUI7CX7BEKRRYSDSBDKQN6VTDBD7LAC YOH32TMLN6QJG4ZFLYWPJF3YUEGIMZPVPYN57RTB26QBBHMICV3AC ZNMT5CZHP2FC4HTLNA7KYEDGFBXSCUE5QHJOALVPE6RDPHSEDXRQC NNG27Y5ZQAZX6UD7F7M4F6KEZBEDFXPEEC3LFUSX4ESKT7K6UJQAC 3DQXSE4YGFBBDUWK4YEOFWW4UPWILWELFSLP37SL6BERGAZJC5YAC NLQNXH3SVJ52CWXEV35FSSZP32VHC4QFGN3HINF4KO5GZHZMOBKQC QDTVLBRGHDTRUVT7I3O72K6TMOYAUSAJBZUHGOEFU2RKJNUPWZSQC KAOE5HB3THUKVGFZRO5EZESHEB3Q34WUO5DFMLWIKOBF47LZTIYAC MSMWAL6JZAWNGZXCNXPATUMAU6TVXBWWFY666P7UBSZ5LPYJYUCQC WT66JDIRTLLP37SHTV4GI3V64JFJ4D25LNRLGCHFG6CLEFKJ3QGQC T6TL6NTIOBYNUIONGK3JFZJ5ONWV6S4CTIRDC5JMKMCBGG5IY3EAC SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC 3ZWALZFSTSIVYXY4BAY6ANGINTDACZC6RSSJTEMQSTSUIE66YOBQC 6GDKXNFXPKQ6AVNOSMJECN7CLELM2KCMVRM2A7BARLK2NNILN6SAC BWAQ3FHBBM6G3K3KYP75CRTR343RDQZJRYX5ZGYUEXYBAC3APDLAC LDBTCT5WIPLJPZWXS2RUQ26QKISCUUTLO77M464WOE6VSYSNPKYAC VNHFP63ZLLZU3A3PLXP4BITX57DUIYDHFOHQYK3BOBHV3S64G26QC 6JBULLXOSQVDJZP2R73BFMPV2OHWFT4V3KBPU5CTGN7REHBOB5NQC SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC 3FRPKD2JSN7RA2HKWAO3XV7MMKCIAMWIMU6JNJ452VZEUSXM6PWQC 77H4BWWPPGLM3PLZH4QTAJRXIZTSDVNCOKZE223I437FN2UJ34RQC ASCTVJSN3NXYQHRVXAORA43CV6H5V2572IMK4UGRHKBAGJOWHC4AC S34LKQDIQJLIWVIPASOJBBZ6ZCXDHP5KPS7TRBZJSCDRVNCLK6UAC 3EUPIYJNWOMOQBP2Z5SGSMWK453BXJD6KL2WFTR3NM565MEBYASAC QZM4EDMUKU7QWQKWXHTRINNWH3GQQ6RSAX7WIX6PQAEM5V2Y2BQQC ACSERNMWRXP4VUEUVKDBSDGTBZRI34P2PUVUDTKSAHNTCEDDCCVAC RDZUMV3A5TREQHLPPJWDWVXBNIOWC3CQJJ35TYFBQQVQNTU7SPXQC UZ5623MOLKBTGBSRBJ4OBOEI4IEZSPV3NCV2DRMUZ3CHHJQVHIIAC 5KJCHLIUFKRPMIVWUAYT6EOF7SW4PTQF6Y5OPEFWXGLE7DUGYLZAC 5V47S4NNTHWTSAHV3YLO2VGH7JTUIYJ3GBPDN5ZM4UQALT2ZEXDQC FLAGBNUNSIQNFDN53CDWABJRTTFWDL4PG34AI474ZKPXDEPYHOAQC CIPVRZGLOZHCERK6YPOBV3P2E4IAB4H6D5EHLRQE2O5E4P4VCBUAC X2RVB2O2TUAT336F5ZN3SRNB2EKPHSJKRD6FHI6YM3AYRDV7XJUAC ASLW3Z5PAVZSWJEMMMVZT226P44EKSAD47QS72JIFJESAI3RPN3AC AIVXE6QBRVCZAASKQRZO6LBDGTYEYSSD2DZCWRX4VLSKE3GCNIDAC LACOILN7WCNIM3GTLY56TQOMC3MFPW2XX3RHDWXRSMBQQPI4AQXQC UADYVV3UD5ERJTZZJGY4EUQ4NJ2JSBG7YYUJ75ZRBIXRQXQKOJPAC BTHEX36BHZOAGTT5SNO6OPWDAZJQSUUNDXSJ77FBEFZE3NGJ7CAQC E46VBOJB5K4GCWG4BBMJZOSCHWRAS5JMHSFVANRS2DEESAWYVD4QC E6NTYF4PVIESKDOXXSDV6DFBAGOLBHE66HAJIGG76ZWPNHURKIIAC PI5BATR2SER3RFE76IUGHM2AGXVFOUM3PLU7WC2K2Q2BA5K2E73QC PHBACPMH3F34GODHVDKNCMXWU373RJQGVTDLBFCCDLLWDXVYOLTAC ISUJEAPPWKP2UIYPT6BJUUNSVH52NEXWGXNUATL7I3IO7TPO32HAC 5BJPWUPLJFS34FUTFJVKA4A52YMIGV6EWDXLNSDCWBJWBGVSQFGQC TCZNXMPFNAWJYUIBTUEOTT73KLB4CU5S6HBKTHRT6KCD4ZVGBGUQC SJP5BHX6MFWF3OSQPEF4WUWZWPUGMOVURTT2CUVT6H3A66LETXUAC MFCHFDPW4YX4QZWUOJIT3UG6OHIJPWZRXLYZQCSAUQFCEPYOYHEAC 5K2ANIEXD3CPJM4XNKNPZINP2G4NT7SJBKRN62WNBUKJXFERTILQC MZXKH5NHXRMX5Y5FG4XXNHZQ7HTQZFX3ARQU55DO4RM5NR3GIAIQC 7YUGK5Q64KG5O7GJGTUBRRLHAHBCJ5YOE23YUPT6UBKUSB67CYAQC 5FHWTG7M6FW4B3I33YI7QSM3OZIB6ZGC6TI6JISSLY5Y43HI56VAC M53SMQWSTQBB24VSHBX7KJAAMMWGVKKPKV4TLMFHONWYYCNEDRGAC GSJA56E3ORVIBCBA6T6WU2HE4DCLJ6NZPW76O7L54N4CYPKLJOWQC WFMQVPMMOPG5SBJD5LUBOIYWRMXVWK3FXENK7SAEGZ5T6XWFKERQC 64VBM7SGUX7CVO5TMVOFU4A26BDOFQXKS6G5K7BXCSWKCCXEETOAC SNSU5AMDAZNG55NQ4JDHU2YBK62MXPIE2QTSYS7PGV7Y2N3VJBFQC 3U7R5PBYTKTXZIIC2UE3MWMJSQSDK2EIZKSPR3PF434ZWK7A76JQC LCDK2CK4O2RBLF2MAX75S2Q6ZKAX46WD6GOQDVIXUGHHXXZXMHRQC AJHVP42Y67SB4NKFMZB24524PGX2XA5WLFNEFV52MIGTS47ALMVQC pbolt.range = LOS_RADIUS;pbolt.beam_source = monster_index(monster);pbolt.type = dchar_glyph(DCHAR_FIRED_MISSILE);pbolt.colour = item.colour;pbolt.flavour = BEAM_MISSILE;pbolt.thrower = KILL_MON_MISSILE;pbolt.item = &item;pbolt.aux_source.clear();
pbolt.range = LOS_RADIUS;
exDamBonus += 6;pbolt.flavour = BEAM_CHAOS;pbolt.name = "bolt of chaos";pbolt.colour = EC_RANDOM;pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP);}// WEAPON or AMMO of FIREelse if (bow_brand == SPWPN_FLAME && ammo_brand != SPMSL_ICE|| ammo_brand == SPMSL_FLAME && bow_brand != SPWPN_FROST){baseHit += 2;exDamBonus += 6;pbolt.flavour = BEAM_FIRE;pbolt.name = "bolt of ";if (poison)pbolt.name += "poison ";pbolt.name += "flame";pbolt.colour = RED;pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP);}// WEAPON or AMMO of FROSTelse if (bow_brand == SPWPN_FROST && ammo_brand != SPMSL_FLAME|| ammo_brand == SPMSL_ICE && bow_brand != SPWPN_FLAME){baseHit += 2;
return (true);}bool mons_thrown_object_destroyed( item_def *item, const coord_def& where,bool returning, int midx ){ASSERT( item != NULL );
bool destroyed = (item->base_type == OBJ_MISSILES&& item->sub_type != MI_THROWING_NET && coinflip());bool hostile_grid = grid_destroys_items(grd(where));
if (pbolt.special_explosion != NULL)delete pbolt.special_explosion;
// Non-returning items thrown into item-destroying grids are always// destroyed. Returning items are only destroyed if they would have// been randomly destroyed anyway.if (returning && !destroyed)hostile_grid = false;// Summoned items go poof if they're not returning.if (hostile_grid || !returning && (item->flags & ISFLAG_SUMMONED)){// No destruction sound here. Too much message spam otherwise.item_was_destroyed(*item, midx);destroyed = true;}return destroyed;
return (true);
void monster_die(monsters *monster, killer_type killer,int killer_index, bool silent = false, bool wizard = false);
int monster_die(monsters *monster, killer_type killer,int killer_index, bool silent = false, bool wizard = false);
}static int _item_to_skill_level(const item_def *item){skill_type type = range_skill(*item);if (type == SK_DARTS || type == SK_SLINGS)return (you.skills[type] + you.skills[SK_THROWING]);return (2 * you.skills[type]);}static bool _poison_hit_victim(bolt& beam, actor* victim, int dmg, int corpse){if (!victim->alive() || victim->res_poison())return (false);if (beam.is_tracer)return (true);int levels = 0;actor* agent = beam.agent();if (agent->atype() == ACT_MONSTER){if (dmg > 0 || beam.ench_power == AUTOMATIC_HIT&& x_chance_in_y(90 - 3 * victim->armour_class(), 100)){levels = 1 + random2(3);}}else{if (beam.ench_power == AUTOMATIC_HIT&& x_chance_in_y(90 - 3 * victim->armour_class(), 100)){levels = 2;}else if (random2(dmg) > random2(victim->armour_class()))levels = 1;int num_success = 0;if (YOU_KILL(beam.thrower)){const int skill_level = _item_to_skill_level(beam.item);if (x_chance_in_y(skill_level + 25, 50))num_success++;if (x_chance_in_y(skill_level, 50))num_success++;}elsenum_success = 1;if (num_success == 0)return (false);else{if (num_success == 2)levels++;}}if (levels <= 0)return (false);victim->poison(agent, levels);return (true);}static bool _item_penetrates_victim(const bolt &beam, const actor *victim,int &used){if (beam.aimed_at_feet)return (false);used = 0;if (!beam.is_tracer && you.can_see(victim))mprf("The %s passes through %s!", beam.name.c_str(),victim->name(DESC_NOCAP_THE).c_str());return (true);}static bool _silver_damages_victim(bolt &beam, actor* victim, int &dmg,std::string &dmg_msg){bool shifter;if (victim->atype() == ACT_MONSTER){monsters* mon = dynamic_cast<monsters*>(victim);shifter = mons_is_shapeshifter(mon);}elseshifter = transform_changed_physiology();mon_holy_type holiness = victim->holiness();if (shifter || holiness == MH_UNDEAD || holiness == MH_DEMONIC){dmg *= 2;if (!beam.is_tracer && you.can_see(victim))dmg_msg = "The silver sears " + victim->name(DESC_NOCAP_THE) + "!";}return (false);}static bool _shadow_hit_victim(bolt& beam, actor* victim, int dmg, int corpse){if (beam.is_tracer || victim->alive() || corpse == -1|| corpse == NON_ITEM){return (false);}actor* agent = beam.agent();beh_type beh;unsigned short hitting;if (agent->atype() == ACT_PLAYER){hitting = you.pet_target;beh = BEH_FRIENDLY;}else{monsters *mon = dynamic_cast<monsters*>(agent);beh = SAME_ATTITUDE(mon);// Get a new foe for the zombie to target.behaviour_event(mon, ME_EVAL);hitting = mon->foe;}int midx = NON_MONSTER;if (!animate_remains(victim->pos(), CORPSE_BODY, beh, hitting,GOD_NO_GOD, true, true, &midx)){return (false);}monsters *zomb = &menv[midx];if (you.can_see(victim))mprf("%s turns into a zombie!", victim->name(DESC_CAP_THE).c_str());else if (you.can_see(zomb))mprf("%s appears out of thin air!", zomb->name(DESC_CAP_THE).c_str());return (true);
if (!victim->alive() || victim == agent)return (false);if (beam.is_tracer)return (true);const bool was_seen = you.can_see(victim);const bool no_sanct = victim->kill_alignment() == KC_OTHER;coord_def pos, pos2;int tries = 0;do{if (!random_near_space(victim->pos(), pos, false, true, no_sanct))return (false);} while (!victim->is_habitable(pos) && tries++ < 100);if (!victim->is_habitable(pos))return (false);tries = 0;do{random_near_space(victim->pos(), pos2, false, true, no_sanct);} while (!victim->is_habitable(pos2) && tries++ < 100);if (!victim->is_habitable(pos2))return (false);// Pick the square further away from the agent.const coord_def from = agent->pos();if (in_bounds(pos2)&& grid_distance(pos2, from) > grid_distance(pos, from)){pos = pos2;}if (pos == victim->pos())return (false);const coord_def oldpos = victim->pos();if (victim->atype() == ACT_PLAYER){clear_trapping_net();victim->moveto(pos);mpr("You blink!");}else{monsters *mon = dynamic_cast<monsters*>(victim);mons_clear_trapping_net(mon);mon->check_redraw(oldpos);mon->move_to_pos(pos);mon->apply_location_effects(pos);mon->check_redraw(pos);const bool seen = you.can_see(mon);const std::string name = mon->name(DESC_CAP_THE);if (was_seen && seen)mprf("%s blinks!", name.c_str());else if (was_seen && !seen)mprf("%s vanishes!", name.c_str());else if (!was_seen && seen)mprf("%s appears from out of thin air!", name.c_str());}return (true);}void setup_missile_beam(const actor *agent, bolt &beam, item_def &item,std::string &ammo_name, bool &returning){dungeon_char_type zapsym = DCHAR_SPACE;switch (item.base_type){case OBJ_WEAPONS: zapsym = DCHAR_FIRED_WEAPON; break;case OBJ_MISSILES: zapsym = DCHAR_FIRED_MISSILE; break;case OBJ_ARMOUR: zapsym = DCHAR_FIRED_ARMOUR; break;case OBJ_WANDS: zapsym = DCHAR_FIRED_STICK; break;case OBJ_FOOD: zapsym = DCHAR_FIRED_CHUNK; break;case OBJ_UNKNOWN_I: zapsym = DCHAR_FIRED_BURST; break;case OBJ_SCROLLS: zapsym = DCHAR_FIRED_SCROLL; break;case OBJ_JEWELLERY: zapsym = DCHAR_FIRED_TRINKET; break;case OBJ_POTIONS: zapsym = DCHAR_FIRED_FLASK; break;case OBJ_UNKNOWN_II: zapsym = DCHAR_FIRED_ZAP; break;case OBJ_BOOKS: zapsym = DCHAR_FIRED_BOOK; break;case OBJ_STAVES: zapsym = DCHAR_FIRED_STICK; break;default: break;}beam.type = dchar_glyph(zapsym);returning = get_weapon_brand(item) == SPWPN_RETURNING|| get_ammo_brand(item) == SPMSL_RETURNING;if (agent->atype() == ACT_PLAYER){beam.attitude = ATT_FRIENDLY;beam.beam_source = NON_MONSTER;beam.smart_monster = true;beam.thrower = KILL_YOU_MISSILE;}else{const monsters *mon = dynamic_cast<const monsters*>(agent);beam.attitude = mons_attitude(mon);beam.beam_source = mon->mindex();beam.smart_monster = (mons_intel(mon) >= I_NORMAL);beam.thrower = KILL_MON_MISSILE;}beam.item = &item;beam.source = agent->pos();beam.colour = item.colour;beam.flavour = BEAM_MISSILE;beam.is_beam = false;beam.aux_source.clear();beam.can_see_invis = agent->can_see_invisible();item_def *launcher = const_cast<actor*>(agent)->weapon(0);if (launcher && !item.launched_by(*launcher))launcher = NULL;int bow_brand = SPWPN_NORMAL;if (launcher != NULL)bow_brand = get_weapon_brand(*launcher);int ammo_brand = get_ammo_brand(item);bool poisoned = ammo_brand == SPMSL_POISONED;if (bow_brand == SPWPN_VENOM && ammo_brand != SPMSL_CURARE){if (ammo_brand == SPMSL_NORMAL)item.special = SPMSL_POISONED;poisoned = true;}const bool exploding = ammo_brand == SPMSL_EXPLODING;const bool penetrating = !exploding&& (bow_brand == SPWPN_PENETRATION|| ammo_brand == SPMSL_PENETRATION);const bool silver = ammo_brand == SPMSL_SILVER;const bool disperses = ammo_brand == SPMSL_DISPERSAL;const bool shadow = bow_brand == SPWPN_SHADOW|| ammo_brand == SPMSL_SHADOW;ASSERT(!exploding || !is_artefact(item));beam.name = item.name(DESC_PLAIN, false, false, false);// Print type of item as influenced by launcher.item_def ammo = item;// The chief advantage here is the extra damage this does// against susceptible creatures.// Note: weapons & ammo of eg fire are not cumulative// ammo of fire and weapons of frost don't work together,// and vice versa.// Note that bow_brand is known since the bow is equipped.// Chaos overides flame and frost/ice.if (bow_brand == SPWPN_CHAOS || ammo_brand == SPMSL_CHAOS){// Chaos can't be poisoned, since that might conflict with// the random healing effect or overlap with the random// poisoning effect.poisoned = false;if (item.special == SPWPN_VENOM || item.special == SPMSL_CURARE)item.special = SPMSL_NORMAL;beam.effect_known = false;beam.flavour = BEAM_CHAOS;beam.name = "chaos";beam.colour = EC_RANDOM;ammo.special = SPMSL_CHAOS;}else if ((bow_brand == SPWPN_FLAME || ammo_brand == SPMSL_FLAME)&& ammo_brand != SPMSL_ICE && bow_brand != SPWPN_FROST){beam.flavour = BEAM_FIRE;beam.name = "flame";beam.colour = RED;ammo.special = SPMSL_FLAME;}else if ((bow_brand == SPWPN_FROST || ammo_brand == SPMSL_ICE)&& ammo_brand != SPMSL_FLAME && bow_brand != SPWPN_FLAME){beam.flavour = BEAM_COLD;beam.name = "frost";beam.colour = WHITE;ammo.special = SPMSL_ICE;}ASSERT(beam.flavour == BEAM_MISSILE || !is_artefact(item));ammo_name = ammo.name(DESC_PLAIN);if (silver)beam.damage_funcs.push_back(_silver_damages_victim);if (poisoned)beam.hit_funcs.push_back(_poison_hit_victim);if (penetrating)beam.range_funcs.push_back(_item_penetrates_victim);if (shadow)beam.hit_funcs.push_back(_shadow_hit_victim);if (disperses)beam.hit_funcs.push_back(_dispersal_hit_victim);if (shadow && ammo.special != SPMSL_SHADOW){beam.name = "shadowy " + beam.name;ammo_name = "shadowy " + ammo_name;}if (disperses && ammo.special != SPMSL_DISPERSAL){beam.name = "dispersing " + beam.name;ammo_name = "dispersing " + ammo_name;}if (poisoned && ammo.special != SPMSL_POISONED){beam.name = "poison " + beam.name;ammo_name = "poisoned " + ammo_name;}if (penetrating && ammo.special != SPMSL_PENETRATION){beam.name = "penetrating " + beam.name;ammo_name = "penetrating " + ammo_name;}if (silver && ammo.special != SPMSL_SILVER){beam.name = "silvery " + beam.name;ammo_name = "silvery " + ammo_name;}// Do this here so that we get all the name mods except for a// redundant "exploding".if (exploding){bolt *expl = new bolt(beam);expl->is_explosion = true;expl->damage = dice_def(2, 5);expl->ex_size = 1;if (beam.flavour == BEAM_MISSILE){expl->flavour = BEAM_FRAG;expl->name += " fragments";const std::string short_name =ammo.name(DESC_PLAIN, false, false, false, false,ISFLAG_IDENT_MASK | ISFLAG_COSMETIC_MASK| ISFLAG_RACIAL_MASK);expl->name = replace_all(expl->name, ammo.name(DESC_PLAIN),short_name);}beam.special_explosion = expl;}if (exploding && ammo.special != SPMSL_EXPLODING){beam.name = "exploding " + beam.name;ammo_name = "exploding " + ammo_name;}if (beam.flavour != BEAM_MISSILE){returning = false;beam.type = dchar_glyph(DCHAR_FIRED_BOLT);beam.name = "bolt of " + beam.name;}if (!is_artefact(item))ammo_name = article_a(ammo_name, true);}
// Hack the quantity to 1 while getting the name.const int old_quantity = thrown.quantity;thrown.quantity = 1;pbolt.name = thrown.name(DESC_PLAIN, false, false, false);thrown.quantity = old_quantity;pbolt.thrower = KILL_YOU_MISSILE;pbolt.source = you.pos();pbolt.colour = thrown.colour;pbolt.flavour = BEAM_MISSILE;pbolt.aux_source.clear();
dungeon_char_type zapsym = DCHAR_SPACE;switch (item.base_type){case OBJ_WEAPONS: zapsym = DCHAR_FIRED_WEAPON; break;case OBJ_MISSILES: zapsym = DCHAR_FIRED_MISSILE; break;case OBJ_ARMOUR: zapsym = DCHAR_FIRED_ARMOUR; break;case OBJ_WANDS: zapsym = DCHAR_FIRED_STICK; break;case OBJ_FOOD: zapsym = DCHAR_FIRED_CHUNK; break;case OBJ_UNKNOWN_I: zapsym = DCHAR_FIRED_BURST; break;case OBJ_SCROLLS: zapsym = DCHAR_FIRED_SCROLL; break;case OBJ_JEWELLERY: zapsym = DCHAR_FIRED_TRINKET; break;case OBJ_POTIONS: zapsym = DCHAR_FIRED_FLASK; break;case OBJ_UNKNOWN_II: zapsym = DCHAR_FIRED_ZAP; break;case OBJ_BOOKS: zapsym = DCHAR_FIRED_BOOK; break;case OBJ_STAVES: zapsym = DCHAR_FIRED_STICK; break;default: break;}pbolt.type = dchar_glyph(zapsym);
// Special cases for flame, frost, poison, etc.// check for venom brand.if (bow_brand == SPWPN_VENOM && ammo_brand == SPMSL_NORMAL){// Poison brand the ammo.set_item_ego_type( item, OBJ_MISSILES, SPMSL_POISONED );pbolt.name = item.name(DESC_PLAIN);}
if (ammo_brand == SPMSL_STEEL)dice_mult = dice_mult * 150 / 100;
// The chief advantage here is the extra damage this does// against susceptible creatures.// Note: weapons & ammo of eg fire are not cumulative// ammo of fire and weapons of frost don't work together,// and vice versa.// Note that bow_brand is known since the bow is equipped.// Chaos overides flame and frost/ice.if (bow_brand == SPWPN_CHAOS || ammo_brand == SPMSL_CHAOS){// Chaos can't be poisoned, since that might conflict with// the random healing effect or overlap with the random// poisoning effect.poisoned = false;// [dshaligram] Branded arrows are much stronger.dice_mult = (dice_mult * 150) / 100;pbolt.effect_known = false;pbolt.flavour = BEAM_CHAOS;pbolt.name = "bolt of chaos";pbolt.colour = EC_RANDOM;pbolt.type = dchar_glyph(DCHAR_FIRED_BOLT);pbolt.thrower = KILL_YOU_MISSILE;pbolt.aux_source.clear();}else if ((bow_brand == SPWPN_FLAME || ammo_brand == SPMSL_FLAME)&& ammo_brand != SPMSL_ICE && bow_brand != SPWPN_FROST){
if (pbolt.flavour != BEAM_MISSILE)
pbolt.flavour = BEAM_FIRE;pbolt.name = "bolt of ";if (poisoned)pbolt.name += "poison ";pbolt.name += "flame";pbolt.colour = RED;pbolt.type = dchar_glyph(DCHAR_FIRED_BOLT);pbolt.thrower = KILL_YOU_MISSILE;pbolt.aux_source.clear();}else if ((bow_brand == SPWPN_FROST || ammo_brand == SPMSL_ICE)&& ammo_brand != SPMSL_FLAME && bow_brand != SPWPN_FLAME){// [dshaligram] Branded arrows are much stronger.dice_mult = (dice_mult * 150) / 100;pbolt.flavour = BEAM_COLD;pbolt.name = "bolt of ";if (poisoned)pbolt.name += "poison ";pbolt.name += "frost";pbolt.colour = WHITE;pbolt.type = dchar_glyph(DCHAR_FIRED_BOLT);pbolt.thrower = KILL_YOU_MISSILE;pbolt.aux_source.clear();}
// Print type of item as influenced by launcher.item_def ammo = item;if (ammo.base_type == OBJ_MISSILES){if (pbolt.flavour == BEAM_CHAOS){ammo.special = SPMSL_CHAOS;}else if (pbolt.flavour == BEAM_FIRE){if (ammo.special != SPMSL_FLAME)ammo.special = SPMSL_FLAME;}else if (pbolt.flavour == BEAM_COLD){if (ammo.special != SPMSL_ICE)ammo.special = SPMSL_ICE;}else{if (ammo.special != SPMSL_NORMAL && ammo.special != SPMSL_POISONED)ammo.special = SPMSL_NORMAL;}}if (ammo_name.empty())ammo_name = ammo.name(DESC_NOCAP_A);
bool bolt::apply_dmg_funcs(actor* victim, int &dmg,std::vector<std::string> &messages){for (unsigned int i = 0; i < damage_funcs.size(); i++){std::string dmg_msg;if ( (*damage_funcs[i])(*this, victim, dmg, dmg_msg) )return (false);if (!dmg_msg.empty())messages.push_back(dmg_msg);}return (true);}static void _undo_tracer(bolt &orig, bolt ©){// FIXME: we should have a better idea of what gets changed!orig.target = copy.target;orig.source = copy.source;orig.aimed_at_spot = copy.aimed_at_spot;orig.range_used = copy.range_used;orig.auto_hit = copy.auto_hit;orig.ray = copy.ray;orig.colour = copy.colour;orig.flavour = copy.flavour;orig.real_flavour = copy.real_flavour;orig.seen = copy.seen;}
// FIXME: we should have a better idea of what gets changed!target = boltcopy.target;source = boltcopy.source;aimed_at_spot = boltcopy.aimed_at_spot;range_used = boltcopy.range_used;auto_hit = boltcopy.auto_hit;ray = boltcopy.ray;colour = boltcopy.colour;flavour = boltcopy.flavour;real_flavour = boltcopy.real_flavour;seen = boltcopy.seen;
if (special_explosion != NULL){seen = seen || special_explosion->seen;foe_info += special_explosion->foe_info;friend_info += special_explosion->friend_info;_undo_tracer(*special_explosion, *boltcopy.special_explosion);delete boltcopy.special_explosion;}_undo_tracer(*this, boltcopy);
range_used += range_used_on_hit();
std::vector<std::string> messages;int dummy = 0;apply_dmg_funcs(&you, dummy, messages);for (unsigned int i = 0; i < messages.size(); i++)mpr(messages[i].c_str(), MSGCH_WARN);range_used += range_used_on_hit(&you);apply_hit_funcs(&you, 0);
else if (item->special == SPMSL_POISONED){if (!player_res_poison()&& (hurted || ench_power == AUTOMATIC_HIT&& x_chance_in_y(90 - 3 * player_AC(), 100))){poison_player(1 + random2(3));was_affected = true;}}
if (name.find("dart") != std::string::npos)type = SK_DARTS;else if (name.find("needle") != std::string::npos)type = SK_DARTS;else if (name.find("bolt") != std::string::npos)type = SK_CROSSBOWS;else if (name.find("arrow") != std::string::npos)type = SK_BOWS;else if (name.find("stone") != std::string::npos)type = SK_SLINGS;if (type == SK_DARTS || type == SK_SLINGS)return (you.skills[type] + you.skills[SK_THROWING]);return (2 * you.skills[type]);}
&& x_chance_in_y(90 - 3 * mon->ac, 100)){num_levels = 2;}else if (random2(dmg) - random2(mon->ac) > 0)num_levels = 1;int num_success = 0;if (YOU_KILL(thrower)){const int skill_level = _name_to_skill_level(name);if (x_chance_in_y(skill_level + 25, 50))num_success++;if (x_chance_in_y(skill_level, 50))num_success++;}elsenum_success = 1;if (num_success){if (num_success == 2)num_levels++;poison_monster(mon, whose_kill(), num_levels);}}else if (item->special == SPMSL_CURARE){if (ench_power == AUTOMATIC_HIT
return (BEAM_STOP);if (is_enchantment())return (flavour == BEAM_DIGGING ? 0 : BEAM_STOP);
used = BEAM_STOP;else if (is_enchantment())used = (flavour == BEAM_DIGGING ? 0 : BEAM_STOP);
if (flavour == BEAM_ACID)return (BEAM_STOP);
else if (flavour == BEAM_ACID)used = BEAM_STOP;// Lava doesn't go far, but it goes through most stuff.else if (flavour == BEAM_LAVA)used = 1;// Lightning goes through things.else if (flavour == BEAM_ELECTRICITY)used = 0;elseused = 2;
// Lava doesn't go far, but it goes through most stuff.if (flavour == BEAM_LAVA)return (1);
if (in_explosion_phase)return (used);
// tmp needed so that what c_str() points to doesn't go out of scope// before the function ends.std::string tmp;if (item != NULL){tmp = "The " + item->name(DESC_PLAIN, false, false, false)+ " explodes!";seeMsg = tmp.c_str();hearMsg = "You hear an explosion.";type = dchar_glyph(DCHAR_FIRED_BURST);}
effect_known(true), draw_delay(15), obvious_effect(false),seen(false), path_taken(), range_used(0), is_tracer(false),aimed_at_feet(false), msg_generated(false),
effect_known(true), draw_delay(15), special_explosion(NULL),range_funcs(), damage_funcs(), hit_funcs(),obvious_effect(false), seen(false), path_taken(), range_used(0),is_tracer(false), aimed_at_feet(false), msg_generated(false),