File: beam.h

package info (click to toggle)
crawl 2%3A0.34.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 100,188 kB
  • sloc: cpp: 363,709; ansic: 27,765; javascript: 9,516; python: 8,463; perl: 3,293; java: 3,132; xml: 2,380; makefile: 1,835; sh: 611; objc: 250; cs: 15; sed: 9; lisp: 3
file content (504 lines) | stat: -rw-r--r-- 19,080 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
/**
 * @file
 * @brief Functions related to ranged attacks.
**/

#pragma once

#include <vector>

#include "ac-type.h"
#include "beam-type.h"
#include "enchant-type.h"
#include "externs.h"
#include "killer-type.h"
#include "mon-ai-action.h"
#include "mon-attitude-type.h"
#include "random.h"
#include "ray.h"
#include "spl-cast.h"
#include "zap-type.h"

using std::string;

// The mid of the source for a pending hostile teleport.
// (Can be the player, if caused by teleportitis.)
#define TELEPORTITIS_SOURCE "TELEPORTITIS_SOURCE"

using std::vector;

#define BEAM_STOP       1000        // all beams stopped by subtracting this
                                    // from remaining range

class monster;
class ranged_attack;

enum mon_resist_type
{
    MON_RESIST,                 // monster resisted
    MON_UNAFFECTED,             // monster unaffected
    MON_AFFECTED,               // monster was affected
    MON_OTHER,                  // monster unaffected, but for other reasons
};

class dist;

typedef FixedArray<int, 19, 19> explosion_map;

struct tracer_info
{
    int count;                         // # of times something "hit"
    int power;                         // total levels/hit dice affected

    tracer_info();
    void reset();
};

struct bolt;

struct beam_tracer
{
    // Is this tracer collecting warnings to prompt the player with?
    virtual bool is_collecting_warnings() noexcept { return false; }
    // Has the tracer hit an enemy worth caring about? Only needs to be
    // accurate when firing if `is_collecting_warnings` returns true.
    virtual bool has_hit_foe() noexcept { return false; }
    // Should the beam stop at the target if there is a friendly monster
    // after it?
    virtual bool should_stop() noexcept { return false; }
    // How many times the player was hit by this tracer.
    virtual int player_hit_count() noexcept { return 0; }

    // Called when a meaningful target is affected
    virtual void actor_affected(bool friendly_fire, int power)
    {
        UNUSED(friendly_fire, power);
    }

    virtual void player_hit(bool was_friendly = true)
    {
        UNUSED(was_friendly);
    }
    virtual void monster_hit(const bolt& bolt, const monster& mon)
    {
        UNUSED(bolt, mon);
    }
    virtual void blocked(string message)
    {
        UNUSED(message);
    }
};

// Used when casting a spell to check if the spell should be aborted
struct player_beam_tracer : beam_tracer
{
    struct bad_target
    {
        const monster* mon;
        string adj;
        string suffix;
        bool penance;
    };
    vector<bad_target> bad_attack_targets;
    const monster* bad_charm_target = nullptr;
    const monster* god_hated_target = nullptr;
    int hit_self_count = 0;
    int foe_count = 0;
    string blocked_message;
    int blocked_count = 0;

    player_beam_tracer() {}

    bool is_collecting_warnings() noexcept override
    {
        return true;
    }

    bool has_hit_foe() noexcept override;
    bool should_stop() noexcept override;
    void actor_affected(bool friendly_fire, int power) noexcept override;
    void player_hit(bool was_friendly) noexcept override;
    void monster_hit(const bolt& bolt, const monster& mon) override;
    void blocked(string message) noexcept override;
    bool has_any_warnings() noexcept;
};

// Used to check if casting a spell might be useful
struct targeting_tracer : beam_tracer
{
    tracer_info foe_info;
    tracer_info friend_info;
    bool abort_for_player = false;
    int hurt_player_count = 0;

    targeting_tracer() {}

    bool has_hit_foe() noexcept override;
    void actor_affected(bool friendly_fire, int power) noexcept override;
    void player_hit(bool was_friendly) noexcept override;
    int player_hit_count() noexcept override;

    ai_action::goodness good_to_fire(int foe_ratio) const;
};

struct bolt
{
    bolt();

