From 1c7e145a0a082b50c22ce53b6db7fccfc6ad9e31 Mon Sep 17 00:00:00 2001 From: haranp Date: Thu, 9 Oct 2008 13:59:30 +0000 Subject: Rewrite of beam.cc: put all beam data in one place. Might be buggy. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7201 c06c8d41-db1a-0410-9941-cceddc491573 --- crawl-ref/source/beam.cc | 2073 +++++++++++++++++++++------------------------- 1 file changed, 953 insertions(+), 1120 deletions(-) (limited to 'crawl-ref/source/beam.cc') diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc index 0e2cbb4136..dfb88d11f7 100644 --- a/crawl-ref/source/beam.cc +++ b/crawl-ref/source/beam.cc @@ -219,11 +219,6 @@ bool zapping(zap_type ztype, int power, bolt &pbolt, bool needs_tracer, mprf(MSGCH_DIAGNOSTICS, "zapping: power=%d", power ); #endif - // GDL: note that rangeMax is set to 0, which means that max range is - // equal to range. This is OK, since rangeMax really only matters for - // stuff monsters throw/zap. - - // 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. @@ -244,11 +239,9 @@ bool zapping(zap_type ztype, int power, bolt &pbolt, bool needs_tracer, mpr(msg.c_str()); if (ztype == ZAP_LIGHTNING) - { - // XXX: Needs to check silenced at other location, too. {dlb} noisy(25, you.pos(), "You hear a mighty clap of thunder!"); - } - else if (ztype == ZAP_DIGGING) + + if (ztype == ZAP_DIGGING) pbolt.aimed_at_spot = false; fire_beam(pbolt); @@ -256,310 +249,6 @@ bool zapping(zap_type ztype, int power, bolt &pbolt, bool needs_tracer, return (true); } -// 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.flavour = BEAM_FRAG; - break; - - case ZAP_SANDBLAST: - pbolt.flavour = BEAM_FRAG; - break; - - case ZAP_FLAME_TONGUE: - if (power > 25) - power = 25; - - pbolt.flavour = BEAM_FIRE; - break; - - case ZAP_CLEANSING_FLAME: - pbolt.name = "golden flame"; - pbolt.flavour = BEAM_HOLY; - pbolt.is_explosion = true; - break; - - case ZAP_MAGMA: - pbolt.flavour = BEAM_LAVA; - pbolt.is_beam = true; - break; - - case ZAP_IRON_BOLT: - pbolt.flavour = BEAM_MMISSILE; // unresistable - break; - - case ZAP_CRYSTAL_SPEAR: - pbolt.flavour = BEAM_MMISSILE; // unresistable - break; - - case ZAP_SPIT_POISON: - if (power > 50) - power = 50; - - pbolt.flavour = BEAM_POISON; - break; - - case ZAP_BREATHE_FIRE: - if (power > 50) - power = 50; - - pbolt.flavour = BEAM_FIRE; - pbolt.is_beam = true; - break; - - case ZAP_BREATHE_FROST: - if (power > 50) - power = 50; - - pbolt.flavour = BEAM_COLD; - pbolt.is_beam = true; - break; - - case ZAP_BREATHE_ACID: - if (power > 50) - power = 50; - - pbolt.flavour = BEAM_ACID; - pbolt.is_beam = true; - break; - - case ZAP_BREATHE_POISON: // leaves clouds of gas - if (power > 50) - power = 50; - - pbolt.flavour = BEAM_POISON; - pbolt.is_beam = true; - break; - - case ZAP_BREATHE_POWER: - if (power > 50) - power = 50; - - pbolt.flavour = BEAM_MMISSILE; // unresistable - pbolt.is_beam = true; - break; - - case ZAP_BREATHE_STEAM: - 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.flavour = BEAM_MMISSILE; // unresistable - break; - - case ZAP_STING: - case ZAP_POISON_ARROW: - pbolt.flavour = BEAM_POISON; - break; - - case ZAP_FLAME: - case ZAP_STICKY_FLAME: - pbolt.flavour = BEAM_FIRE; - break; - - case ZAP_FROST: - pbolt.flavour = BEAM_COLD; - break; - - case ZAP_ICE_BOLT: - pbolt.flavour = BEAM_ICE; // half resistable - break; - - case ZAP_ELECTRICITY: - pbolt.flavour = BEAM_ELECTRICITY; // beams & reflects - pbolt.is_beam = true; - break; - - case ZAP_DISRUPTION: - case ZAP_DISINTEGRATION: - pbolt.name = "0"; - pbolt.flavour = BEAM_DISINTEGRATION; - break; - - case ZAP_PAIN: - pbolt.name = "0"; - pbolt.flavour = BEAM_PAIN; - break; - - case ZAP_DISPEL_UNDEAD: - pbolt.name = "0"; - pbolt.flavour = BEAM_DISPEL_UNDEAD; - break; - - case ZAP_FIRE: - pbolt.flavour = BEAM_FIRE; - pbolt.is_beam = true; - break; - - case ZAP_BONE_SHARDS: - pbolt.flavour = BEAM_MAGIC; // unresisted - pbolt.is_beam = true; - break; - - case ZAP_COLD: - pbolt.flavour = BEAM_COLD; - pbolt.is_beam = true; - break; - - case ZAP_NEGATIVE_ENERGY: - pbolt.flavour = BEAM_NEG; // drains levels - pbolt.is_beam = true; - break; - - case ZAP_BEAM_OF_ENERGY: // bolt of innacuracy - pbolt.flavour = BEAM_ENERGY; // unresisted - pbolt.is_beam = true; - break; - - case ZAP_VENOM_BOLT: - pbolt.flavour = BEAM_POISON; - pbolt.is_beam = true; - break; - - case ZAP_LIGHTNING: - pbolt.flavour = BEAM_ELECTRICITY; // beams & reflects - pbolt.is_beam = true; - break; - - // enchantments - case ZAP_ENSLAVEMENT: - pbolt.name = "0"; - pbolt.flavour = BEAM_CHARM; - break; - - case ZAP_BANISHMENT: - pbolt.name = "0"; - pbolt.flavour = BEAM_BANISH; - break; - - case ZAP_DEGENERATION: - pbolt.name = "0"; - pbolt.flavour = BEAM_DEGENERATE; - break; - - case ZAP_ENSLAVE_UNDEAD: - pbolt.name = "0"; - pbolt.flavour = BEAM_ENSLAVE_UNDEAD; - break; - - case ZAP_CONTROL_DEMON: - pbolt.name = "0"; - pbolt.flavour = BEAM_ENSLAVE_DEMON; - break; - - case ZAP_SLEEP: - pbolt.name = "0"; - pbolt.flavour = BEAM_SLEEP; - break; - - case ZAP_BACKLIGHT: - pbolt.name = "0"; - pbolt.flavour = BEAM_BACKLIGHT; - break; - - case ZAP_SLOWING: - pbolt.name = "0"; - pbolt.flavour = BEAM_SLOW; - break; - - case ZAP_HASTING: - pbolt.name = "0"; - pbolt.flavour = BEAM_HASTE; - break; - - case ZAP_PARALYSIS: - pbolt.name = "0"; - pbolt.flavour = BEAM_PARALYSIS; - break; - - case ZAP_PETRIFY: - pbolt.name = "0"; - pbolt.flavour = BEAM_PETRIFY; - break; - - case ZAP_CONFUSION: - pbolt.name = "0"; - pbolt.flavour = BEAM_CONFUSION; - break; - - case ZAP_INVISIBILITY: - pbolt.name = "0"; - pbolt.flavour = BEAM_INVISIBILITY; - break; - - case ZAP_HEALING: - pbolt.name = "0"; - pbolt.flavour = BEAM_HEALING; - break; - - case ZAP_TELEPORTATION: - pbolt.name = "0"; - pbolt.flavour = BEAM_TELEPORT; - break; - - case ZAP_POLYMORPH_OTHER: - pbolt.name = "0"; - pbolt.flavour = BEAM_POLYMORPH; - break; - - case ZAP_AGONY: - pbolt.name = "0agony"; - pbolt.flavour = BEAM_PAIN; - break; - - case ZAP_DIGGING: - pbolt.name = "0"; - pbolt.flavour = BEAM_DIGGING; - pbolt.is_beam = true; - break; - - // explosions - case ZAP_FIREBALL: - pbolt.name = "fireball"; - pbolt.flavour = BEAM_FIRE; // fire - pbolt.is_explosion = true; - break; - - case ZAP_ICE_STORM: - pbolt.name = "great blast of cold"; - 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.flavour = BEAM_FRAG; // extra AC resist - pbolt.is_explosion = true; - break; - - case ZAP_HELLFIRE: - pbolt.flavour = BEAM_HELLFIRE; - pbolt.is_explosion = true; - break; - - case ZAP_ORB_OF_ELECTRICITY: // cap 150 - pbolt.name = "orb of electricity"; - pbolt.flavour = BEAM_ELECTRICITY; - pbolt.is_explosion = true; - break; - - case ZAP_DEBUGGING_RAY: - default: // buggy beam - pbolt.flavour = BEAM_MMISSILE; // unresistable - break; - } -} - // Returns true if the path is considered "safe", and false if there are // monsters in the way the player doesn't want to hit. // NOTE: Doesn't check for the player being hit by a rebounding lightning bolt. @@ -572,7 +261,6 @@ 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); pbolt.is_tracer = true; pbolt.source = you.pos(); @@ -633,856 +321,1030 @@ dice_def calc_dice( int num_dice, int max_damage ) return (ret); } -// Need to see zapping() for default values not set within this function {dlb} -static void _zappy( zap_type z_type, int power, bolt &pbolt ) +template +struct power_deducer { - int temp_rand = 0; // probability determination {dlb} - - // Note: The incoming power is not linear in the case of spellcasting. - // The power curve currently allows for the character to reasonably - // get up to a power level of about a 100, but more than that will - // be very hard (and the maximum is 200). The low level power caps - // provide the useful feature in that they allow for low level spells - // to have quick advancement, but don't cause them to obsolete the - // higher level spells. -- bwr - // - // I've added some example characters below to show how little - // people should be concerned about the power caps. - // - // The example characters are simplified to three stats: - // - // - Intelligence: This magnifies power, it's very useful. - // - // - Skills: This represents the character having Spellcasting - // and the average of the component skills at this level. - // Although, Spellcasting probably isn't quite as high as - // other spell skills for a lot of characters, note that it - // contributes much less to the total power (about 20%). - // - // - Enhancers: These are equipment that the player can use to - // apply additional magnifiers (x1.5) to power. There are - // also inhibitors that reduce power (/2.0), but we're not - // concerned about those here. Anyways, the character can - // currently have up to 3 levels (for x1.5, x2.25, x3.375). - // The lists below should help to point out the difficulty - // and cost of getting more than one level of enhancement. - // - // Here's a list of current magnifiers: - // - // - rings of fire/cold - // - staff of fire/cold/air/earth/poison/death/conjure/enchant/summon - // - staff of Olgreb (poison) - // - robe of the Archmagi (necro, conjure, enchant, summon) - // - Mummy intrinsic (+1 necromancy at level 13, +2 at level 26) - // - Necromutation (+1 to necromancy -- note: undead can't use this) - // - Ring of Fire (+1 to fire) - // - // The maximum enhancement, by school (but capped at 3): - // - // - Necromancy: 4 (Mummies), 3 (others) - // - Fire: 4 - // - Cold: 3 - // - Conjuration: 2 - // - Enchantment: 2 - // - Summoning: 2 - // - Air: 1 - // - Earth: 1 - // - Poison: 1 - // - Translocations, Transmigrations, Divinations intentionally 0 - - switch (z_type) - { - // level 1 - // - // This cap is to keep these easy and very cheap spells from - // becoming too powerful. - // - // Example characters with about 25 power: - // - // - int 5, skills 20, 0 enhancers - // - int 5, skills 14, 1 enhancer - // - int 10, skills 10, 0 enhancers - // - int 10, skills 7, 1 enhancers - // - int 15, skills 7, 0 enhancers - // - int 20, skills 6, 0 enhancers - case ZAP_STRIKING: - case ZAP_MAGIC_DARTS: - case ZAP_STING: - case ZAP_ELECTRICITY: - case ZAP_FLAME_TONGUE: - case ZAP_SMALL_SANDBLAST: - case ZAP_DISRUPTION: // ench_power boosted below - case ZAP_PAIN: // ench_power boosted below - if (power > 25) - power = 25; - break; - - // level 2/3 - // - // The following examples should make it clear that in the - // early game this cap is only limiting to serious spellcasters - // (they could easily reach the 20-10-0 example). - // - // Example characters with about 50 power: - // - // - int 10, skills 20, 0 enhancers - // - int 10, skills 14, 1 enhancer - // - int 15, skills 14, 0 enhancers - // - int 15, skills 10, 1 enhancer - // - int 20, skills 10, 0 enhancers - // - int 20, skills 7, 1 enhancer - // - int 25, skills 8, 0 enhancers - case ZAP_SANDBLAST: - case ZAP_FLAME: // also ability (pow = lev * 2) - case ZAP_FROST: // also ability (pow = lev * 2) - case ZAP_STONE_ARROW: - if (power > 50) - power = 50; - break; - - // Here are some examples that show that its fairly safe to assume - // that a high level character can easily have 75 power. - // - // Example characters with about 75 power: - // - // - int 10, skills 27, 1 enhancer - // - int 15, skills 27, 0 enhancers - // - int 15, skills 16, 1 enhancer - // - int 20, skills 20, 0 enhancers - // - int 20, skills 14, 1 enhancer - // - int 25, skills 16, 0 enhancers - - // level 4 - // - // The following examples should make it clear that this is the - // effective maximum power. Its not easy to get to 100 power, - // but 20-20-1 or 25-16-1 is certainly attainable by a high level - // spellcaster. As you can see from the examples at 150 and 200, - // getting much power beyond this is very difficult. - // - // Level 3 and 4 spells cannot be overpowered. - // - // Example characters with about 100 power: - // - // - int 10, skills 27, 2 enhancers - // - int 15, skills 27, 1 enhancer - // - int 20, skills 20, 1 enhancer - // - int 25, skills 24, 0 enhancers - // - int 25, skills 16, 1 enhancer - case ZAP_MYSTIC_BLAST: - case ZAP_STICKY_FLAME: - case ZAP_ICE_BOLT: - case ZAP_DISPEL_UNDEAD: // ench_power raised below - if (power > 100) - power = 100; - break; - - // levels 5-7 - // - // These spells used to be capped, but its very hard to raise - // power over 100, and these examples should show that. - // Only the twinkiest of characters are expected to get to 150. - // - // Example characters with about 150 power: - // - // - int 15, skills 27, 3 enhancers (actually, only 146) - // - int 20, skills 27, 2 enhancers (actually, only 137) - // - int 20, skills 21, 3 enhancers - // - int 25, skills 26, 2 enhancers - // - int 30, skills 21, 2 enhancers - // - int 40, skills 24, 1 enhancer - // - int 70, skills 20, 0 enhancers - case ZAP_FIRE: - case ZAP_COLD: - case ZAP_VENOM_BOLT: - case ZAP_MAGMA: - case ZAP_AGONY: - case ZAP_LIGHTNING: // also invoc * 6 or lev * 2 (abils) - case ZAP_NEGATIVE_ENERGY: // also ability (pow = lev * 6) - case ZAP_IRON_BOLT: - case ZAP_DISINTEGRATION: - case ZAP_FIREBALL: - case ZAP_ORB_OF_ELECTRICITY: - case ZAP_ORB_OF_FRAGMENTATION: - case ZAP_POISON_ARROW: - // if (power > 150) - // power = 150; - break; + virtual T operator()(int pow) const = 0; +}; - // levels 8-9 - // - // These spells are capped at 200 (which is the cap in calc_spell_power). - // As an example of how little of a cap that is, consider the fact - // that a 70-27-3 character has an uncapped power of 251. Characters - // are never expected to get to this cap. - // - // Example characters with about 200 power: - // - // - int 30, skills 27, 3 enhancers (actually, only 190) - // - int 40, skills 27, 2 enhancers (actually, only 181) - // - int 40, skills 23, 3 enhancers - // - int 70, skills 27, 0 enhancers (actually, only 164) - // - int 70, skills 27, 1 enhancers (actually, only 194) - // - int 70, skills 20, 2 enhancers - // - int 70, skills 13, 3 enhancers - case ZAP_CRYSTAL_SPEAR: - case ZAP_HELLFIRE: - case ZAP_ICE_STORM: - case ZAP_CLEANSING_FLAME: - // if (power > 200) - // power = 200; - break; +typedef power_deducer tohit_deducer; - // unlimited power (needs a good reason) - case ZAP_BONE_SHARDS: // incoming power is modified for mass - case ZAP_BEAM_OF_ENERGY: // inaccuracy (only on staff, hardly hits) - break; +template +struct tohit_calculator : public tohit_deducer +{ + int operator()(int pow) const + { + return adder + (pow * mult_num) / mult_denom; + } +}; - // natural/mutant breath/spit powers (power ~= characer level) - case ZAP_SPIT_POISON: // lev + mut * 5 - case ZAP_BREATHE_FIRE: // lev + mut * 4 + 12 (if dragonform) - case ZAP_BREATHE_FROST: // lev - case ZAP_BREATHE_ACID: // lev (or invoc * 3 from minor destr) - case ZAP_BREATHE_POISON: // lev - case ZAP_BREATHE_POWER: // lev - case ZAP_BREATHE_STEAM: // lev - if (power > 50) - power = 50; - break; +typedef power_deducer dam_deducer; - // enchantments and other resistable effects - case ZAP_SLOWING: - case ZAP_HASTING: - case ZAP_PARALYSIS: - case ZAP_PETRIFY: - case ZAP_BACKLIGHT: - case ZAP_SLEEP: - case ZAP_CONFUSION: - case ZAP_INVISIBILITY: - case ZAP_ENSLAVEMENT: - case ZAP_TELEPORTATION: - case ZAP_DIGGING: - case ZAP_POLYMORPH_OTHER: - case ZAP_DEGENERATION: - case ZAP_BANISHMENT: - // This is the only power that matters. We magnify it apparently - // to get values that work better with magic resistance checks... - // those checks will scale down this value and max it out at 120. - pbolt.ench_power *= 3; - pbolt.ench_power /= 2; - break; +template +struct dicedef_calculator : public dam_deducer +{ + dice_def operator()(int pow) const + { + return dice_def(numdice, adder + (pow * mult_num) / mult_denom); + } +}; - // anything else we cap to 100 - default: - if (power > 100) - power = 100; - break; +template +struct calcdice_calculator : public dam_deducer +{ + dice_def operator()(int pow) const + { + return calc_dice(numdice, adder + (pow * mult_num) / mult_denom); } +}; - // Note: I'm only displaying the top damage and such here, that's - // because it's really not been known before (since the above caps - // didn't exist), so they were all pretty much unlimited before. - // Also note, that the high end damage occurs at the cap, only - // players that are that powerful can get that damage... and - // although these numbers might seem small, you should remember - // that Dragons in this game are 60-90 hp monsters, and very - // few monsters have more than 100 hp (and that 1d5 damage is - // still capable of taking a good sized chunk (and possibly killing) - // any monster you're likely to meet in the first three levels). -- bwr - - // Note: damage > 100 signals that "random2(damage - 100)" will be - // applied three times, which not only ups the damage but gives - // a more normal distribution. - switch (z_type) - { - case ZAP_STRIKING: // cap 25 - pbolt.name = "force bolt"; - pbolt.colour = BLACK; - pbolt.damage = dice_def( 1, 5 ); // dam: 5 - pbolt.hit = 8 + power / 10; // 25: 10 - pbolt.type = dchar_glyph(DCHAR_SPACE); - pbolt.flavour = BEAM_MMISSILE; // unresistable - pbolt.obvious_effect = true; - break; +struct zap_info +{ + zap_type ztype; + const char* name; // NULL means handled specially + int power_cap; + dam_deducer* damage; + tohit_deducer* tohit; // Enchantments have power modifier here + int colour; + bool is_enchantment; + beam_type flavour; + dungeon_char_type glyph; + bool always_obvious; + bool can_beam; + bool is_explosion; +}; + +const zap_info zap_data[] = { - case ZAP_MAGIC_DARTS: // cap 25 - pbolt.name = "magic dart"; - pbolt.colour = LIGHTMAGENTA; - pbolt.damage = dice_def( 1, 3 + power / 5 ); // 25: 1d8 - pbolt.hit = AUTOMATIC_HIT; // hits always - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_MMISSILE; // unresistable - pbolt.obvious_effect = true; - break; + { + ZAP_FLAME, + "puff of flame", + 50, + new dicedef_calculator<2, 4, 1, 10>, + new tohit_calculator<8, 1, 10>, + RED, + false, + BEAM_FIRE, + DCHAR_FIRED_ZAP, + true, + false, + false + }, - case ZAP_STING: // cap 25 - pbolt.name = "sting"; - pbolt.colour = GREEN; - pbolt.damage = dice_def( 1, 3 + power / 5 ); // 25: 1d8 - pbolt.hit = 8 + power / 5; // 25: 13 - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_POISON; // extra damage - pbolt.obvious_effect = true; - break; + { + ZAP_FROST, + "puff of frost", + 50, + new dicedef_calculator<2, 4, 1, 10>, + new tohit_calculator<8, 1, 10>, + WHITE, + false, + BEAM_COLD, + DCHAR_FIRED_ZAP, + true, + false, + false + }, - case ZAP_ELECTRICITY: // cap 20 - pbolt.name = "zap"; - pbolt.colour = LIGHTCYAN; - pbolt.damage = dice_def( 1, 3 + random2(power) / 2 );// 25: 1d11 - pbolt.hit = 8 + power / 7; // 25: 11 - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_ELECTRICITY; // beams & reflects - pbolt.obvious_effect = true; - pbolt.is_beam = true; - break; + { + ZAP_SLOWING, + "0", + 100, + NULL, + NULL, + BLACK, + true, + BEAM_SLOW, + DCHAR_SPACE, + false, + false, + false + }, - case ZAP_DISRUPTION: // cap 25 - pbolt.name = "0"; - pbolt.flavour = BEAM_DISINTEGRATION; - pbolt.damage = dice_def( 1, 4 + power / 5 ); // 25: 1d9 - pbolt.ench_power *= 3; - break; + { + ZAP_HASTING, + "0", + 100, + NULL, + NULL, + BLACK, + true, + BEAM_HASTE, + DCHAR_SPACE, + false, + false, + false + }, - case ZAP_PAIN: // cap 25 - pbolt.name = "0"; - pbolt.flavour = BEAM_PAIN; - pbolt.damage = dice_def( 1, 4 + power / 5 ); // 25: 1d9 - pbolt.ench_power *= 7; - pbolt.ench_power /= 2; - break; + { + ZAP_MAGIC_DARTS, + "magic dart", + 25, + new dicedef_calculator<1, 3, 1, 5>, + new tohit_calculator, + LIGHTMAGENTA, + false, + BEAM_MMISSILE, + DCHAR_FIRED_ZAP, + true, + false, + false + }, + + { + ZAP_HEALING, + "0", + 100, + new dicedef_calculator<1, 7, 1, 3>, + NULL, + BLACK, + true, + BEAM_HEALING, + DCHAR_SPACE, + false, + false, + false + }, - case ZAP_FLAME_TONGUE: // cap 25 - pbolt.name = "flame"; - pbolt.colour = RED; - pbolt.damage = dice_def( 1, 8 + power / 4 ); // 25: 1d14 - pbolt.hit = 7 + power / 6; // 25: 11 - pbolt.type = dchar_glyph(DCHAR_FIRED_BOLT); - pbolt.flavour = BEAM_FIRE; - pbolt.obvious_effect = true; - break; + { + ZAP_PARALYSIS, + "0", + 100, + NULL, + NULL, + BLACK, + true, + BEAM_PARALYSIS, + DCHAR_SPACE, + false, + false, + false + }, - case ZAP_SMALL_SANDBLAST: // cap 25 - pbolt.name = "blast of "; + { + ZAP_FIRE, + "bolt of fire", + 200, + new calcdice_calculator<6, 18, 2, 3>, + new tohit_calculator<10, 1, 25>, + RED, + false, + BEAM_FIRE, + DCHAR_FIRED_ZAP, + true, + true, + false + }, + + { + ZAP_COLD, + "bolt of cold", + 200, + new calcdice_calculator<6, 18, 2, 3>, + new tohit_calculator<10, 1, 25>, + WHITE, + false, + BEAM_COLD, + DCHAR_FIRED_ZAP, + true, + true, + false + }, + + { + ZAP_CONFUSION, + "0", + 100, + NULL, + NULL, + BLACK, + true, + BEAM_CONFUSION, + DCHAR_SPACE, + false, + false, + false + }, - temp_rand = random2(4); - pbolt.name += (temp_rand == 0) ? "dust" : - (temp_rand == 1) ? "dirt" : - (temp_rand == 2) ? "grit" : "sand"; + { + ZAP_INVISIBILITY, + "0", + 100, + NULL, + NULL, + BLACK, + true, + BEAM_INVISIBILITY, + DCHAR_SPACE, + false, + false, + false + }, - pbolt.colour = BROWN; - pbolt.damage = dice_def( 1, 8 + power / 4 ); // 25: 1d14 - pbolt.hit = 8 + power / 5; // 25: 13 - pbolt.type = dchar_glyph(DCHAR_FIRED_BOLT); - pbolt.flavour = BEAM_FRAG; // extra AC resist - pbolt.obvious_effect = true; - break; + { + ZAP_DIGGING, + "0", + 100, + NULL, + NULL, + BLACK, + true, + BEAM_DIGGING, + DCHAR_SPACE, + false, + true, + false + }, - case ZAP_SANDBLAST: // cap 50 - pbolt.name = coinflip() ? "blast of rock" : "rocky blast"; - pbolt.colour = BROWN; - pbolt.damage = dice_def( 2, 4 + power / 3 ); // 25: 2d12 - pbolt.hit = 13 + power / 10; // 25: 15 - pbolt.type = dchar_glyph(DCHAR_FIRED_BOLT); - pbolt.flavour = BEAM_FRAG; // extra AC resist - pbolt.obvious_effect = true; - break; + { + ZAP_FIREBALL, + "fireball", + 200, + new calcdice_calculator<3, 10, 1, 2>, + new tohit_calculator<40>, + RED, + false, + BEAM_FIRE, + DCHAR_FIRED_ZAP, + false, + false, + true + }, - case ZAP_BONE_SHARDS: - pbolt.name = "spray of bone shards"; - pbolt.colour = LIGHTGREY; + { + ZAP_TELEPORTATION, + "0", + 100, + NULL, + NULL, + BLACK, + true, + BEAM_TELEPORT, + DCHAR_SPACE, + false, + false, + false + }, - // Incoming power is highly dependant on mass (see spells3.cc). - // Basic function is power * 15 + mass... with the largest - // available mass (3000) we get a power of 4500 at a power - // level of 100 (for 3d20). - pbolt.damage = dice_def( 3, 2 + (power / 250) ); - pbolt.hit = 8 + (power / 100); // max hit: 53 - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_MAGIC; // unresisted - pbolt.obvious_effect = true; - pbolt.is_beam = true; - break; + { + ZAP_LIGHTNING, + "bolt of lightning", + 200, + new calcdice_calculator<1, 10, 3, 5>, + new tohit_calculator<7, 1, 40>, + LIGHTCYAN, + false, + BEAM_ELECTRICITY, + DCHAR_FIRED_ZAP, + true, + true, + false + }, - case ZAP_FLAME: // cap 50 - pbolt.name = "puff of flame"; - pbolt.colour = RED; - pbolt.damage = dice_def( 2, 4 + power / 10 );// 25: 2d6 50: 2d9 - pbolt.hit = 8 + power / 10; // 25: 10 50: 13 - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_FIRE; - pbolt.obvious_effect = true; - break; + { + ZAP_POLYMORPH_OTHER, + "0", + 100, + NULL, + NULL, + BLACK, + true, + BEAM_POLYMORPH, + DCHAR_SPACE, + false, + false, + false + }, - case ZAP_FROST: // cap 50 - pbolt.name = "puff of frost"; - pbolt.colour = WHITE; - pbolt.damage = dice_def( 2, 4 + power / 10 );// 25: 2d6 50: 2d9 - pbolt.hit = 8 + power / 10; // 25: 10 50: 13 - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_COLD; - pbolt.obvious_effect = true; - break; + { + ZAP_VENOM_BOLT, + "bolt of poison", + 200, + new calcdice_calculator<4, 15, 1, 2>, + new tohit_calculator<8, 1, 20>, + LIGHTGREEN, + false, + BEAM_POISON, + DCHAR_FIRED_ZAP, + true, + true, + false + }, + + { + ZAP_NEGATIVE_ENERGY, + "bolt of negative energy", + 200, + new calcdice_calculator<4, 15, 3, 5>, + new tohit_calculator<8, 1, 20>, + DARKGREY, + false, + BEAM_NEG, + DCHAR_FIRED_ZAP, + true, + true, + false + }, - case ZAP_STONE_ARROW: // cap 100 - pbolt.name = "stone arrow"; - pbolt.colour = LIGHTGREY; - pbolt.damage = dice_def( 2, 5 + power / 7 );// 25: 2d8 50: 2d12 - pbolt.hit = 8 + power / 10; // 25: 10 50: 13 - pbolt.type = dchar_glyph(DCHAR_FIRED_MISSILE); - pbolt.flavour = BEAM_MMISSILE; // irresistible - pbolt.obvious_effect = true; - break; + { + ZAP_CRYSTAL_SPEAR, + "crystal spear", + 200, + new calcdice_calculator<10, 23, 1, 1>, + new tohit_calculator<10, 1, 15>, + WHITE, + false, + BEAM_MMISSILE, + DCHAR_FIRED_MISSILE, + true, + false, + false + }, - case ZAP_STICKY_FLAME: // cap 100 - pbolt.name = "sticky flame"; // extra damage - pbolt.colour = RED; - // 50: 2d7 100: 2d11 - pbolt.damage = dice_def( 2, 3 + power / 12 ); - // 50: 16 100: 21 - pbolt.hit = 11 + power / 10; - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_FIRE; - pbolt.obvious_effect = true; - break; + { + ZAP_BEAM_OF_ENERGY, + "narrow beam of energy", + 1000, + new calcdice_calculator<12, 40, 3, 2>, + new tohit_calculator<1>, + YELLOW, + false, + BEAM_ENERGY, + DCHAR_FIRED_ZAP, + true, + true, + false + }, - case ZAP_MYSTIC_BLAST: // cap 100 - pbolt.name = "orb of energy"; - pbolt.colour = LIGHTMAGENTA; - pbolt.damage = calc_dice( 2, 15 + (power * 2) / 5 ); - pbolt.hit = 10 + power / 7; // 50: 17 100: 24 - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_MMISSILE; // unresistable - pbolt.obvious_effect = true; - break; + { + ZAP_MYSTIC_BLAST, + "orb of energy", + 100, + new calcdice_calculator<2, 15, 2, 5>, + new tohit_calculator<10, 1, 7>, + LIGHTMAGENTA, + false, + BEAM_MMISSILE, + DCHAR_FIRED_ZAP, + true, + false, + false + }, - case ZAP_ICE_BOLT: // cap 100 - pbolt.name = "bolt of ice"; - pbolt.colour = WHITE; - pbolt.damage = calc_dice( 3, 10 + power / 2 ); - pbolt.hit = 9 + power / 12; // 50: 13 100: 17 - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_ICE; // half resistable - break; + { + ZAP_ENSLAVEMENT, + "0", + 100, + NULL, + NULL, + BLACK, + true, + BEAM_CHARM, + DCHAR_SPACE, + false, + false, + false + }, - case ZAP_DISPEL_UNDEAD: // cap 100 - pbolt.name = "0"; - pbolt.flavour = BEAM_DISPEL_UNDEAD; - pbolt.damage = calc_dice( 3, 20 + (power * 3) / 4 ); - pbolt.ench_power *= 3; - pbolt.ench_power /= 2; - break; + { + ZAP_PAIN, + "0", + 100, + new dicedef_calculator<1, 4, 1,5>, + new tohit_calculator<0, 7, 2>, + BLACK, + true, + BEAM_PAIN, + DCHAR_SPACE, + false, + false, + false + }, - case ZAP_MAGMA: // cap 150 - pbolt.name = "bolt of magma"; - pbolt.colour = RED; - pbolt.damage = calc_dice( 4, 10 + (power * 3) / 5 ); - pbolt.hit = 8 + power / 25; // 50: 10 100: 14 - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_LAVA; - pbolt.obvious_effect = true; - pbolt.is_beam = true; - break; + { + ZAP_STICKY_FLAME, + "sticky flame", + 100, + new dicedef_calculator<2, 3, 1, 12>, + new tohit_calculator<11, 1, 10>, + RED, + false, + BEAM_FIRE, + DCHAR_FIRED_ZAP, + true, + false, + false + }, - case ZAP_FIRE: // cap 150 - pbolt.name = "bolt of fire"; - pbolt.colour = RED; - pbolt.damage = calc_dice( 6, 18 + power * 2 / 3 ); - pbolt.hit = 10 + power / 25; // 50: 12 100: 14 - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_FIRE; - pbolt.obvious_effect = true; - pbolt.is_beam = true; - break; + { + ZAP_DISPEL_UNDEAD, + "0", + 100, + new calcdice_calculator<3, 20, 3, 4>, + new tohit_calculator<0, 3, 2>, + BLACK, + true, + BEAM_DISPEL_UNDEAD, + DCHAR_SPACE, + false, + false, + false + }, - case ZAP_COLD: // cap 150 - pbolt.name = "bolt of cold"; - pbolt.colour = WHITE; - pbolt.damage = calc_dice( 6, 18 + power * 2 / 3 ); - pbolt.hit = 10 + power / 25; // 50: 12 100: 14 - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_COLD; - pbolt.obvious_effect = true; - pbolt.is_beam = true; - break; - case ZAP_VENOM_BOLT: // cap 150 - pbolt.name = "bolt of poison"; - pbolt.colour = LIGHTGREEN; - pbolt.damage = calc_dice( 4, 15 + power / 2 ); - pbolt.hit = 8 + power / 20; // 50: 10 100: 13 - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_POISON; // extra damage - pbolt.obvious_effect = true; - pbolt.is_beam = true; - break; + { + ZAP_CLEANSING_FLAME, + "golden flame", + 200, + new calcdice_calculator<2, 20, 2, 3>, + new tohit_calculator<150>, + YELLOW, + false, + BEAM_HOLY, + DCHAR_FIRED_ZAP, + true, + true, + false + }, - case ZAP_NEGATIVE_ENERGY: // cap 150 - // These always auto-identify, so no generic name. - pbolt.name = "bolt of negative energy"; - pbolt.colour = DARKGREY; - pbolt.damage = calc_dice( 4, 15 + (power * 3) / 5 ); - pbolt.hit = 8 + power / 20; // 50: 10 100: 13 - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_NEG; // drains levels - pbolt.obvious_effect = true; - pbolt.is_beam = true; - break; - case ZAP_IRON_BOLT: // cap 150 - pbolt.name = "iron bolt"; - pbolt.colour = LIGHTCYAN; - pbolt.damage = calc_dice( 9, 15 + (power * 3) / 4 ); - pbolt.hit = 7 + power / 15; // 50: 10 100: 13 - pbolt.type = dchar_glyph(DCHAR_FIRED_MISSILE); - pbolt.flavour = BEAM_MMISSILE; // unresistable - pbolt.obvious_effect = true; - break; + { + ZAP_BONE_SHARDS, + "spray of bone shards", + // Incoming power is highly dependant on mass (see spells3.cc). + // Basic function is power * 15 + mass... with the largest + // available mass (3000) we get a power of 4500 at a power + // level of 100 (for 3d20). + 10000, + new dicedef_calculator<3, 2, 1, 250>, + new tohit_calculator<8, 1, 100>, + LIGHTGREY, + false, + BEAM_MAGIC, + DCHAR_FIRED_ZAP, + true, + true, + false + }, - case ZAP_POISON_ARROW: // cap 150 - pbolt.name = "poison arrow"; - pbolt.colour = LIGHTGREEN; - pbolt.damage = calc_dice( 4, 15 + power ); - pbolt.hit = 5 + power / 10; // 50: 10 100: 15 - pbolt.type = dchar_glyph(DCHAR_FIRED_MISSILE); - pbolt.flavour = BEAM_POISON_ARROW; // extra damage - pbolt.obvious_effect = true; - break; + { + ZAP_BANISHMENT, + "0", + 100, + NULL, + NULL, + BLACK, + true, + BEAM_BANISH, + DCHAR_SPACE, + false, + false, + false + }, - case ZAP_DISINTEGRATION: // cap 150 - pbolt.name = "0"; - pbolt.flavour = BEAM_DISINTEGRATION; - pbolt.damage = calc_dice( 3, 15 + (power * 3) / 4 ); - pbolt.ench_power *= 5; - pbolt.ench_power /= 2; - pbolt.is_beam = true; - break; + { + ZAP_DEGENERATION, + "0", + 100, + NULL, + NULL, + BLACK, + true, + BEAM_DEGENERATE, + DCHAR_SPACE, + false, + false, + false + }, - case ZAP_LIGHTNING: // cap 150 - // also for breath (at pow = lev * 2; max dam: 33) - pbolt.name = "bolt of lightning"; - pbolt.colour = LIGHTCYAN; - pbolt.damage = calc_dice( 1, 10 + (power * 3) / 5 ); - pbolt.hit = 7 + random2(power) / 20; // 50: 7-9 100: 7-12 - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_ELECTRICITY; // beams & reflects - pbolt.obvious_effect = true; - pbolt.is_beam = true; - break; - case ZAP_FIREBALL: // cap 150 - pbolt.name = "fireball"; - pbolt.colour = RED; - pbolt.damage = calc_dice( 3, 10 + power / 2 ); - pbolt.hit = 40; // hit: 40 - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_FIRE; // fire - pbolt.is_explosion = true; - break; + { + ZAP_STING, + "sting", + 25, + new dicedef_calculator<1, 3, 1, 5>, + new tohit_calculator<8, 1, 5>, + GREEN, + false, + BEAM_POISON, + DCHAR_FIRED_ZAP, + true, + false, + false + }, - case ZAP_ORB_OF_ELECTRICITY: // cap 150 - pbolt.name = "orb of electricity"; - pbolt.colour = LIGHTBLUE; - pbolt.damage = calc_dice( 1, 15 + (power * 4) / 5 ); - pbolt.damage.num = 0; // only does explosion damage - pbolt.hit = 40; // hit: 40 - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_ELECTRICITY; - pbolt.is_explosion = true; - break; - case ZAP_ORB_OF_FRAGMENTATION: // cap 150 - pbolt.name = "metal orb"; - pbolt.colour = CYAN; - pbolt.damage = calc_dice( 3, 30 + (power * 3) / 4 ); - pbolt.hit = 20; // hit: 20 - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_FRAG; // extra AC resist - pbolt.is_explosion = true; - break; + { + ZAP_HELLFIRE, + "hellfire", + 200, + new calcdice_calculator<3, 10, 3, 4>, + new tohit_calculator<20, 1, 10>, + RED, + false, + BEAM_HELLFIRE, + DCHAR_FIRED_ZAP, + true, + false, + true + }, - case ZAP_CLEANSING_FLAME: - pbolt.name = "golden flame"; - pbolt.colour = YELLOW; - pbolt.damage = calc_dice( 2, 20 + (power * 2) / 3 ); - pbolt.hit = 150; - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_HOLY; - pbolt.obvious_effect = true; - pbolt.is_explosion = true; - break; + { + ZAP_IRON_BOLT, + "iron bolt", + 200, + new calcdice_calculator<9, 15, 3, 4>, + new tohit_calculator<7, 1, 15>, + LIGHTCYAN, + false, + BEAM_MMISSILE, + DCHAR_FIRED_MISSILE, + true, + false, + false + }, - case ZAP_CRYSTAL_SPEAR: // cap 200 - pbolt.name = "crystal spear"; - pbolt.colour = WHITE; - pbolt.damage = calc_dice( 10, 23 + power ); - pbolt.hit = 10 + power / 15; // 50: 13 100: 16 - pbolt.type = dchar_glyph(DCHAR_FIRED_MISSILE); - pbolt.flavour = BEAM_MMISSILE; // unresistable - pbolt.obvious_effect = true; - break; + { + ZAP_STRIKING, + "force bolt", + 25, + new dicedef_calculator<1, 5, 0, 1>, + new tohit_calculator<8, 1, 10>, + BLACK, + false, + BEAM_MMISSILE, + DCHAR_SPACE, + true, + false, + false + }, - case ZAP_HELLFIRE: // cap 200 - pbolt.name = "hellfire"; - pbolt.colour = RED; - pbolt.damage = calc_dice( 3, 10 + (power * 3) / 4 ); - pbolt.hit = 20 + power / 10; // 50: 25 100: 30 - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_HELLFIRE; - pbolt.obvious_effect = true; - pbolt.is_explosion = true; - break; + { + ZAP_STONE_ARROW, + "stone arrow", + 50, + new dicedef_calculator<2, 5, 1, 7>, + new tohit_calculator<8, 1, 10>, + LIGHTGREY, + false, + BEAM_MMISSILE, + DCHAR_FIRED_MISSILE, + true, + false, + false + }, - case ZAP_ICE_STORM: // cap 200 - pbolt.name = "great blast of cold"; - pbolt.colour = BLUE; - pbolt.damage = calc_dice( 7, 22 + power ); - pbolt.hit = 20 + power / 10; // 50: 25 100: 30 - pbolt.ench_power = power; // used for radius - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_ICE; // half resisted - pbolt.is_explosion = true; - break; + { + ZAP_ELECTRICITY, + "zap", + 25, + new dicedef_calculator<1, 3, 1, 4>, + new tohit_calculator<8, 1, 7>, + LIGHTCYAN, + false, + BEAM_ELECTRICITY, // beams & reflects + DCHAR_FIRED_ZAP, + true, + true, + false + }, - case ZAP_BEAM_OF_ENERGY: // bolt of innacuracy - pbolt.name = "narrow beam of energy"; - pbolt.colour = YELLOW; - pbolt.damage = calc_dice( 12, 40 + (power * 3) / 2 ); - pbolt.hit = 1; - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_ENERGY; // unresisted - pbolt.obvious_effect = true; - pbolt.is_beam = true; - break; + { + ZAP_ORB_OF_ELECTRICITY, + "orb of electricity", + 200, + new calcdice_calculator<0, 15, 4, 5>, + new tohit_calculator<40>, + LIGHTBLUE, + false, + BEAM_ELECTRICITY, + DCHAR_FIRED_ZAP, + true, + false, + true + }, - case ZAP_SPIT_POISON: // cap 50 - // max pow = lev + mut * 5 = 42 - pbolt.name = "splash of poison"; - pbolt.colour = GREEN; - pbolt.damage = dice_def( 1, 4 + power / 2 ); // max dam: 25 - pbolt.hit = 5 + random2( 1 + power / 3 ); // max hit: 19 - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_POISON; - pbolt.obvious_effect = true; - break; + { + ZAP_SPIT_POISON, + "splash of poison", + 50, + new dicedef_calculator<1, 4, 1, 2>, + new tohit_calculator<5, 1, 6>, + GREEN, + false, + BEAM_POISON, + DCHAR_FIRED_ZAP, + true, + false, + false + }, - case ZAP_BREATHE_FIRE: // cap 50 - // max pow = lev + mut * 4 + 12 = 51 (capped to 50) - pbolt.name = "fiery breath"; - pbolt.colour = RED; - pbolt.damage = dice_def( 3, 4 + power / 3 ); // max dam: 60 - pbolt.hit = 8 + random2( 1 + power / 3 ); // max hit: 25 - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_FIRE; - pbolt.obvious_effect = true; - pbolt.is_beam = true; - break; + { + ZAP_DEBUGGING_RAY, + "debugging ray", + 10000, + new dicedef_calculator<1500, 1, 0, 1>, + new tohit_calculator<1500>, + WHITE, + false, + BEAM_MMISSILE, + DCHAR_FIRED_DEBUG, + true, + false, + false + }, - case ZAP_BREATHE_FROST: // cap 50 - // max power = lev = 27 - pbolt.name = "freezing breath"; - pbolt.colour = WHITE; - pbolt.damage = dice_def( 3, 4 + power / 3 ); // max dam: 39 - pbolt.hit = 8 + random2( 1 + power / 3 ); - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_COLD; - pbolt.obvious_effect = true; - pbolt.is_beam = true; - break; + { + ZAP_BREATHE_FIRE, + "fiery breath", + 50, + new dicedef_calculator<3, 4, 1, 3>, + new tohit_calculator<8, 1, 6>, + RED, + false, + BEAM_FIRE, + DCHAR_FIRED_ZAP, + true, + true, + false + }, - case ZAP_BREATHE_ACID: // cap 50 - // max power = lev for ability, 50 for minor destruction (max dam: 57) - pbolt.name = "acid"; - pbolt.colour = YELLOW; - pbolt.damage = dice_def( 3, 3 + power / 3 ); // max dam: 36 - pbolt.hit = 5 + random2( 1 + power / 3 ); - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_ACID; - pbolt.obvious_effect = true; - pbolt.is_beam = true; - break; - case ZAP_BREATHE_POISON: // leaves clouds of gas // cap 50 - // max power = lev = 27 - pbolt.name = "poison gas"; - pbolt.colour = GREEN; - pbolt.damage = dice_def( 3, 2 + power / 6 ); // max dam: 18 - pbolt.hit = 6 + random2( 1 + power / 3 ); - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_POISON; - pbolt.obvious_effect = true; - pbolt.is_beam = true; - break; + { + ZAP_BREATHE_FROST, + "freezing breath", + 50, + new dicedef_calculator<3, 4, 1, 3>, + new tohit_calculator<8, 1, 6>, + WHITE, + false, + BEAM_COLD, + DCHAR_FIRED_ZAP, + true, + true, + false + }, - case ZAP_BREATHE_POWER: // cap 50 - pbolt.name = "bolt of energy"; - // max power = lev = 27 - - pbolt.colour = BLUE; - if (random2(power) >= 8) - pbolt.colour = LIGHTBLUE; - if (random2(power) >= 12) - pbolt.colour = MAGENTA; - if (random2(power) >= 17) - pbolt.colour = LIGHTMAGENTA; - - pbolt.damage = dice_def( 3, 3 + power / 3 ); // max dam: 36 - pbolt.hit = 5 + random2( 1 + power / 3 ); - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_MMISSILE; // unresistable - pbolt.obvious_effect = true; - pbolt.is_beam = true; - break; + { + ZAP_BREATHE_ACID, + "acid", + 50, + new dicedef_calculator<3, 3, 1, 3>, + new tohit_calculator<5, 1, 6>, + YELLOW, + false, + BEAM_ACID, + DCHAR_FIRED_ZAP, + true, + true, + false + }, - case ZAP_BREATHE_STEAM: // cap 50 - // max power = lev = 27 - pbolt.name = "ball of steam"; - pbolt.colour = LIGHTGREY; - pbolt.damage = dice_def( 3, 4 + power / 5 ); // max dam: 27 - pbolt.hit = 10 + random2( 1 + power / 5 ); - pbolt.type = dchar_glyph(DCHAR_FIRED_ZAP); - pbolt.flavour = BEAM_STEAM; - pbolt.obvious_effect = true; - pbolt.is_beam = true; - break; + { + ZAP_BREATHE_POISON, + "poison gas", + 50, + new dicedef_calculator<3, 2, 1, 6>, + new tohit_calculator<6, 1, 6>, + GREEN, + false, + BEAM_POISON, + DCHAR_FIRED_ZAP, + true, + true, + false + }, - case ZAP_SLOWING: - pbolt.name = "0"; - pbolt.flavour = BEAM_SLOW; - // pbolt.is_beam = true; - break; + { + ZAP_BREATHE_POWER, + "bolt of energy", + 50, + new dicedef_calculator<3, 3, 1, 3>, + new tohit_calculator<5, 1, 6>, + BLUE, + false, + BEAM_MMISSILE, + DCHAR_FIRED_ZAP, + true, + true, + false + }, - case ZAP_HASTING: - pbolt.name = "0"; - pbolt.flavour = BEAM_HASTE; - // pbolt.is_beam = true; - break; + { + ZAP_ENSLAVE_UNDEAD, + "0", + 100, + NULL, + NULL, + BLACK, + true, + BEAM_ENSLAVE_UNDEAD, + DCHAR_SPACE, + false, + false, + false + }, - case ZAP_PARALYSIS: - pbolt.name = "0"; - pbolt.flavour = BEAM_PARALYSIS; - // pbolt.is_beam = true; - break; + { + ZAP_AGONY, + "0agony", + 100, + NULL, + new tohit_calculator<0, 5, 1>, + BLACK, + true, + BEAM_PAIN, + DCHAR_SPACE, + false, + false, + false + }, - case ZAP_PETRIFY: - pbolt.name = "0"; - pbolt.flavour = BEAM_PETRIFY; - // pbolt.is_beam = true; - break; - case ZAP_CONFUSION: - pbolt.name = "0"; - pbolt.flavour = BEAM_CONFUSION; - // pbolt.is_beam = true; - break; + { + ZAP_DISRUPTION, + "0", + 100, + new dicedef_calculator<1, 4, 1, 5>, + new tohit_calculator<0, 3, 1>, + BLACK, + true, + BEAM_DISINTEGRATION, + DCHAR_SPACE, + false, + false, + false + }, - case ZAP_INVISIBILITY: - pbolt.name = "0"; - pbolt.flavour = BEAM_INVISIBILITY; - // pbolt.is_beam = true; - break; + { + ZAP_DISINTEGRATION, + "0", + 100, + new calcdice_calculator<3, 15, 3, 4>, + new tohit_calculator<0, 5, 2>, + BLACK, + true, + BEAM_DISINTEGRATION, + DCHAR_SPACE, + false, + true, + false + }, + + { + ZAP_BREATHE_STEAM, + "ball of steam", + 50, + new dicedef_calculator<3, 4, 1, 5>, + new tohit_calculator<10, 1, 10>, + LIGHTGREY, + false, + BEAM_STEAM, + DCHAR_FIRED_ZAP, + true, + true, + false + }, - case ZAP_HEALING: - pbolt.name = "0"; - pbolt.flavour = BEAM_HEALING; - pbolt.damage = dice_def( 1, 7 + power / 3 ); - // pbolt.is_beam = true; - break; + { + ZAP_CONTROL_DEMON, + "0", + 100, + NULL, + new tohit_calculator<0, 3, 2>, + BLACK, + true, + BEAM_ENSLAVE_DEMON, + DCHAR_SPACE, + false, + false, + false + }, - case ZAP_DIGGING: - pbolt.name = "0"; - pbolt.flavour = BEAM_DIGGING; - // not ordinary "0" beam range {dlb} - pbolt.is_beam = true; - break; + { + ZAP_ORB_OF_FRAGMENTATION, + "metal orb", + 200, + new calcdice_calculator<3, 30, 3, 4>, + new tohit_calculator<20>, + CYAN, + false, + BEAM_FRAG, + DCHAR_FIRED_ZAP, + false, + false, + true + }, - case ZAP_TELEPORTATION: - pbolt.name = "0"; - pbolt.flavour = BEAM_TELEPORT; - // pbolt.is_beam = true; - break; + { + ZAP_ICE_BOLT, + "bolt of ice", + 100, + new calcdice_calculator<3, 10, 1, 2>, + new tohit_calculator<9, 1, 12>, + WHITE, + false, + BEAM_ICE, + DCHAR_FIRED_ZAP, + false, + false, + false + }, + + { // ench_power controls radius + ZAP_ICE_STORM, + "great blast of cold", + 200, + new calcdice_calculator<7, 22, 1, 1>, + new tohit_calculator<20, 1, 10>, + BLUE, + false, + BEAM_ICE, + DCHAR_FIRED_ZAP, + true, + false, + true + }, - case ZAP_POLYMORPH_OTHER: - pbolt.name = "0"; - pbolt.flavour = BEAM_POLYMORPH; - // pbolt.is_beam = true; - break; + { + ZAP_BACKLIGHT, + "0", + 100, + NULL, + NULL, + BLUE, + true, + BEAM_BACKLIGHT, + DCHAR_SPACE, + false, + false, + false + }, - case ZAP_ENSLAVEMENT: - pbolt.name = "0"; - pbolt.flavour = BEAM_CHARM; - // pbolt.is_beam = true; - break; + { + ZAP_SLEEP, + "0", + 100, + NULL, + NULL, + BLACK, + true, + BEAM_SLEEP, + DCHAR_SPACE, + false, + false, + false + }, - case ZAP_BANISHMENT: - pbolt.name = "0"; - pbolt.flavour = BEAM_BANISH; - // pbolt.is_beam = true; - break; + { + ZAP_FLAME_TONGUE, + "flame", + 25, + new dicedef_calculator<1, 8, 1, 4>, + new tohit_calculator<7, 1, 6>, + RED, + false, + BEAM_FIRE, + DCHAR_FIRED_BOLT, + true, + false, + false + }, - case ZAP_DEGENERATION: - pbolt.name = "0"; - pbolt.flavour = BEAM_DEGENERATE; - // pbolt.is_beam = true; - break; + { + ZAP_SANDBLAST, + "rocky blast", + 50, + new dicedef_calculator<2, 4, 1, 3>, + new tohit_calculator<13, 1, 10>, + BROWN, + false, + BEAM_FRAG, + DCHAR_FIRED_BOLT, + true, + false, + false + }, - case ZAP_ENSLAVE_UNDEAD: - pbolt.name = "0"; - pbolt.flavour = BEAM_ENSLAVE_UNDEAD; - // pbolt.is_beam = true; - break; + { + ZAP_SMALL_SANDBLAST, + "blast of sand", + 25, + new dicedef_calculator<1, 8, 1, 4>, + new tohit_calculator<8, 1, 5>, + BROWN, + false, + BEAM_FRAG, + DCHAR_FIRED_BOLT, + true, + false, + false + }, - case ZAP_AGONY: - pbolt.name = "0agony"; - pbolt.flavour = BEAM_PAIN; - pbolt.ench_power *= 5; - // pbolt.is_beam = true; - break; + { + ZAP_MAGMA, + "bolt of magma", + 200, + new calcdice_calculator<4, 10, 3, 5>, + new tohit_calculator<8, 1, 25>, + RED, + false, + BEAM_LAVA, + DCHAR_FIRED_ZAP, + true, + true, + false + }, - case ZAP_CONTROL_DEMON: - pbolt.name = "0"; - pbolt.flavour = BEAM_ENSLAVE_DEMON; - pbolt.ench_power *= 3; - pbolt.ench_power /= 2; - // pbolt.is_beam = true; - break; + { + ZAP_POISON_ARROW, + "poison arrow", + 200, + new calcdice_calculator<4, 15, 1, 1>, + new tohit_calculator<5, 1, 10>, + LIGHTGREEN, + false, + BEAM_POISON_ARROW, // extra damage + DCHAR_FIRED_MISSILE, + true, + false, + false + }, - case ZAP_SLEEP: //jmf: added - pbolt.name = "0"; - pbolt.flavour = BEAM_SLEEP; - // pbolt.is_beam = true; - break; + { + ZAP_PETRIFY, + "0", + 100, + NULL, + NULL, + BLACK, + true, + BEAM_PETRIFY, + DCHAR_SPACE, + false, + false, + false + } +}; - case ZAP_BACKLIGHT: //jmf: added - pbolt.name = "0"; - pbolt.flavour = BEAM_BACKLIGHT; - pbolt.colour = BLUE; - // pbolt.is_beam = true; - break; - case ZAP_DEBUGGING_RAY: - pbolt.name = "debugging ray"; - pbolt.colour = random_colour(); - pbolt.damage = dice_def( 1500, 1 ); // dam: 1500 - pbolt.hit = 1500; // hit: 1500 - pbolt.type = dchar_glyph(DCHAR_FIRED_DEBUG); - pbolt.flavour = BEAM_MMISSILE; // unresistable - pbolt.obvious_effect = true; - break; +// Need to see zapping() for default values not set within this function {dlb} +static void _zappy( zap_type z_type, int power, bolt &pbolt ) +{ + const zap_info* zinfo = NULL; - default: - pbolt.name = "buggy beam"; - pbolt.colour = random_colour(); - pbolt.damage = dice_def( 1, 0 ); - pbolt.hit = 60; - pbolt.type = dchar_glyph(DCHAR_FIRED_DEBUG); - pbolt.flavour = BEAM_MMISSILE; // unresistable - pbolt.obvious_effect = true; - break; + // Find the appropriate zap info. + for (unsigned int i = 0; i < ARRAYSZ(zap_data); ++i) + { + if (zap_data[i].ztype == z_type) + { + zinfo = &zap_data[i]; + break; + } + } + + // None found? + if (zinfo == NULL) + { +#ifdef DEBUG_DIAGNOSTICS + mprf(MSGCH_ERROR, "Couldn't find zap type %d", z_type); +#endif + return; + } + + // Fill + pbolt.name = zinfo->name; + pbolt.flavour = zinfo->flavour; + pbolt.colour = zinfo->colour; + pbolt.type = dchar_glyph(zinfo->glyph); + pbolt.obvious_effect = zinfo->always_obvious; + pbolt.is_beam = zinfo->can_beam; + pbolt.is_explosion = zinfo->is_explosion; + + if (zinfo->power_cap > 0) + power = std::min(zinfo->power_cap, power); + + ASSERT(zinfo->is_enchantment == pbolt.is_enchantment()); + + if (zinfo->is_enchantment) + { + pbolt.ench_power = (zinfo->tohit ? (*zinfo->tohit)(power) : power); + pbolt.hit = AUTOMATIC_HIT; + } + else + { + pbolt.hit = (*zinfo->tohit)(power); + if (wearing_amulet(AMU_INACCURACY)) + pbolt.hit = std::max(0, pbolt.hit - 5); } - if (wearing_amulet(AMU_INACCURACY)) - pbolt.hit = std::max(0, pbolt.hit - 5); + if (zinfo->damage) + pbolt.damage = (*zinfo->damage)(power); + + // One special case + if (z_type == ZAP_ICE_STORM) + pbolt.ench_power = power; // used for radius } // Affect monster in wall unless it can shield itself using the wall. @@ -4850,37 +4712,8 @@ static int _range_used_on_hit(bolt &beam) if (!beam.is_beam) return (BEAM_STOP); - // CHECK ENCHANTMENTS if (beam.is_enchantment()) - { - switch(beam.flavour) - { - case BEAM_SLOW: - case BEAM_HASTE: - case BEAM_HEALING: - case BEAM_PARALYSIS: - case BEAM_PETRIFY: - case BEAM_CONFUSION: - case BEAM_INVISIBILITY: - case BEAM_TELEPORT: - case BEAM_POLYMORPH: - case BEAM_CHARM: - case BEAM_BANISH: - case BEAM_PAIN: - case BEAM_DISINTEGRATION: - case BEAM_DEGENERATE: - case BEAM_DISPEL_UNDEAD: - case BEAM_ENSLAVE_UNDEAD: - case BEAM_ENSLAVE_DEMON: - case BEAM_SLEEP: - case BEAM_BACKLIGHT: - return (BEAM_STOP); - default: - break; - } - - return (0); - } + return (beam.flavour == BEAM_DIGGING ? 0 : BEAM_STOP); // Hellfire stops for nobody! if (beam.name == "hellfire") -- cgit v1.2.3-54-g00ecf