💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

132 lines
5.0 KiB

  1. /*
  2. * Copyright (C) 2023 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "game/systems/reproductive-system.hpp"
  20. #include "game/components/ovary-component.hpp"
  21. #include "game/components/scene-component.hpp"
  22. #include "game/components/pose-component.hpp"
  23. #include "game/components/rigid-body-component.hpp"
  24. #include "game/components/egg-component.hpp"
  25. #include "game/components/ant-genome-component.hpp"
  26. #include <engine/math/fract.hpp>
  27. #include <engine/math/interpolation.hpp>
  28. #include <engine/scene/static-mesh.hpp>
  29. #include <engine/debug/log.hpp>
  30. #include <execution>
  31. reproductive_system::reproductive_system(entity::registry& registry):
  32. updatable_system(registry)
  33. {}
  34. void reproductive_system::update(float t, float dt)
  35. {
  36. auto ovary_group = registry.group<ovary_component>(entt::get<ant_genome_component, rigid_body_component, scene_component, pose_component>);
  37. std::for_each
  38. (
  39. std::execution::seq,
  40. ovary_group.begin(),
  41. ovary_group.end(),
  42. [&](auto entity_id)
  43. {
  44. auto& ovary = ovary_group.get<ovary_component>(entity_id);
  45. // Produce eggs
  46. if (ovary.egg_count < ovary.egg_capacity)
  47. {
  48. ovary.elapsed_egg_production_time += dt * m_time_scale;
  49. if (ovary.elapsed_egg_production_time >= ovary.egg_production_duration)
  50. {
  51. ovary.egg_count += static_cast<std::uint16_t>(ovary.elapsed_egg_production_time / ovary.egg_production_duration);
  52. ovary.egg_count = std::min(ovary.egg_count, ovary.egg_capacity);
  53. ovary.elapsed_egg_production_time = math::fract(ovary.elapsed_egg_production_time);
  54. }
  55. }
  56. // Oviposit egg
  57. if (ovary.ovipositor_egg_eid != entt::null || (ovary.ovipositing && ovary.egg_count))
  58. {
  59. // Get transform of ovipositor
  60. const auto& ovipositor_rigid_body = *ovary_group.get<rigid_body_component>(entity_id).body;
  61. const auto& ovipositor_pose = ovary_group.get<pose_component>(entity_id);
  62. const auto ovipositor_transform = ovipositor_rigid_body.get_transform() * ovipositor_pose.current_pose.get_absolute_transform(ovary.ovipositor_bone);
  63. // Advance oviposition time
  64. if (ovary.ovipositing)
  65. {
  66. ovary.elapsed_oviposition_time += dt * m_time_scale;
  67. }
  68. else
  69. {
  70. ovary.elapsed_oviposition_time -= dt * m_time_scale;
  71. ovary.elapsed_oviposition_time = std::max(0.0f, ovary.elapsed_oviposition_time);
  72. }
  73. // Determine position and orientation of egg
  74. const float t = std::min(ovary.elapsed_oviposition_time / ovary.oviposition_duration, 1.0f);
  75. auto egg_transform = ovipositor_transform;
  76. egg_transform.translation = egg_transform * math::lerp(ovary.oviposition_path.a, ovary.oviposition_path.b, t);
  77. if (ovary.ovipositor_egg_eid == entt::null)
  78. {
  79. // Get genome of parent entity
  80. const auto& parent_genome = ovary_group.get<ant_genome_component>(entity_id);
  81. // Get scene component of ovipositing entity
  82. const auto& ovipositor_scene = ovary_group.get<scene_component>(entity_id);
  83. // Construct egg rigid body
  84. auto egg_rigid_body = std::make_unique<physics::rigid_body>();
  85. egg_rigid_body->set_mass(0.0f);
  86. egg_rigid_body->set_transform(egg_transform);
  87. egg_rigid_body->set_previous_transform(egg_transform);
  88. // Construct egg scene object
  89. auto egg_scene_object = std::make_shared<scene::static_mesh>(parent_genome.genome->egg->phenes.front().model);
  90. // Construct egg entity
  91. ovary.ovipositor_egg_eid = registry.create();
  92. registry.emplace<rigid_body_component>(ovary.ovipositor_egg_eid, std::move(egg_rigid_body));
  93. registry.emplace<scene_component>(ovary.ovipositor_egg_eid, std::move(egg_scene_object), ovipositor_scene.layer_mask);
  94. registry.emplace<ant_genome_component>(ovary.ovipositor_egg_eid, parent_genome);
  95. }
  96. else
  97. {
  98. // Update position of egg rigid body
  99. auto& egg_rigid_body = *registry.get<rigid_body_component>(ovary.ovipositor_egg_eid).body;
  100. egg_rigid_body.set_transform(egg_transform);
  101. }
  102. if (ovary.elapsed_oviposition_time >= ovary.oviposition_duration)
  103. {
  104. // Construct egg component
  105. egg_component egg;
  106. egg.incubation_period = 5.0f;
  107. registry.emplace<egg_component>(ovary.ovipositor_egg_eid, std::move(egg));
  108. // Oviposition complete
  109. ovary.ovipositing = false;
  110. ovary.elapsed_oviposition_time = 0.0f;
  111. --ovary.egg_count;
  112. ovary.ovipositor_egg_eid = entt::null;
  113. }
  114. }
  115. }
  116. );
  117. }