summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/beam.h
blob: a2c9668bdba74950e98649ad309cc3a44dd7f1ed (plain) (blame)
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
/**
 * @file
 * @brief Functions related to ranged attacks.
**/

#ifndef BEAM_H
#define BEAM_H

#include "externs.h"
#include "random.h"
#include "ray.h"
#include "spl-cast.h"

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

class monster;

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
    int hurt;                          // # of things actually hurt
    int helped;                        // # of things actually helped
    bool dont_stop;                    // Player said not to stop on this

    tracer_info();
    void reset();

    const tracer_info &operator += (const tracer_info &other);
};

struct bolt;

typedef bool (*range_used_func)(const bolt& beam, int &used);
typedef bool (*beam_damage_func)(bolt& beam, actor* victim, int &dmg,
                                 string &dmg_msg);
typedef bool (*beam_hit_func)(bolt& beam, actor* victim, int dmg);
typedef bool (*explosion_aoe_func)(bolt& beam, const coord_def& target);
typedef bool (*beam_affect_func)(const bolt &beam, const actor *victim);

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

    // beam_source can be -GOD_ENUM_VALUE besides monster indices
    // and MHITNOT, MHITYOU.
    int         beam_source;           // NON_MONSTER or monster index #
    string      source_name;           // The name of the source, if it
                                       // should be different from
                                       // actor->name(), or 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;              // Noise level on hitting or exploding.
    string      noise_msg;             // Message to give player if the hit
                                       // or explosion isn't in view.
    bool        is_beam;               // beam? (can hit multiple targets?)
    bool        is_explosion;
    bool        is_big_cloud;          // expands into big_cloud at endpoint
    bool        aimed_at_spot;         // aimed at (x, y), should not cross
    string      aux_source;            // source of KILL_MISC beams

    bool        affects_nothing;       // should not hit monsters or features
    bool        affects_items;         // hits items on ground/inventory

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

    int         draw_delay;            // delay used when drawing beam.
    int         explode_delay;         // delay when drawing explosions.

    bolt*       special_explosion;     // For exploding with a different
                                       // flavour/damage/etc than the beam
                                       // itself.
    bool        was_missile;           // For determining if this was SPMSL_FLAME / FROST etc
                                       // this is required in order to change mulch rate on these types
    bool        animate;               // Do we draw animations?
    ac_type     ac_rule;               // How does defender's AC affect damage.
#ifdef DEBUG_DIAGNOSTICS
    bool        quiet_debug;           // Disable any debug spam.
#endif

    // Various callbacks.
    vector<range_used_func>  range_funcs;
    vector<beam_damage_func> damage_funcs;
    vector<beam_hit_func>    hit_funcs;
    vector<explosion_aoe_func> aoe_funcs; // Function for if the explosion only
                                          // affects certain grid positions.

    // Test if the beam can affect a particular actor.
    beam_affect_func affect_func;

    // OUTPUT parameters (tracing, ID)
    bool        obvious_effect;        // did an 'obvious' effect happen?

    bool        seen;                  // Has player seen the beam?
    bool        heard;                 // 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;
    bool        is_tracer;       // is this a tracer?
    bool        is_targeting;    // . . . in particular, a targeting tracer?
    bool        aimed_at_feet;   // this was aimed at self!
    bool        msg_generated;   // an appropriate msg was already mpr'd
    bool        noise_generated; // a noise has already been generated at this pos
    bool        passed_target;   // Beam progressed beyond target.
    bool     in_explosion_phase; // explosion phase (as opposed to beam phase)
    bool        smart_monster;   // tracer firer can guess at other mons. resists?
    bool        can_see_invis;   // tracer firer can see invisible?
    bool        nightvision;     // tracer firer has nightvision?
    mon_attitude_type attitude;  // attitude of whoever fired tracer
    int         foe_ratio;       // 100* foe ratio (see mons_should_fire())
    map<mid_t, int> hit_count;   // how many times targets were affected

    tracer_info foe_info;
    tracer_info friend_info;

    bool        chose_ray;       // do we want a specific ray?
    bool        beam_cancelled;  // stop_attack_prompt() returned true
    bool        dont_stop_player; // player answered self target prompt with 'y'

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

    int         reflections;     // # times beam reflected off shields
    int         reflector;       // latest thing to reflect beam

    bool        use_target_as_pos; // pos() should return ::target()
    bool        auto_hit;

    ray_def     ray;             // shoot on this specific ray

#ifdef USE_TILE
    int         tile_beam;
#endif

