1 // Copyright 2014-2018 the openage authors. See copying.md for legal info.
2 
3 #pragma once
4 
5 #include <memory>
6 #include <vector>
7 
8 #include "../pathfinding/path.h"
9 #include "../gamestate/resource.h"
10 #include "attribute.h"
11 #include "research.h"
12 #include "unit.h"
13 #include "unit_container.h"
14 
15 namespace openage {
16 
17 class TerrainSearch;
18 
19 // TODO use a type instead of unsigned int for time
20 
21 /**
22  * A interval triggering timer used in actions.
23  * TODO find a better name for triggers
24  */
25 class IntervalTimer {
26 public:
27 
28 	/**
29 	 * Constructs a timer with a given interval
30 	 */
31 	IntervalTimer(unsigned int interval);
32 
33 	/**
34 	 * Constructs a timer with a given interval which will
35 	 * stop after a given number of triggers.
36 	 */
37 	IntervalTimer(unsigned int interval, int max_triggers);
38 
39 	void skip_to_trigger();
40 
41 	bool update(unsigned int time);
42 
43 	/**
44 	 * Returns the time until the next trigger
45 	 */
46 	unsigned int get_time_left() const;
47 
48 	float get_progress() const;
49 
50 	/**
51 	 * Returns true if at least one interval has passed.
52 	 */
53 	bool has_triggers() const;
54 
55 	/**
56 	 * Returns true if the interval passed have reached the max.
57 	 */
58 	bool finished() const;
59 
60 	/**
61 	 * Returns the number of intervals passed.
62 	 */
get_triggers()63 	int get_triggers() const { return this->triggers; }
64 
get_interval()65 	unsigned int get_interval() const { return this->interval; }
66 
set_interval(unsigned int interval)67 	void set_interval(unsigned int interval) { this->interval = interval; }
68 
69 private:
70 
71 	unsigned int interval;
72 
73 	int max_triggers;
74 
75 	unsigned int time_left;
76 
77 	int triggers;
78 
79 };
80 
81 
82 /**
83  * Actions can be pushed onto any units action stack
84  *
85  * Each update cycle will perform the update function of the
86  * action on top of this stack
87  */
88 class UnitAction {
89 public:
90 
91 	/**
92 	 * Require unit to be updated and an initial graphic type
93 	 */
94 	UnitAction(Unit *u, graphic_type initial_gt);
95 
~UnitAction()96 	virtual ~UnitAction() {}
97 
98 	/**
99 	 * type of graphic this action should use
100 	 */
101 	graphic_type type() const;
102 
103 	/**
104 	 * frame number to use on the current graphic
105 	 */
106 	float current_frame() const;
107 
108 	/**
109 	 * each action has its own update functionality which gets called when this
110 	 * is the active action
111 	 */
112 	virtual void update(unsigned int time) = 0;
113 
114 	/**
115 	 * action to perform when popped from a units action stack
116 	 */
117 	virtual void on_completion() = 0;
118 
119 	/**
120 	 *	gets called for all actions on stack each update cycle
121 	 *	@return true when action is completed so it and everything above it can be popped
122 	 */
123 	virtual bool completed() const = 0;
124 
125 	/**
126 	 * checks if the action can be interrupted, allowing it to be popped if the user
127 	 * specifies a new action, if false the action must reach a completed state
128 	 * before removal
129 	 * eg dead action must be completed and cannot be discarded
130 	 */
131 	virtual bool allow_interupt() const = 0;
132 
133 	/**
134 	 * control whether stack can discard the action automatically and
135 	 * should the stack be modifiable when this action is on top
136 	 *
137 	 * if true this action must complete and will not allow new actions
138 	 * to be pushed while it is active and also does not update the secondary actions
139 	 */
140 	virtual bool allow_control() const = 0;
141 
142 	/**
143 	 * debug string to identify action types
144 	 */
145 	virtual std::string name() const = 0;
146 
147 	/**
148 	 * determines which graphic should be used for drawing this unit
149 	 * finds the default graphic using the units type, used by most actions
150 	 *
151 	 * this virtual function is overriden for special cases such as
152 	 * villager task graphics
153 	 */
154 	virtual const graphic_set &current_graphics() const;
155 
156 	void draw_debug(const Engine &engine);
157 
158 	/**
159 	 * common functions for actions
160 	 */
161 	void face_towards(const coord::phys3 pos);
162 
163 	/**
164 	 * Damage a unit, returns true if the unit was killed in the process
165 	 */
166 	bool damage_unit(Unit &target);
167 
168 	void move_to(Unit &target, bool use_range=true);
169 
170 	/**
171 	 * produce debug info such as visualising paths
172 	 */
173 	static bool show_debug;
174 
175 	/**
176 	 * a small distance to which units are considered touching
177 	 * when within this distance
178 	 */
179 	static coord::phys_t adjacent_range(Unit *u);
180 
181 	/**
182 	 * looks at an ranged attributes on the unit
183 	 * otherwise returns same as adjacent_range()
184 	 */
185 	static coord::phys_t get_attack_range(Unit *u);
186 
187 	/**
188 	 * looks at heal attribute on the unit
189 	 * otherwise returns same as adjacent_range()
190 	 */
191 	static coord::phys_t get_heal_range(Unit *u);
192 
193 protected:
194 	/**
195 	 * the entity being updated
196 	 */
197 	Unit *entity;
198 
199 	/**
200 	 * common graphic controls
201 	 */
202 	graphic_type graphic;
203 	float frame;
204 	float frame_rate;
205 
206 	/**
207 	 * additional drawing for debug purposes
208 	 */
209 	std::function<void(const Engine &)> debug_draw_action;
210 };
211 
212 /**
213  * Base class for actions which target another unit such as
214  * gather, attack, heal and convert
215  * TODO implement min range
216  */
217 class TargetAction: public UnitAction {
218 public:
219 
220 	/**
221 	 * action_rad is how close a unit must come to another
222 	 * unit to be considered to touch the other, for example in
223 	 * gathering resource and melee attack
224 	 */
225 	TargetAction(Unit *e, graphic_type gt, UnitReference r, coord::phys_t action_rad);
226 
227 	/**
228 	 * this constructor uses the default action radius formula which will
229 	 * bring the object as near to the target as the pathing grid will allow.
230 	 */
231 	TargetAction(Unit *e, graphic_type gt, UnitReference r);
~TargetAction()232 	virtual ~TargetAction() {}
233 
234 	void update(unsigned int time) override;
235 	void on_completion() override;
236 	bool completed() const override;
allow_interupt()237 	bool allow_interupt() const override { return true; }
allow_control()238 	bool allow_control() const override { return true; }
239 	virtual std::string name() const override = 0;
240 
241 	/**
242 	 * Control units action when in range of the target
243 	 */
244 	virtual void update_in_range(unsigned int, Unit *) = 0;
245 	virtual void on_completion_in_range(int target_type) = 0;
246 	virtual bool completed_in_range(Unit *) const = 0;
247 
248 	coord::phys_t distance_to_target();
249 	Unit *update_distance();
250 
251 	UnitReference get_target() const;
252 	int get_target_type_id() const;
253 
254 	/**
255 	 * changes target, ending action when new target is invalid
256 	 */
257 	void set_target(UnitReference new_target);
258 
259 private:
260 	UnitReference target;
261 	int target_type_id;
262 	int repath_attempts;
263 	bool end_action;
264 
265 	/**
266 	 * tracks distance to target from last update
267 	 */
268 	coord::phys_t dist_to_target, radius;
269 
270 };
271 
272 /**
273  * plays a fixed number of frames for the units dying animation
274  */
275 class DecayAction: public UnitAction {
276 public:
277 	DecayAction(Unit *e);
~DecayAction()278 	virtual ~DecayAction() {}
279 
280 	void update(unsigned int time) override;
281 	void on_completion() override;
282 	bool completed() const override;
allow_interupt()283 	bool allow_interupt() const override { return false; }
allow_control()284 	bool allow_control() const override { return false; }
name()285 	std::string name() const override { return "decay"; }
286 
287 private:
288 	float end_frame;
289 
290 };
291 
292 /**
293  * plays a fixed number of frames for the units dying animation
294  */
295 class DeadAction: public UnitAction {
296 public:
297 	DeadAction(Unit *e, std::function<void()> on_complete=[]() {});
~DeadAction()298 	virtual ~DeadAction() {}
299 
300 	void update(unsigned int time) override;
301 	void on_completion() override;
302 	bool completed() const override;
allow_interupt()303 	bool allow_interupt() const override { return false; }
allow_control()304 	bool allow_control() const override { return false; }
name()305 	std::string name() const override { return "dead"; }
306 
307 private:
308 	float end_frame;
309 	std::function<void()> on_complete_func;
310 
311 };
312 
313 /**
314  * places an idle action on the stack once building is complete
315  */
316 class FoundationAction: public UnitAction {
317 public:
318 	FoundationAction(Unit *e, bool add_destuction=false);
~FoundationAction()319 	virtual ~FoundationAction() {}
320 
321 	void update(unsigned int time) override;
322 	void on_completion() override;
323 	bool completed() const override;
allow_interupt()324 	bool allow_interupt() const override { return true; }
allow_control()325 	bool allow_control() const override { return false; }
name()326 	std::string name() const override { return "foundation"; }
327 
328 private:
329 	bool add_destruct_effect, cancel;
330 
331 };
332 
333 /**
334  * keeps an entity in a fixed position
335  */
336 class IdleAction: public UnitAction {
337 public:
338 	IdleAction(Unit *e);
~IdleAction()339 	virtual ~IdleAction() {}
340 
341 	void update(unsigned int time) override;
342 	void on_completion() override;
343 	bool completed() const override;
allow_interupt()344 	bool allow_interupt() const override { return false; }
allow_control()345 	bool allow_control() const override { return true; }
name()346 	std::string name() const override { return "idle"; }
347 
348 private:
349 	// look for auto task actions
350 	std::shared_ptr<TerrainSearch> search;
351 	ability_set auto_abilities;
352 
353 };
354 
355 /**
356  * moves an entity to another location
357  */
358 class MoveAction: public UnitAction {
359 public:
360 	/**
361 	 * moves unit to a given fixed location
362 	 */
363 	MoveAction(Unit *e, coord::phys3 tar, bool repath=true);
364 
365 	/**
366 	 * moves a unit to within a distance to another unit
367 	 */
368 	MoveAction(Unit *e, UnitReference tar, coord::phys_t within_range);
369 	virtual ~MoveAction();
370 
371 	void update(unsigned int time) override;
372 	void on_completion() override;
373 	bool completed() const override;
allow_interupt()374 	bool allow_interupt() const override { return true; }
allow_control()375 	bool allow_control() const override { return true; }
name()376 	std::string name() const override { return "move"; }
377 
378 	coord::phys3 next_waypoint() const;
379 
380 private:
381 	UnitReference unit_target;
382 	coord::phys3 target;
383 
384 	// how near the units should come to target
385 	coord::phys_t distance_to_target, radius;
386 
387 	path::Path path;
388 
389 	// should a new path be found if unit gets blocked
390 	bool allow_repath, end_action;
391 
392 	void initialise();
393 
394 	/**
395 	 * use a star to find a path to target
396 	 */
397 	void set_path();
398 
399 	/**
400 	 * updates the distance_to_target value
401 	 */
402 	void set_distance();
403 };
404 
405 /**
406  * garrison inside a building
407  */
408 class GarrisonAction: public TargetAction {
409 public:
410 	GarrisonAction(Unit *e, UnitReference build);
~GarrisonAction()411 	virtual ~GarrisonAction() {}
412 
413 	void update_in_range(unsigned int time, Unit *target_unit) override;
on_completion_in_range(int)414 	void on_completion_in_range(int) override {}
completed_in_range(Unit *)415 	bool completed_in_range(Unit *) const override { return this->complete; }
name()416 	std::string name() const override { return "garrison"; }
417 
418 private:
419 	bool complete;
420 };
421 
422 /**
423  * garrison inside a building
424  */
425 class UngarrisonAction: public UnitAction {
426 public:
427 	UngarrisonAction(Unit *e, const coord::phys3 &pos);
~UngarrisonAction()428 	virtual ~UngarrisonAction() {}
429 
430 	void update(unsigned int time) override;
431 	void on_completion() override;
completed()432 	bool completed() const override { return this->complete; }
allow_interupt()433 	bool allow_interupt() const override { return true; }
allow_control()434 	bool allow_control() const override { return true; }
name()435 	std::string name() const override { return "ungarrison"; }
436 
437 private:
438 	coord::phys3 position;
439 	bool complete;
440 };
441 
442 /**
443  * trains a new unit
444  */
445 class TrainAction: public UnitAction {
446 public:
447 	TrainAction(Unit *e, UnitType *pp);
~TrainAction()448 	virtual ~TrainAction() {}
449 
450 	void update(unsigned int time) override;
451 	void on_completion() override;
completed()452 	bool completed() const override { return this->complete; }
allow_interupt()453 	bool allow_interupt() const override { return false; }
allow_control()454 	bool allow_control() const override { return true; }
name()455 	std::string name() const override { return "train"; }
456 
get_progress()457 	float get_progress() const { return this->timer.get_progress(); }
458 
459 private:
460 	UnitType *trained;
461 
462 	IntervalTimer timer;
463 	bool started;
464 	bool complete;
465 };
466 
467 /**
468  * trains a new unit
469  */
470 class ResearchAction: public UnitAction {
471 public:
472 	ResearchAction(Unit *e, Research *research);
~ResearchAction()473 	virtual ~ResearchAction() {}
474 
475 	void update(unsigned int time) override;
476 	void on_completion() override;
completed()477 	bool completed() const override { return this->complete; }
allow_interupt()478 	bool allow_interupt() const override { return false; }
allow_control()479 	bool allow_control() const override { return true; }
name()480 	std::string name() const override { return "train"; }
481 
get_progress()482 	float get_progress() const { return this->timer.get_progress(); }
get_research_type()483 	const ResearchType* get_research_type() const { return this->research->type; }
484 
485 private:
486 
487 	Research *research;
488 
489 	IntervalTimer timer;
490 	bool complete;
491 };
492 
493 /**
494  * builds a building
495  */
496 class BuildAction: public TargetAction {
497 public:
498 	BuildAction(Unit *e, UnitReference foundation);
~BuildAction()499 	virtual ~BuildAction() {}
500 
501 	void update_in_range(unsigned int time, Unit *target_unit) override;
on_completion_in_range(int)502 	void on_completion_in_range(int) override {}
completed_in_range(Unit *)503 	bool completed_in_range(Unit *) const override { return this->complete >= 1.0f; }
504 	void on_completion() override;
name()505 	std::string name() const override { return "build"; }
506 
get_progress()507 	float get_progress() const { return this->complete; }
508 
509 private:
510 	float complete, build_rate;
511 	static constexpr float search_tile_distance = 9.0f;
512 
513 };
514 
515 /**
516  * repairs a unit
517  */
518 class RepairAction: public TargetAction {
519 public:
520 	RepairAction(Unit *e, UnitReference tar);
~RepairAction()521 	virtual ~RepairAction() {}
522 
523 	void update_in_range(unsigned int time, Unit *target_unit) override;
on_completion_in_range(int)524 	void on_completion_in_range(int) override {}
completed_in_range(Unit *)525 	bool completed_in_range(Unit *) const override { return this->complete; }
name()526 	std::string name() const override { return "repair"; }
527 
528 private:
529 
530 	/**
531 	 * stores the cost of the repair for 1hp
532 	 */
533 	ResourceBundle cost;
534 
535 	IntervalTimer timer;
536 	bool complete;
537 };
538 
539 /**
540  * gathers resource from another object
541  */
542 class GatherAction: public TargetAction {
543 public:
544 	GatherAction(Unit *e, UnitReference tar);
545 	virtual ~GatherAction();
546 
547 	void update_in_range(unsigned int time, Unit *target_unit) override;
548 	void on_completion_in_range(int target_type) override;
completed_in_range(Unit *)549 	bool completed_in_range(Unit *) const override { return this->complete; }
name()550 	std::string name() const override { return "gather"; }
551 
552 private:
553 	bool complete, target_resource;
554 	UnitReference target;
555 	gamedata::unit_classes resource_class;
556 	UnitReference nearest_dropsite(game_resource res_type);
557 };
558 
559 /**
560  * attacks another unit
561  */
562 class AttackAction: public TargetAction {
563 public:
564 	AttackAction(Unit *e, UnitReference tar);
565 	virtual ~AttackAction();
566 
567 	void update_in_range(unsigned int time, Unit *target_unit) override;
on_completion_in_range(int)568 	void on_completion_in_range(int) override {}
569 	bool completed_in_range(Unit *) const override;
name()570 	std::string name() const override { return "attack"; }
571 
572 private:
573 
574 	IntervalTimer timer;
575 
576 	/**
577 	 * use attack action
578 	 */
579 	void attack(Unit &target);
580 
581 	/**
582 	 * add a projectile game object which moves towards the target
583 	 */
584 	void fire_projectile(const Attribute<attr_type::attack> &att, const coord::phys3 &target);
585 };
586 
587 /**
588  * heals another unit
589  */
590 class HealAction: public TargetAction {
591 public:
592 	HealAction(Unit *e, UnitReference tar);
593 	virtual ~HealAction();
594 
595 	void update_in_range(unsigned int time, Unit *target_unit) override;
on_completion_in_range(int)596 	void on_completion_in_range(int) override {}
597 	bool completed_in_range(Unit *) const override;
name()598 	std::string name() const override { return "heal"; }
599 
600 private:
601 
602 	IntervalTimer timer;
603 
604 	/**
605 	 * use heal action
606 	 */
607 	void heal(Unit &target);
608 };
609 
610 /**
611  * convert an object
612  */
613 class ConvertAction: public TargetAction {
614 public:
615 	ConvertAction(Unit *e, UnitReference tar);
~ConvertAction()616 	virtual ~ConvertAction() {}
617 
618 	void update_in_range(unsigned int time, Unit *target_unit) override;
on_completion_in_range(int)619 	void on_completion_in_range(int) override {}
completed_in_range(Unit *)620 	bool completed_in_range(Unit *) const override { return this->complete >= 1.0f; }
name()621 	std::string name() const override { return "convert"; }
622 
623 private:
624 	float complete;
625 
626 };
627 
628 /**
629  * moves object to fly in a parabolic shape
630  */
631 class ProjectileAction: public UnitAction {
632 public:
633 	ProjectileAction(Unit *e, coord::phys3 target);
634 	virtual ~ProjectileAction();
635 
636 	void update(unsigned int time) override;
637 	void on_completion() override;
638 	bool completed() const override;
allow_interupt()639 	bool allow_interupt() const override { return false; }
allow_control()640 	bool allow_control() const override { return false; }
name()641 	std::string name() const override { return "projectile"; }
642 
643 private:
644 	double grav;
645 	bool has_hit;
646 };
647 
648 } // namespace openage
649