diff options
author | zelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573> | 2009-01-14 12:00:48 +0000 |
---|---|---|
committer | zelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573> | 2009-01-14 12:00:48 +0000 |
commit | 85e11d2d3c892c2ffcd53b0bf55c0e83ce13fb9d (patch) | |
tree | c3a0a555a4e2e046ac138f75f1c3bfd76c4357f9 /crawl-ref/source/item_use.cc | |
parent | b83cbbcaed12c8df8422b0fda6465189757ce1c9 (diff) | |
download | crawl-ref-85e11d2d3c892c2ffcd53b0bf55c0e83ce13fb9d.tar.gz crawl-ref-85e11d2d3c892c2ffcd53b0bf55c0e83ce13fb9d.zip |
Implented some ranged brands from FR #2006917 and #1891231: shadow and
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
Diffstat (limited to 'crawl-ref/source/item_use.cc')
-rw-r--r-- | crawl-ref/source/item_use.cc | 653 |
1 files changed, 499 insertions, 154 deletions
diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc index 94a0c150b9..ee73745107 100644 --- a/crawl-ref/source/item_use.cc +++ b/crawl-ref/source/item_use.cc @@ -62,6 +62,7 @@ REVISION("$Rev$"); #include "stuff.h" #include "tiles.h" #include "transfor.h" +#include "traps.h" #include "tutorial.h" #include "view.h" #include "xom.h" @@ -1669,6 +1670,461 @@ bool elemental_missile_beam(int launcher_brand, int ammo_brand) return (element != 0); } +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++; + } + else + num_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); + } + else + shifter = 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); +} + +static bool _dispersal_hit_victim(bolt& beam, actor* victim, int dmg, + int corpse) +{ + const actor* agent = beam.agent(); + + 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); +} + // XXX This is a bit too generous, as it lets the player determine // that the bolt of fire he just shot from a flaming bow is actually // a poison arrow. Hopefully this isn't too abusable. @@ -1682,6 +2138,10 @@ static bool determines_ammo_brand(int bow_brand, int ammo_brand) return (false); if (bow_brand == SPWPN_CHAOS && ammo_brand == SPMSL_CHAOS) return (false); + if (bow_brand == SPWPN_PENETRATION && ammo_brand == SPMSL_PENETRATION) + return (false); + if (bow_brand == SPWPN_SHADOW && ammo_brand == SPMSL_SHADOW) + return (false); return (true); } @@ -1798,9 +2258,18 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus, pbolt.set_target(thr); item_def& thrown = you.inv[throw_2]; + ASSERT(is_valid_item(thrown)); + + // Making a copy of the item: changed only for venom launchers. + item_def item = thrown; + item.quantity = 1; + item.slot = index_to_letter(item.link); + + std::string ammo_name; + setup_missile_beam(&you, pbolt, item, ammo_name, returning); // Did we know the ammo's brand before throwing it? - const bool ammon_brand_known = item_type_known(thrown); + const bool ammo_brand_known = item_type_known(thrown); // Get the ammo/weapon type. Convenience. const object_class_type wepClass = thrown.base_type; @@ -1809,18 +2278,6 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus, // Figure out if we're thrown or launched. const launch_retval projected = is_launched(&you, you.weapon(), thrown); - // 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(); - // Determine range. int max_range = 0; int range = 0; @@ -1855,15 +2312,8 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus, range = std::min(range, LOS_RADIUS); max_range = std::min(max_range, LOS_RADIUS); - pbolt.is_beam = false; - pbolt.beam_source = 0; - pbolt.can_see_invis = player_see_invis(); - pbolt.smart_monster = true; - pbolt.attitude = ATT_FRIENDLY; - pbolt.is_tracer = true; - // For the tracer, use max_range. For the actual shot, use range. - pbolt.range = max_range; + pbolt.range = max_range; // Don't do the tracing when using Portaled Projectile, or when confused. if (!teleport && !you.confused()) @@ -1872,6 +2322,7 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus, pbolt.foe_info.reset(); pbolt.friend_info.reset(); pbolt.foe_ratio = 100; + pbolt.is_tracer = true; pbolt.fire(); @@ -1881,9 +2332,12 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus, { canned_msg(MSG_OK); you.turn_is_over = false; + if (pbolt.special_explosion != NULL) + delete pbolt.special_explosion; return (false); } } + pbolt.is_tracer = false; // Use real range for firing. pbolt.range = range; @@ -1896,16 +2350,8 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus, canned_msg(MSG_EMPTY_HANDED); } - // Making a copy of the item: changed only for venom launchers. - item_def item = thrown; - item.quantity = 1; - item.slot = index_to_letter(item.link); - - pbolt.item = &item; - // Now start real firing! origin_set_unknown(item); - std::string ammo_name; if (is_blood_potion(item) && thrown.quantity > 1) { @@ -1927,26 +2373,6 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus, if (!teleport) pbolt.set_target(thr); - 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); - // Get the launcher class, type. Convenience. if (!you.weapon()) lnchType = NUM_WEAPONS; @@ -1972,7 +2398,6 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus, bow_brand = get_weapon_brand(*you.weapon()); const int ammo_brand = get_ammo_brand( item ); - bool poisoned = (ammo_brand == SPMSL_POISONED); // CALCULATIONS FOR LAUNCHED WEAPONS if (projected == LRET_LAUNCHED) @@ -2196,14 +2621,8 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus, dice_mult = dice_mult * 130 / 100; } - // 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; // ID check. Can't ID off teleported projectiles, uh, because // it's too weird. Also it messes up the messages. @@ -2236,8 +2655,7 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus, // CALCULATIONS FOR THROWN WEAPONS if (projected == LRET_THROWN) { - returning = (!teleport && (get_weapon_brand(item) == SPWPN_RETURNING - || get_ammo_brand(item) == SPMSL_RETURNING)); + returning = returning && !teleport; if (returning && !one_chance_in(1 + skill_bump(SK_THROWING))) did_return = true; @@ -2399,73 +2817,10 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus, } } - // 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) - { - // [dshaligram] Branded arrows are much stronger. - dice_mult = (dice_mult * 150) / 100; - - 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) - { + if (pbolt.flavour != BEAM_MISSILE) // [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(); - } - // Dexterity bonus, and possible skill increase for silly throwing. if (projected) { @@ -2540,34 +2895,6 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus, pbolt.hit, pbolt.damage.num, pbolt.damage.size ); #endif - // 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); - // Create message. mprf( "%s %s%s %s.", teleport ? "Magically, you" : "You", @@ -2610,7 +2937,13 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus, if (bow_brand == SPWPN_CHAOS || ammo_brand == SPMSL_CHAOS) { did_god_conduct(DID_CHAOS, 2 + random2(3), - bow_brand == SPWPN_CHAOS || ammon_brand_known); + bow_brand == SPWPN_CHAOS || ammo_brand_known); + } + + if (ammo_brand == SPMSL_SHADOW || bow_brand == SPWPN_SHADOW) + { + did_god_conduct(DID_NECROMANCY, 2, + bow_brand == SPWPN_SHADOW || ammo_brand_known); } if (did_return) @@ -2655,6 +2988,9 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus, you.turn_is_over = true; + if (pbolt.special_explosion != NULL) + delete pbolt.special_explosion; + return (hit); } @@ -2665,14 +3001,21 @@ bool thrown_object_destroyed(item_def *item, const coord_def& where, int chance = 0; + std::string name = item->name(DESC_PLAIN, false, true, false); + + // Exploding missiles are always destroyed. + if (name.find("explod") != std::string::npos) + return (true); + if (item->base_type == OBJ_MISSILES) { + int brand = get_ammo_brand(*item); // [dshaligram] Removed influence of Throwing on ammo preservation. // The effect is nigh impossible to perceive. switch (item->sub_type) { case MI_NEEDLE: - chance = (get_ammo_brand(*item) == SPMSL_CURARE ? 3 : 6); + chance = (brand == SPMSL_CURARE ? 3 : 6); break; case MI_SLING_BULLET: case MI_STONE: chance = 4; break; @@ -2687,6 +3030,8 @@ bool thrown_object_destroyed(item_def *item, const coord_def& where, chance = 25; break; } + if (brand == SPMSL_STEEL) + chance *= 10; } // Enchanted projectiles get an extra shot at avoiding |