animation_inputs.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. #include "animation_inputs.h"
  2. #include "../../../../game/core/component.h"
  3. #include "../../../../game/core/entity.h"
  4. #include "../../../../game/core/world.h"
  5. #include "../../../entity/registry.h"
  6. #include <algorithm>
  7. #include <cmath>
  8. namespace Render::GL {
  9. namespace {
  10. auto map_combat_state_to_phase(Engine::Core::CombatAnimationState state)
  11. -> CombatAnimPhase {
  12. switch (state) {
  13. case Engine::Core::CombatAnimationState::Advance:
  14. return CombatAnimPhase::Advance;
  15. case Engine::Core::CombatAnimationState::WindUp:
  16. return CombatAnimPhase::WindUp;
  17. case Engine::Core::CombatAnimationState::Strike:
  18. return CombatAnimPhase::Strike;
  19. case Engine::Core::CombatAnimationState::Impact:
  20. return CombatAnimPhase::Impact;
  21. case Engine::Core::CombatAnimationState::Recover:
  22. return CombatAnimPhase::Recover;
  23. case Engine::Core::CombatAnimationState::Reposition:
  24. return CombatAnimPhase::Reposition;
  25. case Engine::Core::CombatAnimationState::Idle:
  26. default:
  27. return CombatAnimPhase::Idle;
  28. }
  29. }
  30. } // namespace
  31. auto sample_anim_state(const DrawContext &ctx) -> AnimationInputs {
  32. AnimationInputs anim{};
  33. anim.time = ctx.animation_time;
  34. anim.is_moving = false;
  35. anim.is_running = false;
  36. anim.is_attacking = false;
  37. anim.is_melee = false;
  38. anim.is_in_hold_mode = false;
  39. anim.is_exiting_hold = false;
  40. anim.hold_exit_progress = 0.0F;
  41. anim.combat_phase = CombatAnimPhase::Idle;
  42. anim.combat_phase_progress = 0.0F;
  43. anim.attack_variant = 0;
  44. anim.is_hit_reacting = false;
  45. anim.hit_reaction_intensity = 0.0F;
  46. if (ctx.entity == nullptr) {
  47. return anim;
  48. }
  49. if (ctx.entity->has_component<Engine::Core::PendingRemovalComponent>()) {
  50. return anim;
  51. }
  52. auto *movement = ctx.entity->get_component<Engine::Core::MovementComponent>();
  53. auto *attack = ctx.entity->get_component<Engine::Core::AttackComponent>();
  54. auto *attack_target =
  55. ctx.entity->get_component<Engine::Core::AttackTargetComponent>();
  56. auto *transform =
  57. ctx.entity->get_component<Engine::Core::TransformComponent>();
  58. auto *hold_mode =
  59. ctx.entity->get_component<Engine::Core::HoldModeComponent>();
  60. auto *combat_state =
  61. ctx.entity->get_component<Engine::Core::CombatStateComponent>();
  62. auto *hit_feedback =
  63. ctx.entity->get_component<Engine::Core::HitFeedbackComponent>();
  64. const auto *stamina =
  65. ctx.entity->get_component<Engine::Core::StaminaComponent>();
  66. anim.is_in_hold_mode = ((hold_mode != nullptr) && hold_mode->active);
  67. if ((hold_mode != nullptr) && !hold_mode->active &&
  68. hold_mode->exit_cooldown > 0.0F) {
  69. anim.is_exiting_hold = true;
  70. anim.hold_exit_progress =
  71. 1.0F - (hold_mode->exit_cooldown / hold_mode->stand_up_duration);
  72. }
  73. anim.is_moving = ((movement != nullptr) && movement->has_target);
  74. anim.is_running = (stamina != nullptr) && stamina->is_running;
  75. auto *healer = ctx.entity->get_component<Engine::Core::HealerComponent>();
  76. if (healer != nullptr && healer->is_healing_active && transform != nullptr) {
  77. anim.is_healing = true;
  78. anim.healing_target_dx = healer->healing_target_x - transform->position.x;
  79. anim.healing_target_dz = healer->healing_target_z - transform->position.z;
  80. }
  81. auto *builder_prod =
  82. ctx.entity->get_component<Engine::Core::BuilderProductionComponent>();
  83. if (builder_prod != nullptr) {
  84. if (builder_prod->bypass_movement_active) {
  85. anim.is_moving = true;
  86. }
  87. if (builder_prod->in_progress) {
  88. anim.is_constructing = true;
  89. if (builder_prod->build_time > 0.0F) {
  90. anim.construction_progress =
  91. 1.0F - (builder_prod->time_remaining / builder_prod->build_time);
  92. }
  93. }
  94. }
  95. if (combat_state != nullptr) {
  96. anim.combat_phase =
  97. map_combat_state_to_phase(combat_state->animation_state);
  98. if (combat_state->state_duration > 0.0F) {
  99. anim.combat_phase_progress =
  100. combat_state->state_time / combat_state->state_duration;
  101. }
  102. anim.attack_variant = combat_state->attack_variant;
  103. }
  104. if (hit_feedback != nullptr && hit_feedback->is_reacting) {
  105. anim.is_hit_reacting = true;
  106. float const progress =
  107. hit_feedback->reaction_time /
  108. Engine::Core::HitFeedbackComponent::kReactionDuration;
  109. anim.hit_reaction_intensity =
  110. hit_feedback->reaction_intensity * std::max(0.0F, 1.0F - progress);
  111. }
  112. if ((attack != nullptr) && (attack_target != nullptr) &&
  113. attack_target->target_id > 0 && (transform != nullptr)) {
  114. anim.is_melee = (attack->current_mode ==
  115. Engine::Core::AttackComponent::CombatMode::Melee);
  116. bool const stationary = !anim.is_moving;
  117. float const current_cooldown =
  118. anim.is_melee ? attack->melee_cooldown : attack->cooldown;
  119. bool const recently_fired =
  120. attack->time_since_last < std::min(current_cooldown, 0.45F);
  121. bool target_in_range = false;
  122. if (ctx.world != nullptr) {
  123. auto *target = ctx.world->get_entity(attack_target->target_id);
  124. if (target != nullptr) {
  125. auto *target_transform =
  126. target->get_component<Engine::Core::TransformComponent>();
  127. if (target_transform != nullptr) {
  128. float const dx = target_transform->position.x - transform->position.x;
  129. float const dz = target_transform->position.z - transform->position.z;
  130. float const dist_squared = dx * dx + dz * dz;
  131. float target_radius = 0.0F;
  132. if (target->has_component<Engine::Core::BuildingComponent>()) {
  133. target_radius =
  134. std::max(target_transform->scale.x, target_transform->scale.z) *
  135. 0.5F;
  136. } else {
  137. target_radius =
  138. std::max(target_transform->scale.x, target_transform->scale.z) *
  139. 0.5F;
  140. }
  141. float const effective_range = attack->range + target_radius + 0.25F;
  142. target_in_range = (dist_squared <= effective_range * effective_range);
  143. }
  144. }
  145. }
  146. anim.is_attacking = stationary && (target_in_range || recently_fired);
  147. }
  148. return anim;
  149. }
  150. } // namespace Render::GL