animation_inputs.cpp 6.0 KB

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