1 #pragma once
2 
3 #include <vector>
4 
5 #include "beam.h"
6 #include "los-type.h"
7 #include "reach-type.h"
8 
9 using std::vector;
10 
11 struct passwall_path;
12 
13 enum aff_type // sign and non-zeroness matters
14 {
15     AFF_TRACER = -1,
16     AFF_NO      = 0,
17     AFF_MAYBE   = 1, // can possibly affect
18     AFF_YES,         // intended/likely to affect
19     // If you want to extend this to pass the probability somehow, feel free to,
20     // just keep AFF_YES the minimal "bright" value.
21     AFF_LANDING,     // Valid shadow step landing site
22     AFF_MULTIPLE,    // Passes through multiple times
23 };
24 
25 class targeter
26 {
27 public:
targeter()28     targeter() :  agent(nullptr), obeys_mesmerise(false) {};
~targeter()29     virtual ~targeter() {};
30 
31     coord_def origin;
32     coord_def aim;
33     const actor* agent;
34     string why_not;
35     bool obeys_mesmerise; // whether the rendering of ranges should take into account mesmerise effects
36 
37     virtual bool set_aim(coord_def a);
38     virtual bool valid_aim(coord_def a) = 0;
39     virtual bool can_affect_outside_range();
40     virtual bool can_affect_walls();
41 
42     virtual aff_type is_affected(coord_def loc) = 0;
43     virtual bool can_affect_unseen();
44     virtual bool affects_monster(const monster_info& mon);
45 protected:
46     bool anyone_there(coord_def loc);
47 };
48 
49 class targeter_beam : public targeter
50 {
51 public:
52     targeter_beam(const actor *act, int range, zap_type zap, int pow,
53                    int min_expl_rad, int max_expl_rad);
54     bolt beam;
55     virtual bool set_aim(coord_def a) override;
56     bool valid_aim(coord_def a) override;
57     bool can_affect_outside_range() override;
58     virtual aff_type is_affected(coord_def loc) override;
59     virtual bool affects_monster(const monster_info& mon) override;
60 protected:
61     vector<coord_def> path_taken; // Path beam took.
62     void set_explosion_aim(bolt tempbeam);
63     void set_explosion_target(bolt &tempbeam);
64     int min_expl_rad, max_expl_rad;
65     int range;
66 private:
67     bool penetrates_targets;
68     explosion_map exp_map_min, exp_map_max;
69 };
70 
71 class targeter_unravelling : public targeter_beam
72 {
73 public:
74     targeter_unravelling(const actor *act, int range, int pow);
75     bool set_aim(coord_def a) override;
76 };
77 
78 class targeter_view : public targeter
79 {
80 public:
81     targeter_view();
82     bool valid_aim(coord_def a) override;
83     aff_type is_affected(coord_def loc) override;
84 };
85 
86 class targeter_smite : public targeter
87 {
88 public:
89     targeter_smite(const actor *act, int range = LOS_RADIUS,
90                     int exp_min = 0, int exp_max = 0, bool wall_ok = false,
91                     bool (*affects_pos_func)(const coord_def &) = 0);
92     virtual bool set_aim(coord_def a) override;
93     virtual bool valid_aim(coord_def a) override;
94     virtual bool can_affect_outside_range() override;
95     bool can_affect_walls() override;
96     aff_type is_affected(coord_def loc) override;
97 protected:
98     // assumes exp_map is valid only if >0, so let's keep it private
99     int exp_range_min, exp_range_max;
100     explosion_map exp_map_min, exp_map_max;
101     int range;
102 private:
103     bool affects_walls;
104     bool (*affects_pos)(const coord_def &);
105 };
106 
107 class targeter_walljump : public targeter_smite
108 {
109 public:
110     targeter_walljump();
111     aff_type is_affected(coord_def loc) override;
112     bool valid_aim(coord_def a) override;
113 };
114 
115 class targeter_transference : public targeter_smite
116 {
117 public:
118     targeter_transference(const actor *act, int aoe);
119     bool valid_aim(coord_def a) override;
120 };
121 
122 class targeter_fragment : public targeter_smite
123 {
124 public:
125     targeter_fragment(const actor *act, int power, int range = LOS_RADIUS);
126     bool set_aim(coord_def a) override;
127     bool valid_aim(coord_def a) override;
128 private:
129     int pow;
130 };
131 
132 class targeter_reach : public targeter
133 {
134 public:
135     targeter_reach(const actor* act, reach_type ran = REACH_NONE);
136     reach_type range;
137     bool valid_aim(coord_def a) override;
138     aff_type is_affected(coord_def loc) override;
139 };
140 
141 class targeter_cleave : public targeter
142 {
143 public:
144     targeter_cleave(const actor* act, coord_def target);
145     aff_type is_affected(coord_def loc) override;
146     bool valid_aim(coord_def) override;
147     bool set_aim(coord_def a) override;
148 private:
149     set<coord_def> targets;
150 };
151 
152 class targeter_cloud : public targeter
153 {
154 public:
155     targeter_cloud(const actor* act, int range = LOS_RADIUS,
156                     int count_min = 8, int count_max = 10);
157     bool set_aim(coord_def a) override;
158     bool valid_aim(coord_def a) override;
159     bool can_affect_outside_range() override;
160     aff_type is_affected(coord_def loc) override;
161     int range;
162     int cnt_min, cnt_max;
163     map<coord_def, aff_type> seen;
164     vector<vector<coord_def> > queue;
165     bool avoid_clouds;
166 };
167 
168 // TODO: this should be based on targeter_beam instead
169 class targeter_splash : public targeter
170 {
171 public:
172     targeter_splash(const actor *act, int ran);
173     bool valid_aim(coord_def a) override;
174     aff_type is_affected(coord_def loc) override;
175 private:
176     int range;
177 };
178 
179 class targeter_radius : public targeter
180 {
181 public:
182     targeter_radius(const actor *act, los_type _los = LOS_DEFAULT,
183                   int ran = LOS_RADIUS, int ran_max = 0, int ran_min = 0);
184     bool valid_aim(coord_def a) override;
185     virtual aff_type is_affected(coord_def loc) override;
186 private:
187     los_type los;
188     int range, range_max, range_min;
189 };
190 
191 // like targeter_radius, but converts all AFF_YESes to AFF_MAYBE
192 class targeter_maybe_radius : public targeter_radius
193 {
194 public:
195     targeter_maybe_radius(const actor *act, los_type _los = LOS_DEFAULT,
196                   int ran = LOS_RADIUS, int ran_max = 0, int ran_min = 0)
targeter_radius(act,_los,ran,ran_max,ran_min)197         : targeter_radius(act, _los, ran, ran_max, ran_min)
198     { }
199 
is_affected(coord_def loc)200     virtual aff_type is_affected(coord_def loc) override
201     {
202         if (targeter_radius::is_affected(loc))
203             return AFF_MAYBE;
204         else
205             return AFF_NO;
206     }
207 };
208 
209 class targeter_thunderbolt : public targeter
210 {
211 public:
212     targeter_thunderbolt(const actor *act, int r, coord_def _prev);
213 
214     bool valid_aim(coord_def a) override;
215     bool set_aim(coord_def a) override;
216     aff_type is_affected(coord_def loc) override;
217     map<coord_def, aff_type> zapped;
218     FixedVector<int, LOS_RADIUS + 1> arc_length;
219 private:
220     coord_def prev;
221     int range;
222 };
223 
224 enum class shadow_step_blocked
225 {
226     none,
227     occupied,
228     move,
229     path,
230     no_target,
231 };
232 
233 class targeter_shadow_step : public targeter
234 {
235 public:
236     targeter_shadow_step(const actor* act, int r);
237 
238     bool valid_aim(coord_def a) override;
239     bool set_aim(coord_def a) override;
240     bool step_is_blocked;
241     aff_type is_affected(coord_def loc) override;
242     bool has_additional_sites(coord_def a);
243     set<coord_def> additional_sites;
244     coord_def landing_site;
245 private:
246     void set_additional_sites(coord_def a);
247     void get_additional_sites(coord_def a);
248     bool valid_landing(coord_def a, bool check_invis = true);
249     shadow_step_blocked no_landing_reason;
250     shadow_step_blocked blocked_landing_reason;
251     set<coord_def> temp_sites;
252     int range;
253 };
254 
255 class targeter_cone : public targeter
256 {
257 public:
258     targeter_cone(const actor *act, int r);
259 
260     bool valid_aim(coord_def a) override;
261     bool set_aim(coord_def a) override;
262     aff_type is_affected(coord_def loc) override;
263     map<coord_def, aff_type> zapped;
264     FixedVector< map<coord_def, aff_type>, LOS_RADIUS + 1 > sweep;
265 private:
266     int range;
267 };
268 
269 #define CLOUD_CONE_BEAM_COUNT 11
270 
271 class targeter_shotgun : public targeter
272 {
273 public:
274     targeter_shotgun(const actor* act, size_t beam_count, int r,
275                      bool cloud = false);
276     bool valid_aim(coord_def a) override;
277     bool set_aim(coord_def a) override;
278     aff_type is_affected(coord_def loc) override;
279     vector<ray_def> rays;
280     map<coord_def, size_t> zapped;
281 private:
282     size_t num_beams;
283     int range;
284     bool uses_clouds;
285 };
286 
287 class targeter_monster_sequence : public targeter_beam
288 {
289 public:
290     targeter_monster_sequence(const actor *act, int pow, int range);
291     bool set_aim(coord_def a);
292     bool valid_aim(coord_def a);
293     aff_type is_affected(coord_def loc);
294 private:
295     explosion_map exp_map;
296 };
297 
298 class targeter_passwall : public targeter_smite
299 {
300 public:
301     targeter_passwall(int max_range);
302     bool set_aim(coord_def a) override;
303     bool valid_aim(coord_def a) override;
304     aff_type is_affected(coord_def loc) override;
305     bool can_affect_outside_range() override;
306     bool can_affect_unseen() override;
307     bool affects_monster(const monster_info& mon) override;
308 
309 private:
310     unique_ptr<passwall_path> cur_path;
311 };
312 
313 class targeter_dig : public targeter_beam
314 {
315 public:
316     targeter_dig(int max_range);
317     bool valid_aim(coord_def a) override;
318     aff_type is_affected(coord_def loc) override;
319     bool can_affect_unseen() override;
320     bool can_affect_walls() override;
321     bool affects_monster(const monster_info& mon) override;
322 private:
323     map<coord_def, int> aim_test_cache;
324 };
325 
326 class targeter_overgrow: public targeter
327 {
328 public:
329     targeter_overgrow();
can_affect_walls()330     bool can_affect_walls() override { return true; }
331     bool valid_aim(coord_def a) override;
332     aff_type is_affected(coord_def loc) override;
333     bool set_aim(coord_def a) override;
334     set<coord_def> affected_positions;
335 private:
336     bool overgrow_affects_pos(const coord_def &p);
337 };
338 
339 class targeter_charge : public targeter
340 {
341 public:
342     targeter_charge(const actor *act, int range);
343     bool valid_aim(coord_def a) override;
344     bool set_aim(coord_def a) override;
345     aff_type is_affected(coord_def loc) override;
346 private:
347     int range;
348     vector<coord_def> path_taken; // Path the charge took.
349 };
350 
351 string bad_charge_target(coord_def a);
352 bool can_charge_through_mons(coord_def a);
353 
354 // a fixed los targeter matching how it is called for shatter, with a custom
355 // tweak to affect walls.
356 class targeter_shatter : public targeter_radius
357 {
358 public:
targeter_shatter(const actor * act)359     targeter_shatter(const actor *act) : targeter_radius(act, LOS_ARENA) { }
can_affect_walls()360     bool can_affect_walls() override { return true; }
361     aff_type is_affected(coord_def loc) override;
362 };
363 
364 // A fixed targeter for multi-position attacks, i.e. los stuff that
365 // affects various squares, or monsters non-locally. For los stuff that
366 // affects only monsters on a per-monster case basis see targeter_multimonster
367 class targeter_multiposition : public targeter
368 {
369 public:
370     targeter_multiposition(const actor *a, vector<coord_def> seeds,
371                            aff_type _positive=AFF_MAYBE);
372     targeter_multiposition(const actor *a, vector<monster *> seeds,
373                            aff_type _positive=AFF_MAYBE);
374     targeter_multiposition(const actor *a, initializer_list<coord_def> seeds,
375                            aff_type _positive=AFF_MAYBE);
376 
377     void add_position(const coord_def &c, bool force=false);
valid_aim(coord_def)378     bool valid_aim(coord_def) override { return true; }
379     aff_type is_affected(coord_def loc) override;
380 
381 protected:
382     set<coord_def> affected_positions;
383     aff_type positive;
384 };
385 
386 class targeter_chain_lightning : public targeter
387 {
388 public:
389     targeter_chain_lightning();
valid_aim(coord_def)390     bool valid_aim(coord_def) override { return true; }
391     aff_type is_affected(coord_def loc) override;
392 private:
393     set<coord_def> potential_victims;
394     set<coord_def> closest_victims;
395 };
396 
397 // A static targeter for Maxwell's Coupling
398 // that finds the closest monster using the absolute zero code.
399 class targeter_maxwells_coupling : public targeter_multiposition
400 {
401 public:
402     targeter_maxwells_coupling();
403 };
404 
405 class targeter_multifireball : public targeter_multiposition
406 {
407 public:
408     targeter_multifireball(const actor *a, vector<coord_def> seeds);
409 };
410 
411 // this is implemented a bit like multifireball, but with some tweaks
412 class targeter_ramparts : public targeter_multiposition
413 {
414 public:
415     targeter_ramparts(const actor *a);
416 
417     aff_type is_affected(coord_def loc) override;
can_affect_walls()418     bool can_affect_walls() override { return true; }
419 };
420 
421 // a class for fixed beams at some offset from the player
422 class targeter_starburst_beam : public targeter_beam
423 {
424 public:
425     targeter_starburst_beam(const actor *a, int _range, int pow, const coord_def &offset);
426     // this is a bit of ui hack: lets us set starburst beams even when the
427     // endpoint would be out of los
can_affect_unseen()428     bool can_affect_unseen() override { return true; }
valid_aim(coord_def)429     bool valid_aim(coord_def) override { return true; }
430 };
431 
432 class targeter_starburst : public targeter
433 {
434 public:
435     targeter_starburst(const actor *a, int range, int pow);
valid_aim(coord_def)436     bool valid_aim(coord_def) override { return true; }
437     aff_type is_affected(coord_def loc) override;
438     vector<targeter_starburst_beam> beams;
439 };
440 
441 // A targeter for Eringya's Noxious Bog that finds cells that can be bogged.
442 class targeter_bog : public targeter_multiposition
443 {
444 public:
445     targeter_bog(const actor *a, int pow);
446 };
447 
448 class targeter_ignite_poison : public targeter_multiposition
449 {
450 public:
451     targeter_ignite_poison(actor *a);
452 };
453 
454 class targeter_multimonster : public targeter
455 {
456 public:
457     targeter_multimonster(const actor *a);
458 
valid_aim(coord_def)459     bool valid_aim(coord_def) override { return true; }
460     aff_type is_affected(coord_def loc) override;
461 protected:
462     bool check_monster;
463 };
464 
465 class targeter_drain_life : public targeter_multimonster
466 {
467 public:
468     targeter_drain_life();
469     bool affects_monster(const monster_info& mon) override;
470 };
471 
472 class targeter_discord : public targeter_multimonster
473 {
474 public:
475     targeter_discord();
476     bool affects_monster(const monster_info& mon) override;
477 };
478 
479 class targeter_englaciate : public targeter_multimonster
480 {
481 public:
482     targeter_englaciate();
483     bool affects_monster(const monster_info& mon) override;
484 };
485 
486 class targeter_fear : public targeter_multimonster
487 {
488 public:
489     targeter_fear();
490     bool affects_monster(const monster_info& mon) override;
491 };
492 
493 class targeter_intoxicate : public targeter_multimonster
494 {
495 public:
496     targeter_intoxicate();
497     bool affects_monster(const monster_info& mon) override;
498 };
499