summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/source/beam.cc168
-rw-r--r--crawl-ref/source/beam.h9
-rw-r--r--crawl-ref/source/dat/database/monspell.txt4
-rw-r--r--crawl-ref/source/mstuff2.cc106
4 files changed, 234 insertions, 53 deletions
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc
index 1f03b7930a..817e6ab89c 100644
--- a/crawl-ref/source/beam.cc
+++ b/crawl-ref/source/beam.cc
@@ -214,6 +214,7 @@ static void _beam_set_default_values(bolt &beam, int power)
beam.dropped_item = false; // no item droped yet
beam.reflections = 0; // no reflections yet
beam.bounces = 0; // no bounces yet
+ beam.seen = false; // not seen yet
beam.aux_source.clear(); // additional source info, unused
}
@@ -288,6 +289,7 @@ bool player_tracer( zap_type ztype, int power, bolt &pbolt, int range)
// Clear misc
pbolt.dropped_item = false;
+ pbolt.seen = false;
pbolt.reflections = 0;
pbolt.bounces = 0;
@@ -312,6 +314,9 @@ bool player_tracer( zap_type ztype, int power, bolt &pbolt, int range)
pbolt.reflections = 0;
pbolt.bounces = 0;
+ // Haven't seen it yet in the actual firing.
+ pbolt.seen = false;
+
// Set to non-tracing for actual firing.
pbolt.is_tracer = false;
return (true);
@@ -1526,20 +1531,39 @@ static void _munge_bounced_bolt(bolt &old_bolt, bolt &new_bolt,
void fire_beam(bolt &pbolt)
{
+ ASSERT(!pbolt.name.empty());
+ ASSERT(pbolt.flavour > BEAM_NONE && pbolt.flavour < NUM_BEAMS);
+ ASSERT(!pbolt.drop_item || pbolt.item);
+ ASSERT(!pbolt.dropped_item);
+
pbolt.real_flavour = pbolt.flavour;
const int reflections = pbolt.reflections;
if (reflections == 0)
{
- // We aren't being recursively called.
+ // We aren't being recursively called, so initialize some stuff.
beam_message_cache.clear();
pbolt.range_used = 0;
+
+ // pbolt.seen might be set by caller to supress this.
+ if (!pbolt.seen && see_grid(pbolt.source) && pbolt.range > 0
+ && pbolt.type != 0 && pbolt.name[0] != '0')
+ {
+ pbolt.seen = true;
+ int midx = mgrd(pbolt.source);
+
+ if (!pbolt.is_tracer && !YOU_KILL(pbolt.thrower)
+ && !crawl_state.is_god_acting()
+ && (midx == NON_MONSTER || !you.can_see(&menv[midx])))
+ {
+ mprf("%s appears from out of thin air!",
+ article_a(pbolt.name, false).c_str());
+ }
+ }
}
ASSERT(pbolt.range >= 0 && pbolt.range_used >=0);
ASSERT(pbolt.range_used <= pbolt.range);
- ASSERT(!pbolt.drop_item || pbolt.item);
- ASSERT(!pbolt.dropped_item);
if (pbolt.range == pbolt.range_used && pbolt.range > 0)
{
@@ -1720,6 +1744,19 @@ void fire_beam(bolt &pbolt)
if (grid_is_solid(grd(testpos)))
break;
+ const bool was_seen = pbolt.seen;
+ if (!was_seen && pbolt.range > 0 && pbolt.type != 0
+ && pbolt.name[0] != '0' && see_grid(testpos))
+ {
+ pbolt.seen = true;
+ }
+
+ if (!was_seen && pbolt.seen && !pbolt.is_tracer)
+ {
+ mprf("%s appears from out of your range of vision.",
+ article_a(pbolt.name, false).c_str());
+ }
+
// Check for "target termination"
// occurs when beam can be targetted at empty
// cell (e.g. a mage wants an explosion to happen
@@ -2713,6 +2750,9 @@ void fire_tracer(const monsters *monster, bolt &pbolt, bool explode_only)
pbolt.reflections = 0;
pbolt.bounces = 0;
+ // Hasn't been seen yet in the real firing.
+ pbolt.seen = false;
+
// Unset tracer flag (convenience).
pbolt.is_tracer = false;
}
@@ -5695,18 +5735,18 @@ bolt::bolt() : range(0), type('*'),
flavour(BEAM_MAGIC), real_flavour(BEAM_MAGIC), drop_item(false),
item(NULL), source(), target(), pos(), damage(0,0),
ench_power(0), hit(0), thrower(KILL_MISC), ex_size(0),
- beam_source(MHITNOT), name(), is_beam(false),
+ beam_source(MHITNOT), name(), short_name(), is_beam(false),
is_explosion(false), is_big_cloud(false), aimed_at_spot(false),
aux_source(), affects_nothing(false), effect_known(true),
obvious_effect(false),
fr_count(0), foe_count(0), fr_power(0), foe_power(0),
fr_hurt(0), foe_hurt(0), fr_helped(0),foe_helped(0),
dropped_item(false), item_pos(), item_index(NON_ITEM),
- range_used(0), is_tracer(false), aimed_at_feet(false),
- msg_generated(false), in_explosion_phase(false),
- smart_monster(false), can_see_invis(false),
- attitude(ATT_HOSTILE), foe_ratio(0), chose_ray(false),
- beam_cancelled(false), dont_stop_foe(false),
+ seen(false), range_used(0), is_tracer(false),
+ aimed_at_feet(false), msg_generated(false),
+ in_explosion_phase(false), smart_monster(false),
+ can_see_invis(false), attitude(ATT_HOSTILE), foe_ratio(0),
+ chose_ray(false), beam_cancelled(false), dont_stop_foe(false),
dont_stop_fr(false), dont_stop_player(false),
bounces(false), bounce_pos(), reflections(false), reflector(-1)
{
@@ -5776,3 +5816,113 @@ bool bolt::is_enchantment() const
return (this->flavour >= BEAM_FIRST_ENCHANTMENT
&& this->flavour <= BEAM_LAST_ENCHANTMENT);
}
+
+std::string bolt::get_short_name()
+{
+ if (!short_name.empty())
+ return (short_name);
+
+ if (item != NULL && is_valid_item(*item))
+ return item->name(DESC_NOCAP_A, false, false, false, false,
+ ISFLAG_IDENT_MASK | ISFLAG_COSMETIC_MASK
+ | ISFLAG_RACIAL_MASK);
+
+ if (real_flavour == BEAM_RANDOM || real_flavour == BEAM_CHAOS)
+ flavour = real_flavour;
+
+ if (flavour == BEAM_FIRE && name == "sticky fire")
+ return ("sticky fire");
+
+ if (flavour == BEAM_ELECTRICITY && is_beam)
+ return ("lightning");
+
+ if (flavour == BEAM_NONE || flavour == BEAM_MISSILE
+ || flavour == BEAM_MMISSILE)
+ {
+ return (name);
+ }
+
+ return beam_type_name(flavour);
+}
+
+std::string beam_type_name(beam_type type)
+{
+ switch(type)
+ {
+ case BEAM_NONE: return("none");
+ case BEAM_MISSILE: return("missile");
+ case BEAM_MMISSILE: return("magic missile");
+
+ case BEAM_POTION_FIRE:
+ case BEAM_FIRE: return("fire");
+
+ case BEAM_POTION_COLD:
+ case BEAM_COLD: return("cold");
+
+ case BEAM_MAGIC: return("magic");
+ case BEAM_ELECTRICITY: return("electricity");
+
+ case BEAM_POTION_STINKING_CLOUD:
+ case BEAM_POTION_POISON:
+ case BEAM_POISON: return("poison");
+
+ case BEAM_NEG: return("negative energy");
+ case BEAM_ACID: return("acid");
+
+ case BEAM_MIASMA:
+ case BEAM_POTION_MIASMA: return("miasma");
+
+ case BEAM_SPORE: return("spores");
+ case BEAM_POISON_ARROW: return("poison arrow");
+ case BEAM_HELLFIRE: return("hellfire");
+ case BEAM_NAPALM: return("sticky fire");
+
+ case BEAM_POTION_STEAM:
+ case BEAM_STEAM: return("steam");
+
+ case BEAM_HELLFROST: return("hellfrost");
+ case BEAM_ENERGY: return("energy");
+ case BEAM_HOLY: return("holy power");
+ case BEAM_FRAG: return("fragments");
+ case BEAM_LAVA: return("magma");
+ case BEAM_ICE: return("ice");
+ case BEAM_NUKE: return("nuke");
+ case BEAM_RANDOM: return("random");
+ case BEAM_CHAOS: return("chaos");
+ case BEAM_SLOW: return("slow");
+ case BEAM_HASTE: return("haste");
+ case BEAM_HEALING: return("healing");
+ case BEAM_PARALYSIS: return("paralysis");
+ case BEAM_CONFUSION: return("confusion");
+ case BEAM_INVISIBILITY: return("invisibility");
+ case BEAM_DIGGING: return("digging");
+ case BEAM_TELEPORT: return("teleportation");
+ case BEAM_POLYMORPH: return("polymorph");
+ case BEAM_CHARM: return("enslave");
+ case BEAM_BANISH: return("banishment");
+ case BEAM_DEGENERATE: return("degenration");
+ case BEAM_ENSLAVE_UNDEAD: return("enslave undead");
+ case BEAM_ENSLAVE_SOUL: return("enslave soul");
+ case BEAM_PAIN: return("pain");
+ case BEAM_DISPEL_UNDEAD: return("dispel undead");
+ case BEAM_DISINTEGRATION: return("disintegration");
+ case BEAM_ENSLAVE_DEMON: return("enlsave demon");
+ case BEAM_BLINK: return("blink");
+ case BEAM_PETRIFY: return("petrify");
+ case BEAM_BACKLIGHT: return("backlight");
+ case BEAM_SLEEP: return("sleep");
+ case BEAM_POTION_BLACK_SMOKE: return("black smoke");
+ case BEAM_POTION_GREY_SMOKE: return("grey smoke");
+ case BEAM_POTION_BLUE_SMOKE: return("blue smoke");
+ case BEAM_POTION_PURP_SMOKE: return("purple smoke");
+ case BEAM_POTION_RANDOM: return("random potion");
+ case BEAM_TORMENT_DAMAGE: return("torment damage");
+ case BEAM_STEAL_FOOD: return("steal food");
+ case BEAM_LINE_OF_SIGHT: return("line of sight");
+ case NUM_BEAMS:
+ DEBUGSTR("invalid beam type");
+ return("INVALID");
+ }
+ DEBUGSTR("unknown beam type");
+ return("UNKNOWN");
+}
diff --git a/crawl-ref/source/beam.h b/crawl-ref/source/beam.h
index c805611783..f8968e3967 100644
--- a/crawl-ref/source/beam.h
+++ b/crawl-ref/source/beam.h
@@ -54,6 +54,7 @@ struct bolt
char ex_size; // explosion radius (0==none)
int beam_source; // NON_MONSTER or monster index #
std::string name;
+ std::string short_name;
bool is_beam; // beams? (can hits multiple targets?)
bool is_explosion;
bool is_big_cloud; // expands into big_cloud at endpoint
@@ -76,6 +77,8 @@ struct bolt
coord_def item_pos; // position item was dropped at
int item_index; // mitm[index] of item
+ bool seen; // Has player seen the beam?
+
// INTERNAL use - should not usually be set outside of beam.cc
int range_used;
bool is_tracer; // is this a tracer?
@@ -117,6 +120,10 @@ public:
killer_type killer() const;
actor* agent() const;
+
+ // Returns member short_name if set, otherwise some reasonble string
+ // for a short name, most likely the name of the beam's flavour.
+ std::string get_short_name();
};
dice_def calc_dice( int num_dice, int max_damage );
@@ -163,4 +170,6 @@ int affect(bolt &beam, const coord_def& p = coord_def(),
void beam_drop_object( bolt &beam, item_def *item = NULL,
const coord_def& where = coord_def() );
+std::string beam_type_name(beam_type type);
+
#endif
diff --git a/crawl-ref/source/dat/database/monspell.txt b/crawl-ref/source/dat/database/monspell.txt
index 9e232d65d3..bbf76a8b83 100644
--- a/crawl-ref/source/dat/database/monspell.txt
+++ b/crawl-ref/source/dat/database/monspell.txt
@@ -12,7 +12,7 @@ You hear a spitting sound.
%%%%
Draconian Breath cast
-@The_monster@ breathes.
+@The_monster@ breathes @beam@ at @target@.
%%%%
Draconian Breath cast unseen
@@ -78,7 +78,7 @@ demon cast
%%%%
dragon cast
-@The_monster@ breathes.
+@The_monster@ breathes @beam@ at @target@.
%%%%
dragon cast unseen
diff --git a/crawl-ref/source/mstuff2.cc b/crawl-ref/source/mstuff2.cc
index 477d886d1f..5c9407f0fe 100644
--- a/crawl-ref/source/mstuff2.cc
+++ b/crawl-ref/source/mstuff2.cc
@@ -651,7 +651,6 @@ void mons_cast_noise(monsters *monster, bolt &pbolt, spell_type spell_cast)
}
std::string target = "something";
-
if (pbolt.target == you.pos())
target = "you";
else if (see_grid(pbolt.target))
@@ -669,6 +668,22 @@ void mons_cast_noise(monsters *monster, bolt &pbolt, spell_type spell_cast)
msg = replace_all(msg, "@target@", target);
+ // Don't check for pbolt.seen, since we get called before the beam is
+ // fired.
+ std::string beam_name;
+ if (pbolt.flavour <= BEAM_NONE
+ || pbolt.flavour >= NUM_BEAMS
+ || pbolt.name.empty())
+ {
+ beam_name = "INVALID BEAM";
+ }
+ else if (pbolt.type == 0 || pbolt.name[0] == '0')
+ beam_name = "INVISIBLE BEAM";
+ else
+ beam_name = pbolt.get_short_name();
+
+ msg = replace_all(msg, "@beam@", beam_name);
+
const msg_channel_type chan =
(unseen ? MSGCH_SOUND :
mons_friendly(monster) ? MSGCH_FRIEND_SPELL :
@@ -782,6 +797,7 @@ void setup_mons_cast(monsters *monster, bolt &pbolt,
pbolt.flavour = theBeam.flavour;
pbolt.thrower = theBeam.thrower;
pbolt.name = theBeam.name;
+ pbolt.short_name = theBeam.short_name;
pbolt.is_beam = theBeam.is_beam;
pbolt.source = monster->pos();
pbolt.is_tracer = false;
@@ -1754,14 +1770,15 @@ bolt mons_spells( monsters *mons, spell_type spell_cast, int power )
break;
case SPELL_ISKENDERUNS_MYSTIC_BLAST: // mystic blast
- beam.colour = LIGHTMAGENTA;
- beam.name = "orb of energy";
- beam.damage = dice_def( 3, 7 + (power / 14) );
- beam.hit = 20 + (power / 20);
- beam.type = dchar_glyph(DCHAR_FIRED_ZAP);
- beam.thrower = KILL_MON_MISSILE;
- beam.flavour = BEAM_MMISSILE;
- beam.is_beam = false;
+ beam.colour = LIGHTMAGENTA;
+ beam.name = "orb of energy";
+ beam.short_name = "energy";
+ beam.damage = dice_def( 3, 7 + (power / 14) );
+ beam.hit = 20 + (power / 20);
+ beam.type = dchar_glyph(DCHAR_FIRED_ZAP);
+ beam.thrower = KILL_MON_MISSILE;
+ beam.flavour = BEAM_MMISSILE;
+ beam.is_beam = false;
break;
case SPELL_STEAM_BALL:
@@ -1810,14 +1827,15 @@ bolt mons_spells( monsters *mons, spell_type spell_cast, int power )
break;
case SPELL_ENERGY_BOLT: // eye of devastation
- beam.colour = YELLOW;
- beam.name = "bolt of energy";
- beam.damage = dice_def( 3, 20 );
- beam.hit = 15 + power / 30;
- beam.type = dchar_glyph(DCHAR_FIRED_ZAP);
- beam.thrower = KILL_MON_MISSILE;
- beam.flavour = BEAM_NUKE; // a magical missile which destroys walls
- beam.is_beam = true;
+ beam.colour = YELLOW;
+ beam.name = "bolt of energy";
+ beam.short_name = "energy";
+ beam.damage = dice_def( 3, 20 );
+ beam.hit = 15 + power / 30;
+ beam.type = dchar_glyph(DCHAR_FIRED_ZAP);
+ beam.thrower = KILL_MON_MISSILE;
+ beam.flavour = BEAM_NUKE; // a magical missile which destroys walls
+ beam.is_beam = true;
break;
case SPELL_STING: // sting
@@ -1911,14 +1929,15 @@ bolt mons_spells( monsters *mons, spell_type spell_cast, int power )
break;
case SPELL_QUICKSILVER_BOLT: // Quicksilver dragon
- beam.colour = random_colour();
- beam.name = "bolt of energy";
- beam.damage = dice_def( 3, 25 );
- beam.hit = 16 + power / 25;
- beam.type = dchar_glyph(DCHAR_FIRED_ZAP);
- beam.thrower = KILL_MON_MISSILE;
- beam.flavour = BEAM_MMISSILE;
- beam.is_beam = false;
+ beam.colour = random_colour();
+ beam.name = "bolt of energy";
+ beam.short_name = "energy";
+ beam.damage = dice_def( 3, 25 );
+ beam.hit = 16 + power / 25;
+ beam.type = dchar_glyph(DCHAR_FIRED_ZAP);
+ beam.thrower = KILL_MON_MISSILE;
+ beam.flavour = BEAM_MMISSILE;
+ beam.is_beam = false;
break;
case SPELL_HELLFIRE: // fiend's hellfire
@@ -1935,14 +1954,15 @@ bolt mons_spells( monsters *mons, spell_type spell_cast, int power )
break;
case SPELL_METAL_SPLINTERS:
- beam.name = "spray of metal splinters";
- beam.damage = dice_def( 3, 20 + power / 20 );
- beam.colour = CYAN;
- beam.type = dchar_glyph(DCHAR_FIRED_ZAP);
- beam.thrower = KILL_MON;
- beam.flavour = BEAM_FRAG;
- beam.hit = 19 + power / 30;
- beam.is_beam = true;
+ beam.name = "spray of metal splinters";
+ beam.short_name = "metal splinters";
+ beam.damage = dice_def( 3, 20 + power / 20 );
+ beam.colour = CYAN;
+ beam.type = dchar_glyph(DCHAR_FIRED_ZAP);
+ beam.thrower = KILL_MON;
+ beam.flavour = BEAM_FRAG;
+ beam.hit = 19 + power / 30;
+ beam.is_beam = true;
break;
case SPELL_BANISHMENT:
@@ -1974,15 +1994,16 @@ bolt mons_spells( monsters *mons, spell_type spell_cast, int power )
break;
case SPELL_COLD_BREATH:
- beam.name = "blast of cold";
- beam.aux_source = "blast of icy breath";
- beam.damage = dice_def( 3, (mons->hit_dice * 2) );
- beam.colour = WHITE;
- beam.type = dchar_glyph(DCHAR_FIRED_ZAP);
- beam.thrower = KILL_MON;
- beam.hit = 30;
- beam.flavour = BEAM_COLD;
- beam.is_beam = true;
+ beam.name = "blast of cold";
+ beam.aux_source = "blast of icy breath";
+ beam.short_name = "frost";
+ beam.damage = dice_def( 3, (mons->hit_dice * 2) );
+ beam.colour = WHITE;
+ beam.type = dchar_glyph(DCHAR_FIRED_ZAP);
+ beam.thrower = KILL_MON;
+ beam.hit = 30;
+ beam.flavour = BEAM_COLD;
+ beam.is_beam = true;
break;
case SPELL_DRACONIAN_BREATH:
@@ -2011,6 +2032,7 @@ bolt mons_spells( monsters *mons, spell_type spell_cast, int power )
case MONS_WHITE_DRACONIAN:
beam.name = "chilling blast";
beam.aux_source = "blast of chilling breath";
+ beam.short_name = "frost";
scaling = 65;
break;