    // INPUT parameters set by caller
    spell_type  origin_spell = SPELL_NO_SPELL; // may remain SPELL_NO_SPELL for
                                               // non-spell beams.
    int         range = -2;
    char32_t    glyph = '*';           // missile gfx
    colour_t    colour = BLACK;
    beam_type   flavour = BEAM_MAGIC;
    beam_type   real_flavour = BEAM_MAGIC; // for random and chaos beams this
                                           // will remain the same while flavour
                                           // changes
    bool        drop_item = false;     // should drop an item when done
    coord_def   source = {0,0};           // beam origin
    coord_def   target = {0,0};           // intended target
    dice_def    damage = dice_def(0,0);
    int         ench_power = 0, hit = 0;
    killer_type thrower = KILL_NON_ACTOR;   // what kind of thing threw this?
    int         ex_size = 0;           // explosion radius (0==none)

    mid_t       source_id = MID_NOBODY;// The mid of the source (remains
                                       // MID_NOBODY if not coming from a player
                                       // or a monster).
    string source_name = "";      // The name of the source, should it
                                  // be different from agent->name(),
                                  // or if the actor dies prematurely.
    string name = "";
    string short_name = "";
    string hit_verb = "";         // The verb to use when this beam hits
                                  // something. If not set, will use
                                  // "engulfs" if an explosion or cloud
                                  // and "hits" otherwise.
    int    loudness = 0;          // Noise level on hitting or exploding.
    string hit_noise_msg = "";    // Message to give player for each hit
                                  // monster that isn't in view.
    string explode_noise_msg = "";  // Message to give player if the explosion
                                    // isn't in view.
    bool   pierce = false;        // Can the beam pass through a target and
                                  // hit another target behind the first?
    bool   is_explosion = false;
    bool   is_death_effect = false; // effect of e.g. ballistomycete spore
    bool   aimed_at_spot = false; // aimed at (x, y), should not cross
    bool   stop_at_allies = false; // Should beam automatically stop before reaching allies
    bool   safe_to_user = false;  //
    string aux_source = "";       // source of KILL_NON_ACTOR beams

    bool   affects_nothing = false; // should not hit monsters or features

    bool   effect_known = true;   // did we _know_ this would happen?
    bool   effect_wanton = false; // could we have guessed it would happen?

    bool   no_saving_throw = false;   // whether to ignore any saving throw
                                      // this beam might otherwise have
    int    draw_delay = 15;       // delay used when drawing beam.
    int    explode_delay = 50;    // delay when drawing explosions.
    bool   redraw_per_cell = true; // whether to force a redraw after every cell
                                   // drawn during an animation. Not for
                                   // explosions.
                                   // TODO: why can't this behavior follow
                                   // from draw_delay == 0?

    bolt*  special_explosion = nullptr; // For exploding with a different
                                        // flavour/damage/etc than the beam
                                        // itself.
    // Do we draw animations?
    bool   animate;
    ac_type ac_rule = ac_type::normal;   // How defender's AC affects damage.
#ifdef DEBUG_DIAGNOSTICS
    bool   quiet_debug = false;    // Disable any debug spam.
#endif

    // OUTPUT parameters (tracing, ID)
    bool obvious_effect = false; // is this a non-enchantment, or did it already
                                 // show some effect or message? (Otherwise, we'll
                                 // print the canned 'nothing happened.)

    bool seen = false;          // Has player seen the beam?
    bool heard = false;         // Has the player heard the beam?

    vector<coord_def> path_taken = {}; // Path beam took.

    // INTERNAL use - should not usually be set outside of beam.cc
    int  extra_range_used = 0;
    bool aimed_at_feet = false;   // this was aimed at self!
    bool msg_generated = false;   // an appropriate msg was already mpr'd
    bool noise_generated = false; // a noise has already been generated at this pos
    bool passed_target = false;   // Beam progressed beyond target.
    bool in_explosion_phase = false; // explosion phase (as opposed to beam phase)
    bool enchant_chaining_done = false; // wheather we have already chained to nearby actors
    mon_attitude_type attitude = ATT_HOSTILE; // attitude of whoever fired the bolt
    int foe_ratio = 0;           // 100* foe ratio (see mons_should_fire())
    map<mid_t, int> hit_count;   // how many times targets were affected
    int foes_hurt = 0;               // number of foes actually hurt
    int foes_helped = 0;             // number of foes actually helped
    int friends_hurt = 0;            // number of friends actually hurt
    int friends_helped = 0;          // number of friends actually helped

    // Ranged attack to perform on each actor reached (for ranged attack beams)
    ranged_attack* ranged_atk = nullptr;

    beam_tracer* tracer = nullptr;

    bool chose_ray = false;       // do we want a specific ray?
    bool overshoot_prompt = true; // warn when an ally is past the target
    bool friendly_past_target = false; // we fired and found something past the target