public:
    bolt();

    bool is_enchantment() const; // no block/dodge, use magic resist
    void set_target(const dist &targ);
    void set_agent(actor *agent);
    void setup_retrace();

    // 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();

    // 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;

    // Assume that all saving throws are failed, actually apply
    // the enchantment.
    mon_resist_type apply_enchantment_to_monster(monster* mon);

    // Return whether any affected cell was seen.
    bool explode(bool show_more = true, bool hole_in_the_middle = false);
    bool knockback_actor(actor *actor);

    bool visible() const;

    bool can_affect_actor(const actor *act) const;
    bool ignores_monster(const monster* mon) const;

    maybe_bool affects_wall(dungeon_feature_type wall) const;

    int range_used_on_hit() const;

private:
    void do_fire();
    coord_def pos() const;
    coord_def leg_source() const;

    // Lots of properties of the beam.
    bool is_blockable() const;
    bool is_fiery() const;
    bool is_superhot() const;
    bool can_affect_wall(dungeon_feature_type feat) const;
    bool can_affect_wall_actor(const actor *act) const;
    bool is_bouncy(dungeon_feature_type feat) const;
    bool stop_at_target() const;
    bool has_saving_throw() const;
    bool is_harmless(const monster* mon) const;
    bool harmless_to_player() const;
    bool is_reflectable(const item_def *item) const;
    bool nasty_to(const monster* mon) const;
    bool nice_to(const monster* mon) const;
    bool found_player() const;
    bool need_regress() const;

    const actor* beam_source_as_target() const;

    string zapper() const;

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

    bool apply_hit_funcs(actor* victim, int dmg);
    bool apply_dmg_funcs(actor* victim, int &dmg, vector<string> &messages);
    int apply_AC(const actor* victim, int hurted);

    cloud_type get_cloud_type();
    int get_cloud_pow();
    int get_cloud_size(bool min = false, bool max = false);

    // Functions which handle actually affecting things. They all
    // operate on the beam's current position (i.e., whatever pos()
    // returns.)
public:
    void affect_cell();
    void affect_wall();
    void affect_actor(actor *act);
    void affect_monster(monster* m);
    void affect_player();
    void affect_ground();
    void affect_place_clouds();
    void affect_place_explosion_clouds();
    void affect_endpoint();

    void beam_hits_actor(actor *act);
    bool god_cares() const; // Will the god be unforgiving about this beam?

    // Stuff when a monster or player is hit.
    void affect_player_enchantment(bool resistible = true);
    void tracer_affect_player();
    void tracer_affect_monster(monster* mon);
    void apply_bolt_paralysis(monster* mons);
    void apply_bolt_petrify(monster* mons);
    void enchantment_affect_monster(monster* mon);
    mon_resist_type try_enchant_monster(monster* mon, int &res_margin);
    void tracer_enchantment_affect_monster(monster* mon);
    void tracer_nonenchantment_affect_monster(monster* mon);
    void update_hurt_or_helped(monster* mon);
    bool attempt_block(monster* mon);
    void handle_stop_attack_prompt(monster* mon);
    bool determine_damage(monster* mon, int& preac, int& postac, int& final,
                          vector<string> &messages);
    void monster_post_hit(monster* mon, int dmg);
    bool misses_player();

    void initialise_fire();
    void apply_beam_conducts();
    void choose_ray();
    void draw(const coord_def& p);
    void bounce();
    void reflect();
    void fake_flavour();
    void digging_wall_effect();
    void fire_wall_effect();
    void elec_wall_effect();
    void destroy_wall_effect();
    void drop_object();
    int range_used(bool leg_only = false) const;
    void finish_beam();
    bool fuzz_invis_tracer();

    void internal_ouch(int dam);

    // Various explosion-related stuff.
    void refine_for_explosion();
    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);
    bool can_knockback(const actor *act = NULL, int dam = -1) const;
};

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, actor *atk,
                                beam_type flavour, int powc = 0);

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

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

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 napalm_monster(monster* mons, const actor* who, int levels = 1,
                    bool verbose = true);
bool curare_actor(actor* source, actor* target, int levels, string name,
                  string source_name);
int silver_damages_victim(actor* victim, int damage, string &dmg_msg);
void fire_tracer(const monster* mons, bolt &pbolt,
                  bool explode_only = false);
bool imb_can_splash(coord_def origin, coord_def center,
                    vector<coord_def> path_taken, coord_def target);
spret_type zapping(zap_type ztype, int power, bolt &pbolt,
                   bool needs_tracer = false, const char* msg = NULL,
                   bool fail = false);
bool player_tracer(zap_type ztype, int power, bolt &pbolt, int range = 0);

void init_zap_index();
void clear_zap_info_on_exit();

int zap_power_cap(zap_type ztype);
void zappy(zap_type z_type, int power, bolt &pbolt);
void bolt_parent_init(bolt *parent, bolt *child);
#endif