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 ¤t_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