    int       bounces = 0;        // # times beam bounced off walls
    coord_def bounce_pos = {0,0}; // position of latest wall bounce,
                                  // reset if a reflection happens

    coord_def last_affected_actor_pos = {0,0};   // position of the last actor affected by this beam

    int   reflections = 0;        // # times beam reflected off shields
    mid_t reflector = MID_NOBODY; // latest thing to reflect beam

    bool use_target_as_pos = false; // pos() should return ::target()

    ray_def     ray;             // shoot on this specific ray

    // only used if USE_TILE is defined
    tileidx_t tile_beam = 0;
    tileidx_t tile_explode = 0;

private:
    bool can_see_invis = false;
    bool nightvision = false;

    bool can_trigger_bullseye = false;

public:
    bool is_enchantment() const; // no block/dodge, use willpower
    void set_target(const dist &targ);
    void set_agent(const actor *agent);
    void setup_retrace();
    void precalc_agent_properties();

    // Returns YOU_KILL or MON_KILL, depending on the source of the beam.
    killer_type  killer() const;

    kill_category whose_kill() const;

    actor* agent(bool ignore_reflections = false) const;

    void fire();
    void fire(beam_tracer& tracer);
    void fire_as_ranged_attack(ranged_attack& atk);

    // Returns member short_name if set, otherwise some reasonable string
    // for a short name, most likely the name of the beam's flavour.
    string get_short_name() const;
    string get_source_name() const;

    bool visible() const;

    bool can_affect_actor(const actor *act) const;
    bool can_affect_wall(const coord_def& p, bool map_knowledge = false) const;
    bool harmless_to_player() const;
    bool ignores_monster(const monster* mon) const;
    bool ignores_player() const;
    bool can_knockback(int dam = -1) const;
    bool can_pull(const actor &act, int dam = -1) const;
    bool god_cares() const; // Will the god be unforgiving about this beam?
    bool is_harmless(const monster* mon) const;
    bool nasty_to(const monster* mon) const;
    bool nice_to(const monster_info& mi) const;
    bool has_saving_throw() const;

    void draw(const coord_def& p, bool force_refresh=true);

    // Various explosion-related stuff.
    bool explode(bool show_more = true, bool hole_in_the_middle = false);
    bool explode(beam_tracer& tracer, bool show_more = true,
                 bool hole_in_the_middle = false);
    void refine_for_explosion(const string& explode_msg = "");
    bool explosion_draw_cell(const coord_def& p);
    void explosion_affect_cell(const coord_def& p);
    void determine_affected_cells(explosion_map& m, const coord_def& delta,
                                  int count, int r,
                                  bool stop_at_statues, bool stop_at_walls);
    void special_explode();

    bool self_targeted() const;

    coord_def get_last_affected_pos(int step = 0);

    // Setup.
    void fake_flavour();
private:
    void do_fire();
    void initialise_fire();

    // Lots of properties of the beam.
    coord_def pos() const;
    coord_def leg_source() const;
    cloud_type get_cloud_type() const;
    int get_cloud_pow() const;
    int get_cloud_size(bool min = false, bool max = false) const;
    bool is_blockable() const;
    bool is_omnireflectable() const;
    bool is_fiery() const;
    bool can_burn_trees() const;
    bool is_bouncy(dungeon_feature_type feat) const;
    bool stop_at_target() const;
    bool is_reflectable(const actor &whom) const;
    bool found_player() const;
    bool need_regress() const;
    bool is_big_cloud() const; // expands into big_cloud at endpoint
    int range_used_on_hit() const;
    bool bush_immune(const monster &mons) const;
    bool at_blocking_monster() const;
    int apply_lighting(int base_hit, const actor &target) const;

    void do_ranged_attack(actor& target);

    set<string> message_cache;
    void emit_message(const char* msg);

    int apply_AC(const actor* victim, int hurted);
    bool determine_damage(monster* mon, int& preac, int& postac, int& final);

    // Functions which handle actually affecting things. They all
    // operate on the beam's current position (i.e., whatever pos()
    // returns.)
    void step();
public:
    void affect_cell();
    void affect_endpoint();
    void affect_endpoint(beam_tracer& tracer);
private:
    void affect_wall();
    void digging_wall_effect();
    void sporangium_wall_effect();
    void burn_wall_effect();
    void affect_ground();
    void affect_place_clouds();
    void affect_place_explosion_clouds();
    int range_used(bool leg_only = false) const;
    void finish_beam();
    void drop_object();

