💿🐜 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.

947 lines
33 KiB

  1. /*
  2. * Copyright (C) 2021 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/state/nuptial-flight.hpp"
  20. #include "game/state/pause-menu.hpp"
  21. #include "entity/archetype.hpp"
  22. #include "entity/systems/camera.hpp"
  23. #include "entity/systems/astronomy.hpp"
  24. #include "entity/components/locomotion.hpp"
  25. #include "entity/components/transform.hpp"
  26. #include "entity/components/terrain.hpp"
  27. #include "entity/components/camera.hpp"
  28. #include "entity/components/model.hpp"
  29. #include "entity/components/constraints/spring-to.hpp"
  30. #include "entity/components/constraints/three-dof.hpp"
  31. #include "entity/components/constraint-stack.hpp"
  32. #include "entity/commands.hpp"
  33. #include "animation/screen-transition.hpp"
  34. #include "animation/ease.hpp"
  35. #include "resources/resource-manager.hpp"
  36. #include "game/world.hpp"
  37. #include "application.hpp"
  38. #include "render/passes/clear-pass.hpp"
  39. #include "render/passes/ground-pass.hpp"
  40. #include "state-machine.hpp"
  41. #include "config.hpp"
  42. #include "game/load.hpp"
  43. #include "game/ant/breed.hpp"
  44. #include "game/ant/morphogenesis.hpp"
  45. using namespace game::ant;
  46. namespace game {
  47. namespace state {
  48. nuptial_flight::nuptial_flight(game::context& ctx):
  49. game::state::base(ctx)
  50. {
  51. ctx.logger->push_task("Entering nuptial flight state");
  52. // Allocate ant breed
  53. ant::breed breed;
  54. // Load morphological traits
  55. breed.head = ctx.resource_manager->load<ant::trait::head>("square-harvester-head.dna");
  56. breed.mandibles = ctx.resource_manager->load<ant::trait::mandibles>("harvester-mandibles.dna");
  57. breed.antennae = ctx.resource_manager->load<ant::trait::antennae>("slender-antennae.dna");
  58. breed.eyes = ctx.resource_manager->load<ant::trait::eyes>("oval-eyes.dna");
  59. breed.mesosoma = ctx.resource_manager->load<ant::trait::mesosoma>("humpback-mesosoma.dna");
  60. breed.legs = ctx.resource_manager->load<ant::trait::legs>("trekking-legs.dna");
  61. breed.waist = ctx.resource_manager->load<ant::trait::waist>("harvester-waist.dna");
  62. breed.gaster = ctx.resource_manager->load<ant::trait::gaster>("ovoid-gaster.dna");
  63. breed.ocelli = ctx.resource_manager->load<ant::trait::ocelli>("trinocular-fisheye-ocelli.dna");
  64. breed.sting = ctx.resource_manager->load<ant::trait::sting>("sting-absent.dna");
  65. breed.sculpturing = ctx.resource_manager->load<ant::trait::sculpturing>("politus-sculpturing.dna");
  66. breed.pigmentation = ctx.resource_manager->load<ant::trait::pigmentation>("rust-pigmentation.dna");
  67. breed.egg = ctx.resource_manager->load<ant::trait::egg>("ellipsoid-egg.dna");
  68. breed.larva = ctx.resource_manager->load<ant::trait::larva>("old-larva.dna");
  69. breed.cocoon = ctx.resource_manager->load<ant::trait::cocoon>("cocoon-present.dna");
  70. breed.pilosity = ctx.resource_manager->load<ant::trait::pilosity>("hairless-pilosity.dna");
  71. breed.forewings = nullptr;
  72. breed.hindwings = nullptr;
  73. // Load behavioral traits
  74. breed.foraging_time = ctx.resource_manager->load<ant::trait::foraging_time>("crepuscular-foraging-time.dna");
  75. breed.diet = nullptr;
  76. breed.nest = ctx.resource_manager->load<ant::trait::nest>("hypogeic-nest.dna");
  77. // Build caste models
  78. render::model* worker_model = ant::morphogenesis(breed, ant::caste::worker);
  79. // Disable UI color clear
  80. ctx.ui_clear_pass->set_cleared_buffers(false, true, false);
  81. // Create world if not yet created
  82. if (ctx.entities.find("planet") == ctx.entities.end())
  83. {
  84. game::world::create_stars(ctx);
  85. game::world::create_sun(ctx);
  86. game::world::create_planet(ctx);
  87. game::world::create_moon(ctx);
  88. // Set time to solar noon
  89. game::world::set_time(ctx, 0.3);
  90. // Freeze time
  91. game::world::set_time_scale(ctx, 0.0);
  92. }
  93. // Load biome
  94. game::load::biome(ctx, "desert-scrub.bio");
  95. // Setup and enable sky and ground passes
  96. ctx.sky_pass->set_enabled(true);
  97. ctx.ground_pass->set_enabled(true);
  98. // Create color checker
  99. {
  100. entity::archetype* color_checker_archetype = ctx.resource_manager->load<entity::archetype>("color-checker.ent");
  101. auto color_checker_eid = color_checker_archetype->create(*ctx.entity_registry);
  102. entity::command::warp_to(*ctx.entity_registry, color_checker_eid, {0, 0, -10});
  103. }
  104. // Create ruler
  105. {
  106. entity::archetype* ruler_10cm_archetype = ctx.resource_manager->load<entity::archetype>("ruler-10cm.ent");
  107. auto ruler_10cm_eid = ruler_10cm_archetype->create(*ctx.entity_registry);
  108. entity::command::warp_to(*ctx.entity_registry, ruler_10cm_eid, {0, 0, 10});
  109. }
  110. // Create keeper if not yet created
  111. if (ctx.entities.find("keeper") == ctx.entities.end())
  112. {
  113. entity::id keeper_eid = ctx.entity_registry->create();
  114. ctx.entities["keeper"] = keeper_eid;
  115. }
  116. // Create ant if not created
  117. if (ctx.entities.find("ant") == ctx.entities.end())
  118. {
  119. auto boid_eid = ctx.entity_registry->create();
  120. entity::component::model model;
  121. model.render_model = worker_model;//ctx.resource_manager->load<render::model>("ant-test.mdl");
  122. model.instance_count = 0;
  123. model.layers = 1;
  124. ctx.entity_registry->assign<entity::component::model>(boid_eid, model);
  125. entity::component::transform transform;
  126. transform.local = math::identity_transform<float>;
  127. transform.world = math::identity_transform<float>;
  128. transform.warp = true;
  129. ctx.entity_registry->assign<entity::component::transform>(boid_eid, transform);
  130. entity::component::locomotion locomotion;
  131. locomotion.yaw = 0.0f;
  132. ctx.entity_registry->assign<entity::component::locomotion>(boid_eid, locomotion);
  133. entity::command::warp_to(*ctx.entity_registry, boid_eid, {0, 2, 0});
  134. // Set target ant
  135. ctx.entities["ant"] = boid_eid;
  136. }
  137. // Start as ant-keeper
  138. is_keeper = true;
  139. // Setup camera
  140. setup_camera();
  141. // Queue fade in
  142. ctx.fade_transition_color->set_value({1, 1, 1});
  143. ctx.function_queue.push(std::bind(&screen_transition::transition, ctx.fade_transition, config::nuptial_flight_fade_in_duration, true, ease<float>::out_sine, true, nullptr));
  144. // Queue control setup
  145. ctx.function_queue.push(std::bind(&nuptial_flight::enable_keeper_controls, this));
  146. ctx.logger->pop_task(EXIT_SUCCESS);
  147. }
  148. nuptial_flight::~nuptial_flight()
  149. {
  150. ctx.logger->push_task("Exiting nuptial flight state");
  151. ctx.logger->pop_task(EXIT_SUCCESS);
  152. }
  153. void nuptial_flight::setup_camera()
  154. {
  155. // Switch to surface camera
  156. ctx.underground_camera->set_active(false);
  157. ctx.surface_camera->set_active(true);
  158. // Create surface camera entity
  159. if (!ctx.entities.count("surface_cam"))
  160. {
  161. // Create camera target entity
  162. entity::id target_eid = ctx.entity_registry->create();
  163. ctx.entities["surface_cam_target"] = target_eid;
  164. {
  165. // Transform
  166. entity::component::transform target_transform;
  167. target_transform.local = math::identity_transform<float>;
  168. target_transform.world = target_transform.local;
  169. target_transform.warp = true;
  170. ctx.entity_registry->assign<entity::component::transform>(target_eid, target_transform);
  171. }
  172. // Create camera entity
  173. entity::id camera_eid = ctx.entity_registry->create();
  174. ctx.entities["surface_cam"] = camera_eid;
  175. // Create camera transform component
  176. entity::component::transform transform;
  177. transform.local = math::identity_transform<float>;
  178. transform.world = transform.local;
  179. transform.warp = true;
  180. ctx.entity_registry->assign<entity::component::transform>(camera_eid, transform);
  181. // Create camera camera component
  182. entity::component::camera camera;
  183. camera.object = ctx.surface_camera;
  184. ctx.entity_registry->assign<entity::component::camera>(camera_eid, camera);
  185. // Create camera 3DOF constraint entity
  186. entity::id three_dof_constraint_eid = ctx.entity_registry->create();
  187. ctx.entities["surface_cam_3dof"] = three_dof_constraint_eid;
  188. {
  189. // Create 3DOF to constraint
  190. entity::component::constraint::three_dof three_dof;
  191. three_dof.yaw = 0.0f;
  192. three_dof.pitch = 0.0f;
  193. three_dof.roll = 0.0f;
  194. ctx.entity_registry->assign<entity::component::constraint::three_dof>(three_dof_constraint_eid, three_dof);
  195. // Create constraint stack node component
  196. entity::component::constraint_stack_node node;
  197. node.active = true;
  198. node.weight = 1.0f;
  199. node.next = entt::null;
  200. ctx.entity_registry->assign<entity::component::constraint_stack_node>(three_dof_constraint_eid, node);
  201. }
  202. // Create camera spring to constraint entity
  203. entity::id spring_constraint_eid = ctx.entity_registry->create();
  204. {
  205. // Create spring to constraint
  206. entity::component::constraint::spring_to spring;
  207. spring.target = target_eid;
  208. spring.translation = {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, 1.0f, math::two_pi<float>};
  209. spring.translation.w = hz_to_rads(8.0f);
  210. spring.spring_translation = true;
  211. spring.spring_rotation = false;
  212. ctx.entity_registry->assign<entity::component::constraint::spring_to>(spring_constraint_eid, spring);
  213. // Create constraint stack node component
  214. entity::component::constraint_stack_node node;
  215. node.active = true;
  216. node.weight = 1.0f;
  217. node.next = three_dof_constraint_eid;
  218. ctx.entity_registry->assign<entity::component::constraint_stack_node>(spring_constraint_eid, node);
  219. }
  220. // Create camera constraint stack component
  221. entity::component::constraint_stack constraint_stack;
  222. constraint_stack.head = spring_constraint_eid;
  223. ctx.entity_registry->assign<entity::component::constraint_stack>(camera_eid, constraint_stack);
  224. }
  225. float ev100 = 13.5f;
  226. ctx.surface_camera->set_exposure(ev100);
  227. }
  228. void nuptial_flight::enable_keeper_controls()
  229. {
  230. // Get camera entities
  231. entity::id camera_eid = ctx.entities["surface_cam"];
  232. entity::id target_eid = ctx.entities["surface_cam_target"];
  233. entity::id three_dof_eid = ctx.entities["surface_cam_3dof"];
  234. const float min_elevation = 0.1f;
  235. const float max_elevation = 100.0f;
  236. const float slow_modifier = 0.25f;
  237. const float fast_modifier = 4.0f;
  238. const float dolly_speed = 5.0f;
  239. const float truck_speed = dolly_speed;
  240. const float pedestal_speed = 5.0f;
  241. float mouse_tilt_sensitivity = 1.0f;
  242. float mouse_pan_sensitivity = 1.0f;
  243. bool mouse_invert_tilt = false;
  244. bool mouse_invert_pan = false;
  245. float gamepad_tilt_sensitivity = 1.0f;
  246. float gamepad_pan_sensitivity = 1.0f;
  247. bool gamepad_invert_tilt = false;
  248. bool gamepad_invert_pan = false;
  249. bool mouse_look_toggle = false;
  250. ctx.mouse_look = false;
  251. const double time_scale = 5000.0;
  252. if (ctx.config->contains("mouse_tilt_sensitivity"))
  253. mouse_tilt_sensitivity = math::radians((*ctx.config)["mouse_tilt_sensitivity"].get<float>());
  254. if (ctx.config->contains("mouse_pan_sensitivity"))
  255. mouse_pan_sensitivity = math::radians((*ctx.config)["mouse_pan_sensitivity"].get<float>());
  256. if (ctx.config->contains("mouse_invert_tilt"))
  257. mouse_invert_tilt = math::radians((*ctx.config)["mouse_invert_tilt"].get<bool>());
  258. if (ctx.config->contains("mouse_invert_pan"))
  259. mouse_invert_pan = math::radians((*ctx.config)["mouse_invert_pan"].get<bool>());
  260. if (ctx.config->contains("mouse_look_toggle"))
  261. mouse_look_toggle = math::radians((*ctx.config)["mouse_look_toggle"].get<bool>());
  262. if (ctx.config->contains("gamepad_tilt_sensitivity"))
  263. gamepad_tilt_sensitivity = math::radians((*ctx.config)["gamepad_tilt_sensitivity"].get<float>());
  264. if (ctx.config->contains("gamepad_pan_sensitivity"))
  265. gamepad_pan_sensitivity = math::radians((*ctx.config)["gamepad_pan_sensitivity"].get<float>());
  266. if (ctx.config->contains("gamepad_invert_tilt"))
  267. gamepad_invert_tilt = math::radians((*ctx.config)["gamepad_invert_tilt"].get<bool>());
  268. if (ctx.config->contains("gamepad_invert_pan"))
  269. gamepad_invert_pan = math::radians((*ctx.config)["gamepad_invert_pan"].get<bool>());
  270. const input::control* move_slow = ctx.controls["move_slow"];
  271. const input::control* move_fast = ctx.controls["move_fast"];
  272. const input::control* mouse_look = ctx.controls["mouse_look"];
  273. float mouse_tilt_factor = mouse_tilt_sensitivity * (mouse_invert_tilt ? -1.0f : 1.0f);
  274. float mouse_pan_factor = mouse_pan_sensitivity * (mouse_invert_pan ? -1.0f : 1.0f);
  275. float gamepad_tilt_factor = gamepad_tilt_sensitivity * (gamepad_invert_tilt ? -1.0f : 1.0f);
  276. float gamepad_pan_factor = gamepad_pan_sensitivity * (gamepad_invert_pan ? -1.0f : 1.0f);
  277. ctx.controls["move_forward"]->set_active_callback
  278. (
  279. [&ctx = this->ctx, target_eid, three_dof_eid, dolly_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value)
  280. {
  281. if (move_slow->is_active())
  282. value *= slow_modifier;
  283. if (move_fast->is_active())
  284. value *= fast_modifier;
  285. auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid);
  286. const math::quaternion<float> yaw = math::angle_axis(three_dof.yaw, {0.0f, 1.0f, 0.0f});
  287. const float3 movement = {0.0f, 0.0f, -dolly_speed * value * (1.0f / 60.0f)};
  288. entity::command::translate(*ctx.entity_registry, target_eid, yaw * movement);
  289. }
  290. );
  291. // Dolly backward
  292. ctx.controls["move_back"]->set_active_callback
  293. (
  294. [&ctx = this->ctx, target_eid, three_dof_eid, dolly_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value)
  295. {
  296. if (move_slow->is_active())
  297. value *= slow_modifier;
  298. if (move_fast->is_active())
  299. value *= fast_modifier;
  300. auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid);
  301. const math::quaternion<float> yaw = math::angle_axis(three_dof.yaw, {0.0f, 1.0f, 0.0f});
  302. const float3 movement = {0.0f, 0.0f, dolly_speed * value * (1.0f / 60.0f)};
  303. entity::command::translate(*ctx.entity_registry, target_eid, yaw * movement);
  304. }
  305. );
  306. // Truck right
  307. ctx.controls["move_right"]->set_active_callback
  308. (
  309. [&ctx = this->ctx, target_eid, three_dof_eid, truck_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value)
  310. {
  311. if (move_slow->is_active())
  312. value *= slow_modifier;
  313. if (move_fast->is_active())
  314. value *= fast_modifier;
  315. auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid);
  316. const math::quaternion<float> yaw = math::angle_axis(three_dof.yaw, {0.0f, 1.0f, 0.0f});
  317. const float3 movement = {truck_speed * value * (1.0f / 60.0f), 0.0f, 0.0f};
  318. entity::command::translate(*ctx.entity_registry, target_eid, yaw * movement);
  319. }
  320. );
  321. // Truck left
  322. ctx.controls["move_left"]->set_active_callback
  323. (
  324. [&ctx = this->ctx, target_eid, three_dof_eid, truck_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value)
  325. {
  326. if (move_slow->is_active())
  327. value *= slow_modifier;
  328. if (move_fast->is_active())
  329. value *= fast_modifier;
  330. auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid);
  331. const math::quaternion<float> yaw = math::angle_axis(three_dof.yaw, {0.0f, 1.0f, 0.0f});
  332. const float3 movement = {-truck_speed * value * (1.0f / 60.0f), 0.0f, 0.0f};
  333. entity::command::translate(*ctx.entity_registry, target_eid, yaw * movement);
  334. }
  335. );
  336. // Pedestal up
  337. ctx.controls["move_up"]->set_active_callback
  338. (
  339. [&ctx = this->ctx, target_eid, pedestal_speed, move_slow, move_fast, slow_modifier, fast_modifier, max_elevation](float value)
  340. {
  341. if (move_slow->is_active())
  342. value *= slow_modifier;
  343. if (move_fast->is_active())
  344. value *= fast_modifier;
  345. float3 movement = {0.0f, pedestal_speed * value * (1.0f / 60.0f), 0.0f};
  346. auto transform = entity::command::get_world_transform(*ctx.entity_registry, target_eid);
  347. if (transform.translation.y + movement.y > max_elevation)
  348. movement.y = max_elevation - transform.translation.y;
  349. entity::command::translate(*ctx.entity_registry, target_eid, movement);
  350. }
  351. );
  352. // Pedestal down
  353. ctx.controls["move_down"]->set_active_callback
  354. (
  355. [&ctx = this->ctx, target_eid, pedestal_speed, move_slow, move_fast, slow_modifier, fast_modifier, min_elevation](float value)
  356. {
  357. if (move_slow->is_active())
  358. value *= slow_modifier;
  359. if (move_fast->is_active())
  360. value *= fast_modifier;
  361. float3 movement = {0.0f, -pedestal_speed * value * (1.0f / 60.0f), 0.0f};
  362. auto transform = entity::command::get_world_transform(*ctx.entity_registry, target_eid);
  363. if (transform.translation.y + movement.y < min_elevation)
  364. movement.y = min_elevation - transform.translation.y;
  365. entity::command::translate(*ctx.entity_registry, target_eid, movement);
  366. }
  367. );
  368. // Mouse rotate
  369. ctx.controls["mouse_look"]->set_activated_callback
  370. (
  371. [&ctx = this->ctx, mouse_look_toggle]()
  372. {
  373. if (mouse_look_toggle)
  374. ctx.mouse_look = !ctx.mouse_look;
  375. else
  376. ctx.mouse_look = true;
  377. ctx.app->set_relative_mouse_mode(ctx.mouse_look);
  378. }
  379. );
  380. ctx.controls["mouse_look"]->set_deactivated_callback
  381. (
  382. [&ctx = this->ctx, mouse_look_toggle]()
  383. {
  384. if (!mouse_look_toggle)
  385. {
  386. ctx.mouse_look = false;
  387. ctx.app->set_relative_mouse_mode(false);
  388. }
  389. }
  390. );
  391. // Pan left
  392. ctx.controls["look_left_gamepad"]->set_active_callback
  393. (
  394. [&ctx = this->ctx, three_dof_eid, gamepad_pan_factor](float value)
  395. {
  396. auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid);
  397. three_dof.yaw += gamepad_pan_factor * value * (1.0f / 60.0f);
  398. }
  399. );
  400. ctx.controls["look_left_mouse"]->set_active_callback
  401. (
  402. [&ctx = this->ctx, three_dof_eid, mouse_pan_factor](float value)
  403. {
  404. if (!ctx.mouse_look)
  405. return;
  406. auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid);
  407. three_dof.yaw += mouse_pan_factor * value * (1.0f / 60.0f);
  408. }
  409. );
  410. // Pan right
  411. ctx.controls["look_right_gamepad"]->set_active_callback
  412. (
  413. [&ctx = this->ctx, three_dof_eid, gamepad_pan_factor](float value)
  414. {
  415. auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid);
  416. three_dof.yaw -= gamepad_pan_factor * value * (1.0f / 60.0f);
  417. }
  418. );
  419. ctx.controls["look_right_mouse"]->set_active_callback
  420. (
  421. [&ctx = this->ctx, three_dof_eid, mouse_pan_factor](float value)
  422. {
  423. if (!ctx.mouse_look)
  424. return;
  425. auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid);
  426. three_dof.yaw -= mouse_pan_factor * value * (1.0f / 60.0f);
  427. }
  428. );
  429. // Tilt up
  430. ctx.controls["look_up_gamepad"]->set_active_callback
  431. (
  432. [&ctx = this->ctx, three_dof_eid, gamepad_tilt_factor](float value)
  433. {
  434. auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid);
  435. three_dof.pitch -= gamepad_tilt_factor * value * (1.0f / 60.0f);
  436. three_dof.pitch = std::max<float>(math::radians(-90.0f), three_dof.pitch);
  437. }
  438. );
  439. ctx.controls["look_up_mouse"]->set_active_callback
  440. (
  441. [&ctx = this->ctx, three_dof_eid, mouse_tilt_factor](float value)
  442. {
  443. if (!ctx.mouse_look)
  444. return;
  445. auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid);
  446. three_dof.pitch -= mouse_tilt_factor * value * (1.0f / 60.0f);
  447. three_dof.pitch = std::max<float>(math::radians(-90.0f), three_dof.pitch);
  448. }
  449. );
  450. // Tilt down
  451. ctx.controls["look_down_gamepad"]->set_active_callback
  452. (
  453. [&ctx = this->ctx, three_dof_eid, gamepad_tilt_factor](float value)
  454. {
  455. auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid);
  456. three_dof.pitch += gamepad_tilt_factor * value * (1.0f / 60.0f);
  457. three_dof.pitch = std::min<float>(math::radians(90.0f), three_dof.pitch);
  458. }
  459. );
  460. ctx.controls["look_down_mouse"]->set_active_callback
  461. (
  462. [&ctx = this->ctx, three_dof_eid, mouse_tilt_factor](float value)
  463. {
  464. if (!ctx.mouse_look)
  465. return;
  466. auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid);
  467. three_dof.pitch += mouse_tilt_factor * value * (1.0f / 60.0f);
  468. three_dof.pitch = std::min<float>(math::radians(90.0f), three_dof.pitch);
  469. }
  470. );
  471. // Setup switch POV control
  472. ctx.controls["switch_pov"]->set_activated_callback
  473. (
  474. [this]()
  475. {
  476. // Disable keeper controls
  477. this->disable_keeper_controls();
  478. // Switch to ant
  479. this->is_keeper = false;
  480. // Enable ant controls
  481. this->enable_ant_controls();
  482. }
  483. );
  484. // Fast-forward
  485. ctx.controls["fast_forward"]->set_activated_callback
  486. (
  487. [&ctx = this->ctx, time_scale]()
  488. {
  489. game::world::set_time_scale(ctx, time_scale);
  490. }
  491. );
  492. ctx.controls["fast_forward"]->set_deactivated_callback
  493. (
  494. [&ctx = this->ctx, time_scale]()
  495. {
  496. game::world::set_time_scale(ctx, 0.0);
  497. }
  498. );
  499. ctx.controls["rewind"]->set_activated_callback
  500. (
  501. [&ctx = this->ctx, time_scale]()
  502. {
  503. game::world::set_time_scale(ctx, -time_scale);
  504. }
  505. );
  506. ctx.controls["rewind"]->set_deactivated_callback
  507. (
  508. [&ctx = this->ctx, time_scale]()
  509. {
  510. game::world::set_time_scale(ctx, 0.0);
  511. }
  512. );
  513. // Setup pause control
  514. ctx.controls["pause"]->set_activated_callback
  515. (
  516. [this, &ctx = this->ctx]()
  517. {
  518. // Disable controls
  519. this->disable_controls();
  520. // Set resume callback
  521. ctx.resume_callback = [this, &ctx]()
  522. {
  523. this->enable_controls();
  524. ctx.resume_callback = nullptr;
  525. };
  526. // Push pause menu state
  527. ctx.state_machine.emplace(new game::state::pause_menu(ctx));
  528. }
  529. );
  530. }
  531. void nuptial_flight::disable_keeper_controls()
  532. {
  533. ctx.controls["move_forward"]->set_active_callback(nullptr);
  534. ctx.controls["move_back"]->set_active_callback(nullptr);
  535. ctx.controls["move_right"]->set_active_callback(nullptr);
  536. ctx.controls["move_left"]->set_active_callback(nullptr);
  537. ctx.controls["move_up"]->set_active_callback(nullptr);
  538. ctx.controls["move_down"]->set_active_callback(nullptr);
  539. ctx.controls["mouse_look"]->set_activated_callback(nullptr);
  540. ctx.controls["mouse_look"]->set_deactivated_callback(nullptr);
  541. ctx.controls["look_left_gamepad"]->set_active_callback(nullptr);
  542. ctx.controls["look_left_mouse"]->set_active_callback(nullptr);
  543. ctx.controls["look_right_gamepad"]->set_active_callback(nullptr);
  544. ctx.controls["look_right_mouse"]->set_active_callback(nullptr);
  545. ctx.controls["look_up_gamepad"]->set_active_callback(nullptr);
  546. ctx.controls["look_up_mouse"]->set_active_callback(nullptr);
  547. ctx.controls["look_down_gamepad"]->set_active_callback(nullptr);
  548. ctx.controls["look_down_mouse"]->set_active_callback(nullptr);
  549. ctx.controls["switch_pov"]->set_activated_callback(nullptr);
  550. ctx.controls["fast_forward"]->set_activated_callback(nullptr);
  551. ctx.controls["rewind"]->set_activated_callback(nullptr);
  552. ctx.controls["pause"]->set_activated_callback(nullptr);
  553. }
  554. void nuptial_flight::enable_ant_controls()
  555. {
  556. // Get ant controller entities
  557. entity::id ant_eid = ctx.entities["ant"];
  558. const float move_forward_speed = 5.0f;
  559. const float move_back_speed = move_forward_speed * 0.5f;
  560. const float strafe_speed = move_forward_speed * 0.5f;
  561. const float turn_speed = math::radians(270.0f);
  562. const float slow_modifier = 0.5f;
  563. const float fast_modifier = 2.0f;
  564. float mouse_tilt_sensitivity = 1.0f;
  565. float mouse_pan_sensitivity = 1.0f;
  566. bool mouse_invert_tilt = false;
  567. bool mouse_invert_pan = false;
  568. float gamepad_tilt_sensitivity = 1.0f;
  569. float gamepad_pan_sensitivity = 1.0f;
  570. bool gamepad_invert_tilt = false;
  571. bool gamepad_invert_pan = false;
  572. const double time_scale = 5000.0;
  573. if (ctx.config->contains("mouse_tilt_sensitivity"))
  574. mouse_tilt_sensitivity = math::radians((*ctx.config)["mouse_tilt_sensitivity"].get<float>());
  575. if (ctx.config->contains("mouse_pan_sensitivity"))
  576. mouse_pan_sensitivity = math::radians((*ctx.config)["mouse_pan_sensitivity"].get<float>());
  577. if (ctx.config->contains("mouse_invert_tilt"))
  578. mouse_invert_tilt = math::radians((*ctx.config)["mouse_invert_tilt"].get<bool>());
  579. if (ctx.config->contains("mouse_invert_pan"))
  580. mouse_invert_pan = math::radians((*ctx.config)["mouse_invert_pan"].get<bool>());
  581. if (ctx.config->contains("gamepad_tilt_sensitivity"))
  582. gamepad_tilt_sensitivity = math::radians((*ctx.config)["gamepad_tilt_sensitivity"].get<float>());
  583. if (ctx.config->contains("gamepad_pan_sensitivity"))
  584. gamepad_pan_sensitivity = math::radians((*ctx.config)["gamepad_pan_sensitivity"].get<float>());
  585. if (ctx.config->contains("gamepad_invert_tilt"))
  586. gamepad_invert_tilt = math::radians((*ctx.config)["gamepad_invert_tilt"].get<bool>());
  587. if (ctx.config->contains("gamepad_invert_pan"))
  588. gamepad_invert_pan = math::radians((*ctx.config)["gamepad_invert_pan"].get<bool>());
  589. const input::control* move_slow = ctx.controls["move_slow"];
  590. const input::control* move_fast = ctx.controls["move_fast"];
  591. const input::control* mouse_look = ctx.controls["mouse_look"];
  592. float mouse_tilt_factor = mouse_tilt_sensitivity * (mouse_invert_tilt ? -1.0f : 1.0f);
  593. float mouse_pan_factor = mouse_pan_sensitivity * (mouse_invert_pan ? -1.0f : 1.0f);
  594. float gamepad_tilt_factor = gamepad_tilt_sensitivity * (gamepad_invert_tilt ? -1.0f : 1.0f);
  595. float gamepad_pan_factor = gamepad_pan_sensitivity * (gamepad_invert_pan ? -1.0f : 1.0f);
  596. // Move forward
  597. ctx.controls["move_forward"]->set_active_callback
  598. (
  599. [&ctx = this->ctx, ant_eid, move_forward_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value)
  600. {
  601. if (move_slow->is_active())
  602. value *= slow_modifier;
  603. if (move_fast->is_active())
  604. value *= fast_modifier;
  605. auto& locomotion = ctx.entity_registry->get<entity::component::locomotion>(ant_eid);
  606. const math::quaternion<float> yaw = math::angle_axis(locomotion.yaw, {0.0f, 1.0f, 0.0f});
  607. const float3 movement = {0.0f, 0.0f, move_forward_speed * value * (1.0f / 60.0f)};
  608. entity::command::translate(*ctx.entity_registry, ant_eid, yaw * movement);
  609. }
  610. );
  611. // Move back
  612. ctx.controls["move_back"]->set_active_callback
  613. (
  614. [&ctx = this->ctx, ant_eid, move_back_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value)
  615. {
  616. if (move_slow->is_active())
  617. value *= slow_modifier;
  618. if (move_fast->is_active())
  619. value *= fast_modifier;
  620. auto& locomotion = ctx.entity_registry->get<entity::component::locomotion>(ant_eid);
  621. const math::quaternion<float> yaw = math::angle_axis(locomotion.yaw, {0.0f, 1.0f, 0.0f});
  622. const float3 movement = {0.0f, 0.0f, -move_back_speed * value * (1.0f / 60.0f)};
  623. entity::command::translate(*ctx.entity_registry, ant_eid, yaw * movement);
  624. }
  625. );
  626. // Turn right
  627. ctx.controls["move_right"]->set_active_callback
  628. (
  629. [&ctx = this->ctx, ant_eid, turn_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value)
  630. {
  631. if (move_slow->is_active())
  632. value *= slow_modifier;
  633. if (move_fast->is_active())
  634. value *= fast_modifier;
  635. auto& locomotion = ctx.entity_registry->get<entity::component::locomotion>(ant_eid);
  636. float delta_yaw = -turn_speed * value * (1.0f / 60.0f);
  637. locomotion.yaw += delta_yaw;
  638. entity::command::rotate(*ctx.entity_registry, ant_eid, delta_yaw, {0.0f, 1.0f, 0.0f});
  639. }
  640. );
  641. // Truck left
  642. ctx.controls["move_left"]->set_active_callback
  643. (
  644. [&ctx = this->ctx, ant_eid, turn_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value)
  645. {
  646. if (move_slow->is_active())
  647. value *= slow_modifier;
  648. if (move_fast->is_active())
  649. value *= fast_modifier;
  650. auto& locomotion = ctx.entity_registry->get<entity::component::locomotion>(ant_eid);
  651. float delta_yaw = turn_speed * value * (1.0f / 60.0f);
  652. locomotion.yaw += delta_yaw;
  653. entity::command::rotate(*ctx.entity_registry, ant_eid, delta_yaw, {0.0f, 1.0f, 0.0f});
  654. }
  655. );
  656. // Pan left
  657. /*
  658. ctx.controls["look_left_gamepad"]->set_active_callback
  659. (
  660. [&ctx = this->ctx, three_dof_eid, gamepad_pan_factor](float value)
  661. {
  662. auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid);
  663. three_dof.yaw += gamepad_pan_factor * value * (1.0f / 60.0f);
  664. }
  665. );
  666. ctx.controls["look_left_mouse"]->set_active_callback
  667. (
  668. [&ctx = this->ctx, three_dof_eid, mouse_pan_factor](float value)
  669. {
  670. if (!ctx.mouse_look)
  671. return;
  672. auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid);
  673. three_dof.yaw += mouse_pan_factor * value * (1.0f / 60.0f);
  674. }
  675. );
  676. // Pan right
  677. ctx.controls["look_right_gamepad"]->set_active_callback
  678. (
  679. [&ctx = this->ctx, three_dof_eid, gamepad_pan_factor](float value)
  680. {
  681. auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid);
  682. three_dof.yaw -= gamepad_pan_factor * value * (1.0f / 60.0f);
  683. }
  684. );
  685. ctx.controls["look_right_mouse"]->set_active_callback
  686. (
  687. [&ctx = this->ctx, three_dof_eid, mouse_pan_factor](float value)
  688. {
  689. if (!ctx.mouse_look)
  690. return;
  691. auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid);
  692. three_dof.yaw -= mouse_pan_factor * value * (1.0f / 60.0f);
  693. }
  694. );
  695. // Tilt up
  696. ctx.controls["look_up_gamepad"]->set_active_callback
  697. (
  698. [&ctx = this->ctx, three_dof_eid, gamepad_tilt_factor](float value)
  699. {
  700. auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid);
  701. three_dof.pitch -= gamepad_tilt_factor * value * (1.0f / 60.0f);
  702. three_dof.pitch = std::max<float>(math::radians(-90.0f), three_dof.pitch);
  703. }
  704. );
  705. ctx.controls["look_up_mouse"]->set_active_callback
  706. (
  707. [&ctx = this->ctx, three_dof_eid, mouse_tilt_factor](float value)
  708. {
  709. if (!ctx.mouse_look)
  710. return;
  711. auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid);
  712. three_dof.pitch -= mouse_tilt_factor * value * (1.0f / 60.0f);
  713. three_dof.pitch = std::max<float>(math::radians(-90.0f), three_dof.pitch);
  714. }
  715. );
  716. // Tilt down
  717. ctx.controls["look_down_gamepad"]->set_active_callback
  718. (
  719. [&ctx = this->ctx, three_dof_eid, gamepad_tilt_factor](float value)
  720. {
  721. auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid);
  722. three_dof.pitch += gamepad_tilt_factor * value * (1.0f / 60.0f);
  723. three_dof.pitch = std::min<float>(math::radians(90.0f), three_dof.pitch);
  724. }
  725. );
  726. ctx.controls["look_down_mouse"]->set_active_callback
  727. (
  728. [&ctx = this->ctx, three_dof_eid, mouse_tilt_factor](float value)
  729. {
  730. if (!ctx.mouse_look)
  731. return;
  732. auto& three_dof = ctx.entity_registry->get<entity::component::constraint::three_dof>(three_dof_eid);
  733. three_dof.pitch += mouse_tilt_factor * value * (1.0f / 60.0f);
  734. three_dof.pitch = std::min<float>(math::radians(90.0f), three_dof.pitch);
  735. }
  736. );
  737. */
  738. // Setup switch POV control
  739. ctx.controls["switch_pov"]->set_activated_callback
  740. (
  741. [this]()
  742. {
  743. // Disable ant controls
  744. this->disable_ant_controls();
  745. // Switch to keeper
  746. this->is_keeper = true;
  747. // Enable keeper controls
  748. this->enable_keeper_controls();
  749. }
  750. );
  751. // Fast-forward
  752. ctx.controls["fast_forward"]->set_activated_callback
  753. (
  754. [&ctx = this->ctx, time_scale]()
  755. {
  756. game::world::set_time_scale(ctx, time_scale);
  757. }
  758. );
  759. ctx.controls["fast_forward"]->set_deactivated_callback
  760. (
  761. [&ctx = this->ctx, time_scale]()
  762. {
  763. game::world::set_time_scale(ctx, 0.0);
  764. }
  765. );
  766. ctx.controls["rewind"]->set_activated_callback
  767. (
  768. [&ctx = this->ctx, time_scale]()
  769. {
  770. game::world::set_time_scale(ctx, -time_scale);
  771. }
  772. );
  773. ctx.controls["rewind"]->set_deactivated_callback
  774. (
  775. [&ctx = this->ctx, time_scale]()
  776. {
  777. game::world::set_time_scale(ctx, 0.0);
  778. }
  779. );
  780. // Setup pause control
  781. ctx.controls["pause"]->set_activated_callback
  782. (
  783. [this, &ctx = this->ctx]()
  784. {
  785. // Disable controls
  786. this->disable_controls();
  787. // Set resume callback
  788. ctx.resume_callback = [this, &ctx]()
  789. {
  790. this->enable_controls();
  791. ctx.resume_callback = nullptr;
  792. };
  793. // Push pause menu state
  794. ctx.state_machine.emplace(new game::state::pause_menu(ctx));
  795. }
  796. );
  797. }
  798. void nuptial_flight::disable_ant_controls()
  799. {
  800. ctx.controls["move_forward"]->set_active_callback(nullptr);
  801. ctx.controls["move_back"]->set_active_callback(nullptr);
  802. ctx.controls["move_right"]->set_active_callback(nullptr);
  803. ctx.controls["move_left"]->set_active_callback(nullptr);
  804. ctx.controls["look_left_gamepad"]->set_active_callback(nullptr);
  805. ctx.controls["look_left_mouse"]->set_active_callback(nullptr);
  806. ctx.controls["look_right_gamepad"]->set_active_callback(nullptr);
  807. ctx.controls["look_right_mouse"]->set_active_callback(nullptr);
  808. ctx.controls["look_up_gamepad"]->set_active_callback(nullptr);
  809. ctx.controls["look_up_mouse"]->set_active_callback(nullptr);
  810. ctx.controls["look_down_gamepad"]->set_active_callback(nullptr);
  811. ctx.controls["look_down_mouse"]->set_active_callback(nullptr);
  812. ctx.controls["switch_pov"]->set_activated_callback(nullptr);
  813. ctx.controls["fast_forward"]->set_activated_callback(nullptr);
  814. ctx.controls["rewind"]->set_activated_callback(nullptr);
  815. ctx.controls["pause"]->set_activated_callback(nullptr);
  816. }
  817. void nuptial_flight::enable_controls()
  818. {
  819. if (is_keeper)
  820. enable_keeper_controls();
  821. else
  822. enable_ant_controls();
  823. }
  824. void nuptial_flight::disable_controls()
  825. {
  826. if (is_keeper)
  827. disable_keeper_controls();
  828. else
  829. disable_ant_controls();
  830. }
  831. } // namespace state
  832. } // namespace game