    // These methods make the beam affect a specific actor, not
    // necessarily what's at pos().
public:
    void affect_actor(actor *act);
private:
    // for monsters
    void affect_monster(monster* m);
    void kill_monster(monster &m);
    bool check_for_friendly_past_target(monster* mon);
    bool attempt_block(monster* mon);
    void update_hurt_or_helped(monster* mon);
    void enchantment_affect_monster(monster* mon);
public:
    mon_resist_type try_enchant_monster(monster* mon, int &res_margin);
    mon_resist_type apply_enchantment_to_monster(monster* mon);
    void apply_beam_conducts();
private:
    void apply_bolt_paralysis(monster* mons);
    void apply_bolt_petrify(monster* mons);
    void handle_enchant_chaining(coord_def centre);
    void monster_post_hit(monster* mon, int dmg);
    // for players
    void affect_player();
    bool misses_player();
public:
    void affect_player_enchantment(bool resistible = true);
private:
    void internal_ouch(int dam);
    // for both
    void knockback_actor(actor *act, int dam);
    void pull_actor(actor *act, int dam);

    // tracers
    void tracer_affect_player();
    void tracer_affect_monster(monster* mon);
    void tracer_enchantment_affect_monster(monster* mon);
    void tracer_nonenchantment_affect_monster(monster* mon);
    bool has_relevant_side_effect(monster* mon);

    // methods to change the path
    void bounce();
    void reflect();
public:
    void choose_ray();

    bool is_tracer() const noexcept { return tracer != nullptr; }
    void set_is_tracer(bool value) noexcept;
};

int mons_adjust_flavoured(monster* mons, bolt &pbolt, int hurted,
                          bool doFlavouredEffects = true);

// Return whether the effect was visible.
bool enchant_actor_with_flavour(actor* victim, const actor *atk,
                                beam_type flavour, int powc = 0);

bool enchant_monster_invisible(monster* mon, const string &how);

bool ench_flavour_affects_monster(actor *agent, beam_type flavour,
                                  const monster* mon, bool intrinsic_only = false);
spret mass_enchantment(enchant_type wh_enchant, int pow,
                            bool fail = false);
int ench_power_stepdown(int pow);

bool poison_monster(monster* mons, const actor* who, int levels = 1,
                    bool force = false, bool verbose = true);
bool miasma_monster(monster* mons, const actor* who);
bool sticky_flame_monster(monster* mons, const actor* who, int dur,
                    bool verbose = true);
bool curare_actor(actor* source, actor* target, string name,
                  string source_name, int bonus_poison = 0);
int silver_damages_victim(actor* victim, int damage, string &dmg_msg);
void fire_tracer(const monster* mons, targeting_tracer& tracer,
                 bolt &pbolt, bool explode_only = false,
                 bool explosion_hole = false);
spret zapping(zap_type ztype, int power, bolt &pbolt,
                   bool needs_tracer = false, const char* msg = nullptr,
                   bool fail = false);
void fire_partial_player_tracer(zap_type ztype, int power,
                                player_beam_tracer& tracer,
                                bolt &pbolt, int range = 0);
bool player_tracer(zap_type ztype, int power, bolt &pbolt, int range = 0);

set<coord_def> create_feat_splash(coord_def center, int radius, int num, int dur,
                                  dungeon_feature_type new_feat = DNGN_SHALLOW_WATER);

void init_zap_index();
void clear_zap_info_on_exit();

bool zap_explodes(zap_type ztype);
bool zap_is_enchantment(zap_type ztype);
int zap_ench_power(zap_type z_type, int pow, bool is_monster);
int zap_to_hit(zap_type z_type, int power, bool is_monster);
dice_def zap_damage(zap_type z_type, int power, bool is_monster, bool random = true);
colour_t zap_colour(zap_type z_type);

dice_def combustion_breath_damage(int pow, bool allow_random = true);

void zappy(zap_type z_type, int power, bool is_monster, bolt &pbolt);
void bolt_parent_init(const bolt &parent, bolt &child);

int explosion_noise(int rad);

int omnireflect_chance_denom(int SH);

void glaciate_freeze(monster* mon, killer_type englaciator,
                             int kindex);

void fill_chain_targets(const bolt& beam, coord_def centre,
                        vector<coord_def> &targs, bool random);

bolt setup_targeting_beam(const monster &mons);

bool cancel_beam_prompt(const bolt& beam, const player_beam_tracer& tracer,
                        int beams_fired = 1);

int apply_willpower_bypass(const actor& source, int willpower);
int apply_willpower_bypass(const monster_info& source, int willpower);
int guile_will_reduction(bool max = false);