diff --git a/CMakeLists.txt b/CMakeLists.txt
index df838bd..7faddc1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,7 +3,6 @@ cmake_minimum_required(VERSION 3.7)
option(VERSION_STRING "Project version string" "0.0.0")
-
project(antkeeper VERSION ${VERSION_STRING} LANGUAGES CXX)
# Find dependency packages
diff --git a/src/config.hpp.in b/src/config.hpp.in
index c13004c..2123901 100644
--- a/src/config.hpp.in
+++ b/src/config.hpp.in
@@ -44,7 +44,7 @@ constexpr float menu_fade_out_duration = 0.125f;
constexpr float menu_mouseover_padding = 0.1f;
/// Opacity of the menu background.
-constexpr float menu_bg_opacity = 0.5f;
+constexpr float menu_bg_opacity = 2.0f / 3.0f;
/// RGBA color of active menu items.
constexpr float4 menu_active_color{1.0f, 1.0f, 1.0f, 1.0f};
diff --git a/src/entity/components/locomotion.hpp b/src/entity/components/locomotion.hpp
index 8f49130..a1d4553 100644
--- a/src/entity/components/locomotion.hpp
+++ b/src/entity/components/locomotion.hpp
@@ -28,8 +28,10 @@ namespace component {
struct locomotion
{
- const geom::mesh::face* triangle;
- float3 barycentric_position;
+ //const geom::mesh::face* triangle;
+ //float3 barycentric_position;
+
+ float yaw;
};
} // namespace component
diff --git a/src/entity/components/steering.hpp b/src/entity/components/steering.hpp
new file mode 100644
index 0000000..3c915aa
--- /dev/null
+++ b/src/entity/components/steering.hpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_ENTITY_COMPONENT_STEERING_HPP
+#define ANTKEEPER_ENTITY_COMPONENT_STEERING_HPP
+
+#include "utility/fundamental-types.hpp"
+
+namespace entity {
+namespace component {
+
+struct steering
+{
+ float3 velocity;
+ float3 acceleration;
+ float max_force;
+ float max_speed;
+};
+
+} // namespace component
+} // namespace entity
+
+#endif // ANTKEEPER_ENTITY_COMPONENT_STEERING_HPP
+
diff --git a/src/entity/systems/steering.cpp b/src/entity/systems/steering.cpp
new file mode 100644
index 0000000..73f1ac4
--- /dev/null
+++ b/src/entity/systems/steering.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#include "entity/systems/steering.hpp"
+#include "entity/components/steering.hpp"
+#include "entity/components/transform.hpp"
+#include "entity/id.hpp"
+
+namespace entity {
+namespace system {
+
+steering::steering(entity::registry& registry):
+ updatable(registry)
+{}
+
+void steering::update(double t, double dt)
+{
+ registry.view().each(
+ [&](entity::id entity_id, auto& transform, auto& boid)
+ {
+ // Accelerate
+ boid.velocity += boid.acceleration;
+ if (math::dot(boid.velocity, boid.velocity) > boid.max_speed * boid.max_speed)
+ {
+ boid.velocity = math::normalize(boid.velocity) * boid.max_speed;
+ }
+
+ // Clear acceleration
+ boid.acceleration = {0, 0, 0};
+
+ // Move
+ transform.local.translation += boid.velocity;
+ });
+}
+
+void steering::wander()
+{
+
+}
+
+} // namespace system
+} // namespace entity
diff --git a/src/entity/systems/steering.hpp b/src/entity/systems/steering.hpp
new file mode 100644
index 0000000..77909e9
--- /dev/null
+++ b/src/entity/systems/steering.hpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_ENTITY_SYSTEM_STEERING_HPP
+#define ANTKEEPER_ENTITY_SYSTEM_STEERING_HPP
+
+#include "entity/systems/updatable.hpp"
+
+namespace entity {
+namespace system {
+
+class steering:
+ public updatable
+{
+public:
+ steering(entity::registry& registry);
+ virtual void update(double t, double dt);
+
+private:
+ void wander();
+};
+
+} // namespace system
+} // namespace entity
+
+#endif // ANTKEEPER_ENTITY_SYSTEM_STEERING_HPP
diff --git a/src/game/ant/breed.hpp b/src/game/ant/breed.hpp
new file mode 100644
index 0000000..21fe9b1
--- /dev/null
+++ b/src/game/ant/breed.hpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_BREED_HPP
+#define ANTKEEPER_GAME_ANT_BREED_HPP
+
+#include "game/ant/trait/antennae.hpp"
+#include "game/ant/trait/cocoon.hpp"
+#include "game/ant/trait/diet.hpp"
+#include "game/ant/trait/egg.hpp"
+#include "game/ant/trait/eyes.hpp"
+#include "game/ant/trait/foraging-time.hpp"
+#include "game/ant/trait/forewings.hpp"
+#include "game/ant/trait/gaster.hpp"
+#include "game/ant/trait/head.hpp"
+#include "game/ant/trait/hindwings.hpp"
+#include "game/ant/trait/larva.hpp"
+#include "game/ant/trait/legs.hpp"
+#include "game/ant/trait/mandibles.hpp"
+#include "game/ant/trait/mesosoma.hpp"
+#include "game/ant/trait/nest.hpp"
+#include "game/ant/trait/ocelli.hpp"
+#include "game/ant/trait/pigmentation.hpp"
+#include "game/ant/trait/pilosity.hpp"
+#include "game/ant/trait/sculpturing.hpp"
+#include "game/ant/trait/sting.hpp"
+#include "game/ant/trait/waist.hpp"
+
+namespace game {
+namespace ant {
+
+/**
+ * Set of all traits that describes an ant breed.
+ */
+struct breed
+{
+ // Morphological traits
+ trait::antennae* antennae;
+ trait::eyes* eyes;
+ trait::forewings* forewings;
+ trait::gaster* gaster;
+ trait::waist* waist;
+ trait::head* head;
+ trait::hindwings* hindwings;
+ trait::legs* legs;
+ trait::mandibles* mandibles;
+ trait::mesosoma* mesosoma;
+ trait::ocelli* ocelli;
+ trait::sting* sting;
+ trait::sculpturing* sculpturing;
+ trait::pigmentation* pigmentation;
+ trait::pilosity* pilosity;
+ trait::egg* egg;
+ trait::larva* larva;
+ trait::cocoon* cocoon;
+
+ // Behavioral traits
+ trait::diet* diet;
+ trait::foraging_time* foraging_time;
+ trait::nest* nest;
+};
+
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_BREED_HPP
diff --git a/src/game/ant/caste.hpp b/src/game/ant/caste.hpp
new file mode 100644
index 0000000..ac1a97f
--- /dev/null
+++ b/src/game/ant/caste.hpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_CASTE_HPP
+#define ANTKEEPER_GAME_ANT_CASTE_HPP
+
+namespace game {
+namespace ant {
+
+/**
+ * Caste type enumerations
+ */
+enum class caste
+{
+ queen,
+ worker,
+ soldier,
+ male
+};
+
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_CASTE_HPP
diff --git a/src/game/ant/founding-mode.hpp b/src/game/ant/founding-mode.hpp
new file mode 100644
index 0000000..67be08d
--- /dev/null
+++ b/src/game/ant/founding-mode.hpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_FOUNDING_MODE_HPP
+#define ANTKEEPER_GAME_ANT_FOUNDING_MODE_HPP
+
+namespace game {
+namespace ant {
+
+enum class founding_mode
+{
+ semi_claustral,
+ claustral
+};
+
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_FOUNDING_MODE_HPP
diff --git a/src/game/ant/morphogenesis.cpp b/src/game/ant/morphogenesis.cpp
new file mode 100644
index 0000000..bf91cf8
--- /dev/null
+++ b/src/game/ant/morphogenesis.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#include "game/ant/morphogenesis.hpp"
+#include "render/material.hpp"
+
+namespace game {
+namespace ant {
+
+static render::model* generate_queen(const ant::breed& breed);
+static render::model* generate_worker(const ant::breed& breed);
+static render::model* generate_soldier(const ant::breed& breed);
+static render::model* generate_male(const ant::breed& breed);
+static render::material* build_material(const ant::breed& breed);
+static render::model* build_model
+(
+ render::material* material,
+ render::model* antennae,
+ render::model* eyes,
+ render::model* forewings,
+ render::model* gaster,
+ render::model* head,
+ render::model* hindwings,
+ render::model* legs,
+ render::model* mandibles,
+ render::model* mesosoma,
+ render::model* ocelli,
+ render::model* sting,
+ render::model* waist
+);
+
+render::model* morphogenesis(const ant::breed& breed, ant::caste caste)
+{
+ switch (caste)
+ {
+ case ant::caste::queen:
+ return generate_queen(breed);
+ case ant::caste::worker:
+ return generate_worker(breed);
+ case ant::caste::soldier:
+ return generate_soldier(breed);
+ case ant::caste::male:
+ return generate_male(breed);
+ }
+
+ return nullptr;
+}
+
+render::model* generate_queen(const ant::breed& breed)
+{
+ return nullptr;
+}
+
+render::model* generate_worker(const ant::breed& breed)
+{
+ // Get material parameters
+
+
+ // Build material
+ render::material* material = build_material(breed);
+
+ // Get worker body part models
+ render::model* antennae_model = breed.antennae->model;
+ render::model* eyes_model = breed.eyes->model;
+ render::model* gaster_model = breed.gaster->model;
+ render::model* head_model = breed.head->model;
+ render::model* legs_model = breed.legs->model;
+ render::model* mandibles_model = breed.mandibles->model;
+ render::model* mesosoma_model = breed.mesosoma->model;
+ render::model* sting_model = breed.sting->model;
+ render::model* waist_model = breed.waist->model;
+
+ // Build worker model
+ render::model* model = build_model
+ (
+ material,
+ antennae_model,
+ eyes_model,
+ nullptr,
+ gaster_model,
+ head_model,
+ nullptr,
+ legs_model,
+ mandibles_model,
+ mesosoma_model,
+ nullptr,
+ sting_model,
+ waist_model
+ );
+
+ return model;
+}
+
+
+render::model* generate_soldier(const ant::breed& breed)
+{
+ return nullptr;
+}
+
+render::model* generate_male(const ant::breed& breed)
+{
+ return nullptr;
+}
+
+render::material* build_material(const ant::breed& breed)
+{
+ return nullptr;
+}
+
+render::model* build_model
+(
+ render::material* material,
+ render::model* antennae,
+ render::model* eyes,
+ render::model* forewings,
+ render::model* gaster,
+ render::model* head,
+ render::model* hindwings,
+ render::model* legs,
+ render::model* mandibles,
+ render::model* mesosoma,
+ render::model* ocelli,
+ render::model* sting,
+ render::model* waist
+)
+{
+ return nullptr;
+}
+
+
+} // namespace ant
+} // namespace game
diff --git a/src/game/ant/morphogenesis.hpp b/src/game/ant/morphogenesis.hpp
new file mode 100644
index 0000000..b10540e
--- /dev/null
+++ b/src/game/ant/morphogenesis.hpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_MORPHOGENESIS_HPP
+#define ANTKEEPER_GAME_ANT_MORPHOGENESIS_HPP
+
+#include "game/ant/breed.hpp"
+#include "game/ant/caste.hpp"
+#include "render/model.hpp"
+
+namespace game {
+namespace ant {
+
+/**
+ * Generates a 3D model of an ant.
+ *
+ * @param breed Breed of the ant.
+ * @param caste Caste to which the ant belongs.
+ * @return 3D model of an ant.
+ */
+render::model* morphogenesis(const ant::breed& breed, ant::caste caste);
+
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_MORPHOGENESIS_HPP
diff --git a/src/game/ant/nest-site.hpp b/src/game/ant/nest-site.hpp
new file mode 100644
index 0000000..7dd159e
--- /dev/null
+++ b/src/game/ant/nest-site.hpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_NEST_SITE_HPP
+#define ANTKEEPER_GAME_ANT_NEST_SITE_HPP
+
+namespace game {
+namespace ant {
+
+/**
+ * Nest site enumerations.
+ */
+enum class nest_site
+{
+ hypogeic,
+ arboreal
+};
+
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_NEST_SITE_HPP
diff --git a/src/game/ant/subcaste.hpp b/src/game/ant/subcaste.hpp
new file mode 100644
index 0000000..82e360b
--- /dev/null
+++ b/src/game/ant/subcaste.hpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_SUBCASTE_HPP
+#define ANTKEEPER_GAME_ANT_SUBCASTE_HPP
+
+namespace game {
+namespace ant {
+
+/**
+ * Ant subcaste types.
+ */
+enum class subcaste
+{
+ /// A worker from the queen's first batch of eggs, smaller than normal workers.
+ nanitic,
+
+ /// A small worker or soldier.
+ minor,
+
+ /// A normal-sized worker or soldier
+ media,
+
+ /// A large worker or soldier.
+ major,
+
+ /// A queen or male which still has its wings.
+ alate,
+
+ /// A queen or male which has shed its wings.
+ dealate,
+
+ /// A queen or male which does not develop wings.
+ ergatoid,
+
+ /// A queen or male with short, nonfunctional wings.
+ brachypterous
+};
+
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_SUBCASTE_HPP
diff --git a/src/game/ant/trait/antennae.hpp b/src/game/ant/trait/antennae.hpp
new file mode 100644
index 0000000..bda1b9b
--- /dev/null
+++ b/src/game/ant/trait/antennae.hpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_TRAIT_ANTENNAE_HPP
+#define ANTKEEPER_GAME_ANT_TRAIT_ANTENNAE_HPP
+
+#include "render/model.hpp"
+
+namespace game {
+namespace ant {
+namespace trait {
+
+/**
+ * Trait that describes the antennae of an ant.
+ */
+struct antennae
+{
+ /// Scape length (SL), measured in mesosomal lengths.
+ float scape_length;
+
+ /// 3D model of the antennae.
+ render::model* model;
+};
+
+} // namespace trait
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_TRAIT_ANTENNAE_HPP
diff --git a/src/game/ant/trait/cocoon.hpp b/src/game/ant/trait/cocoon.hpp
new file mode 100644
index 0000000..ea34f17
--- /dev/null
+++ b/src/game/ant/trait/cocoon.hpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_TRAIT_COCOON_HPP
+#define ANTKEEPER_GAME_ANT_TRAIT_COCOON_HPP
+
+#include "render/model.hpp"
+
+namespace game {
+namespace ant {
+namespace trait {
+
+/**
+ * Trait that describes the cocoon of an ant species.
+ */
+struct cocoon
+{
+ /// Indicates whether a cocoon is formed by the larvae or not.
+ bool present;
+
+ /// 3D model of the cocoon, if present.
+ render::model* model;
+};
+
+} // namespace trait
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_TRAIT_COCOON_HPP
diff --git a/src/game/ant/trait/diet.hpp b/src/game/ant/trait/diet.hpp
new file mode 100644
index 0000000..a1ec448
--- /dev/null
+++ b/src/game/ant/trait/diet.hpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_TRAIT_DIET_HPP
+#define ANTKEEPER_GAME_ANT_TRAIT_DIET_HPP
+
+namespace game {
+namespace ant {
+namespace trait {
+
+/**
+ * Trait that describes the diet of an ant.
+ */
+struct diet
+{
+ /// Preference for eating seeds.
+ float seeds;
+
+ /// Preference for eating ant brood.
+ float ant_brood;
+
+ /// Preference for eating arthropod eggs.
+ float arthropod_eggs;
+
+ /// Preference for eating nectar.
+ float nectar;
+
+ /// Preference for eating fungi.
+ float fungi;
+
+ /// Preference for eating carrion.
+ float carrion;
+};
+
+} // namespace trait
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_TRAIT_DIET_HPP
diff --git a/src/game/ant/trait/egg.hpp b/src/game/ant/trait/egg.hpp
new file mode 100644
index 0000000..b5a2502
--- /dev/null
+++ b/src/game/ant/trait/egg.hpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_TRAIT_EGG_HPP
+#define ANTKEEPER_GAME_ANT_TRAIT_EGG_HPP
+
+#include "render/model.hpp"
+
+namespace game {
+namespace ant {
+namespace trait {
+
+/**
+ * Trait that describes the eggs of an ant species.
+ */
+struct egg
+{
+ /// 3D model of the egg.
+ render::model* model;
+};
+
+} // namespace trait
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_TRAIT_EGG_HPP
diff --git a/src/game/ant/trait/eyes.hpp b/src/game/ant/trait/eyes.hpp
new file mode 100644
index 0000000..3018f65
--- /dev/null
+++ b/src/game/ant/trait/eyes.hpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_TRAIT_EYES_HPP
+#define ANTKEEPER_GAME_ANT_TRAIT_EYES_HPP
+
+#include "render/model.hpp"
+
+namespace game {
+namespace ant {
+namespace trait {
+
+/**
+ * Trait that describes the eyes of an ant.
+ */
+struct eyes
+{
+ /// Eye length (EL), measured in mesosomal lengths.
+ float length;
+
+ /// Eye width (EW), measured in mesosomal lengths.
+ float width;
+
+ /// Number of ommatidia.
+ int ommatidia;
+
+ /// 3D model of the eyes.
+ render::model* model;
+};
+
+} // namespace trait
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_TRAIT_EYES_HPP
diff --git a/src/game/ant/trait/foraging-time.hpp b/src/game/ant/trait/foraging-time.hpp
new file mode 100644
index 0000000..90df4a8
--- /dev/null
+++ b/src/game/ant/trait/foraging-time.hpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_TRAIT_FORAGING_TIME_HPP
+#define ANTKEEPER_GAME_ANT_TRAIT_FORAGING_TIME_HPP
+
+#include "render/model.hpp"
+
+namespace game {
+namespace ant {
+namespace trait {
+
+/**
+ * Trait that describes the surface foraging time of an ant.
+ */
+struct foraging_time
+{
+ /// Minimum solar altitude at which foraging occurs.
+ float solar_altitude_min;
+
+ /// Maximum solar alttiude at which foraging occurs.
+ float solar_altitude_max;
+};
+
+} // namespace trait
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_TRAIT_FORAGING_TIME_HPP
diff --git a/src/game/ant/trait/forewings.hpp b/src/game/ant/trait/forewings.hpp
new file mode 100644
index 0000000..fc604a5
--- /dev/null
+++ b/src/game/ant/trait/forewings.hpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_TRAIT_FOREWINGS_HPP
+#define ANTKEEPER_GAME_ANT_TRAIT_FOREWINGS_HPP
+
+#include "render/model.hpp"
+
+namespace game {
+namespace ant {
+namespace trait {
+
+/**
+ * Trait that describes the forewings of an ant.
+ */
+struct forewings
+{
+ /// Wing length, measured in mesosomal lengths.
+ float length;
+
+ /// Wing width, measured in mesosomal lengths.
+ float width;
+
+ /// Degree of venation. A value of `1.0` indicates a highly-developed venation pattern, while `0.0` indicates a complete absence of visible venation.
+ float venation;
+
+ /// 3D model of the forewings.
+ render::model* model;
+};
+
+} // namespace trait
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_TRAIT_FOREWINGS_HPP
diff --git a/src/game/ant/trait/gaster.hpp b/src/game/ant/trait/gaster.hpp
new file mode 100644
index 0000000..dec4005
--- /dev/null
+++ b/src/game/ant/trait/gaster.hpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_TRAIT_GASTER_HPP
+#define ANTKEEPER_GAME_ANT_TRAIT_GASTER_HPP
+
+#include "render/model.hpp"
+
+namespace game {
+namespace ant {
+namespace trait {
+
+/**
+ * Trait that describes the gaster of an ant.
+ */
+struct gaster
+{
+ /// 3D model of the gaster.
+ render::model* model;
+};
+
+} // namespace trait
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_TRAIT_GASTER_HPP
diff --git a/src/game/ant/trait/head.hpp b/src/game/ant/trait/head.hpp
new file mode 100644
index 0000000..6d6db88
--- /dev/null
+++ b/src/game/ant/trait/head.hpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_TRAIT_HEAD_HPP
+#define ANTKEEPER_GAME_ANT_TRAIT_HEAD_HPP
+
+#include "render/model.hpp"
+
+namespace game {
+namespace ant {
+namespace trait {
+
+/**
+ * Trait that describes the head of an ant.
+ */
+struct head
+{
+ /// Head length in full face view (HL), measured in mesosomal lengths.
+ float length;
+
+ /// Head width in full face view (HW), measured in mesosomal lengths.
+ float width;
+
+ /// Indicates whether the head can be used to plug nest entrances.
+ bool phragmotic;
+
+ /// 3D model of the head.
+ render::model* model;
+};
+
+} // namespace trait
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_TRAIT_HEAD_HPP
diff --git a/src/game/ant/trait/hindwings.hpp b/src/game/ant/trait/hindwings.hpp
new file mode 100644
index 0000000..312503b
--- /dev/null
+++ b/src/game/ant/trait/hindwings.hpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_TRAIT_HINDWINGS_HPP
+#define ANTKEEPER_GAME_ANT_TRAIT_HINDWINGS_HPP
+
+#include "render/model.hpp"
+
+namespace game {
+namespace ant {
+namespace trait {
+
+/**
+ * Trait that describes the hindwings of an ant.
+ */
+struct hindwings
+{
+ /// Wing length, measured in mesosomal lengths.
+ float length;
+
+ /// Wing width, measured in mesosomal lengths.
+ float width;
+
+ /// Degree of venation. A value of `1.0` indicates a highly-developed venation pattern, while `0.0` indicates a complete absence of visible venation.
+ float venation;
+
+ /// 3D model of the hindwings.
+ render::model* model;
+};
+
+} // namespace trait
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_TRAIT_HINDWINGS_HPP
diff --git a/src/game/ant/trait/larva.hpp b/src/game/ant/trait/larva.hpp
new file mode 100644
index 0000000..a3f5123
--- /dev/null
+++ b/src/game/ant/trait/larva.hpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_TRAIT_LARVA_HPP
+#define ANTKEEPER_GAME_ANT_TRAIT_LARVA_HPP
+
+#include "render/model.hpp"
+
+namespace game {
+namespace ant {
+namespace trait {
+
+/**
+ * Trait that describes the larvae of an ant species.
+ */
+struct larva
+{
+ /// Number of larval instars before pupation.
+ int instars;
+
+ /// 3D model of the larva.
+ render::model* model;
+};
+
+} // namespace trait
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_TRAIT_LARVA_HPP
diff --git a/src/game/ant/trait/legs.hpp b/src/game/ant/trait/legs.hpp
new file mode 100644
index 0000000..d3d005e
--- /dev/null
+++ b/src/game/ant/trait/legs.hpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_TRAIT_LEGS_HPP
+#define ANTKEEPER_GAME_ANT_TRAIT_LEGS_HPP
+
+#include "render/model.hpp"
+
+namespace game {
+namespace ant {
+namespace trait {
+
+/**
+ * Trait that describes the legs of an ant.
+ */
+struct legs
+{
+ /// Running speed, measured in mesosomal lengths per second (ML/s).
+ float speed;
+
+ /// 3D model of the legs.
+ render::model* model;
+};
+
+} // namespace trait
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_TRAIT_LEGS_HPP
diff --git a/src/game/ant/trait/loader/antennae-loader.cpp b/src/game/ant/trait/loader/antennae-loader.cpp
new file mode 100644
index 0000000..61bca5d
--- /dev/null
+++ b/src/game/ant/trait/loader/antennae-loader.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#include "resources/resource-loader.hpp"
+#include "resources/resource-manager.hpp"
+#include "resources/json.hpp"
+#include "game/ant/trait/antennae.hpp"
+#include "render/model.hpp"
+#include
+
+using namespace game::ant;
+
+template <>
+trait::antennae* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
+{
+ // Load JSON data
+ json* data = resource_loader::load(resource_manager, file, path);
+
+ // Validate trait file
+ auto antennae_element = data->find("antennae");
+ if (antennae_element == data->end())
+ throw std::runtime_error("Invalid antennae trait.");
+
+ // Allocate antennae trait
+ trait::antennae* antennae = new trait::antennae();
+
+ // Load antennae model
+ auto model_element = antennae_element->find("model");
+ if (model_element == antennae_element->end())
+ throw std::runtime_error("Antennae trait doesn't specify antennae model.");
+ antennae->model = resource_manager->load(model_element->get());
+
+ // Parse antennae scape length
+ antennae->scape_length = 0.0f;
+ if (auto scape_length_element = antennae_element->find("scape_length"); scape_length_element != antennae_element->end())
+ antennae->scape_length = scape_length_element->get();
+
+ // Free JSON data
+ delete data;
+
+ return antennae;
+}
diff --git a/src/game/ant/trait/loader/cocoon-loader.cpp b/src/game/ant/trait/loader/cocoon-loader.cpp
new file mode 100644
index 0000000..a5b1d5d
--- /dev/null
+++ b/src/game/ant/trait/loader/cocoon-loader.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#include "resources/resource-loader.hpp"
+#include "resources/resource-manager.hpp"
+#include "resources/json.hpp"
+#include "game/ant/trait/cocoon.hpp"
+#include "render/model.hpp"
+#include
+
+using namespace game::ant;
+
+template <>
+trait::cocoon* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
+{
+ // Load JSON data
+ json* data = resource_loader::load(resource_manager, file, path);
+
+ // Validate trait file
+ auto cocoon_element = data->find("cocoon");
+ if (cocoon_element == data->end())
+ throw std::runtime_error("Invalid cocoon trait.");
+
+ // Allocate cocoon trait
+ trait::cocoon* cocoon = new trait::cocoon();
+
+ // Parse cocoon present
+ cocoon->present = false;
+ if (auto present_element = cocoon_element->find("present"); present_element != cocoon_element->end())
+ cocoon->present = present_element->get();
+
+ // Load cocoon model (if present)
+ if (cocoon->present)
+ {
+ auto model_element = cocoon_element->find("model");
+ if (model_element == cocoon_element->end())
+ throw std::runtime_error("Cocoon trait doesn't specify cocoon model.");
+ cocoon->model = resource_manager->load(model_element->get());
+ }
+ else
+ {
+ cocoon->model = nullptr;
+ }
+
+ // Free JSON data
+ delete data;
+
+ return cocoon;
+}
diff --git a/src/game/ant/trait/loader/egg-loader.cpp b/src/game/ant/trait/loader/egg-loader.cpp
new file mode 100644
index 0000000..e4de136
--- /dev/null
+++ b/src/game/ant/trait/loader/egg-loader.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#include "resources/resource-loader.hpp"
+#include "resources/resource-manager.hpp"
+#include "resources/json.hpp"
+#include "game/ant/trait/egg.hpp"
+#include "render/model.hpp"
+#include
+
+using namespace game::ant;
+
+template <>
+trait::egg* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
+{
+ // Load JSON data
+ json* data = resource_loader::load(resource_manager, file, path);
+
+ // Validate trait file
+ auto egg_element = data->find("egg");
+ if (egg_element == data->end())
+ throw std::runtime_error("Invalid egg trait.");
+
+ // Allocate egg trait
+ trait::egg* egg = new trait::egg();
+
+ // Load egg model
+ auto model_element = egg_element->find("model");
+ if (model_element == egg_element->end())
+ throw std::runtime_error("Egg trait doesn't specify egg model.");
+ egg->model = resource_manager->load(model_element->get());
+
+ // Free JSON data
+ delete data;
+
+ return egg;
+}
diff --git a/src/game/ant/trait/loader/eyes-loader.cpp b/src/game/ant/trait/loader/eyes-loader.cpp
new file mode 100644
index 0000000..f923c4a
--- /dev/null
+++ b/src/game/ant/trait/loader/eyes-loader.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#include "resources/resource-loader.hpp"
+#include "resources/resource-manager.hpp"
+#include "resources/json.hpp"
+#include "game/ant/trait/eyes.hpp"
+#include "render/model.hpp"
+#include
+
+using namespace game::ant;
+
+template <>
+trait::eyes* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
+{
+ // Load JSON data
+ json* data = resource_loader::load(resource_manager, file, path);
+
+ // Validate trait file
+ auto eyes_element = data->find("eyes");
+ if (eyes_element == data->end())
+ throw std::runtime_error("Invalid eyes trait.");
+
+ // Allocate eyes trait
+ trait::eyes* eyes = new trait::eyes();
+
+ // Load eyes model (if not null)
+ auto model_element = eyes_element->find("model");
+ if (model_element == eyes_element->end())
+ throw std::runtime_error("Eyes trait doesn't specify eyes model.");
+ if (model_element->is_null())
+ {
+ eyes->model = nullptr;
+ }
+ else
+ {
+ eyes->model = resource_manager->load(model_element->get());
+ }
+
+ // Parse eyes length
+ eyes->length = 0.0f;
+ if (auto length_element = eyes_element->find("length"); length_element != eyes_element->end())
+ eyes->length = length_element->get();
+
+ // Parse eyes width
+ eyes->width = 0.0f;
+ if (auto width_element = eyes_element->find("width"); width_element != eyes_element->end())
+ eyes->width = width_element->get();
+
+ // Parse eyes ommatidia
+ eyes->ommatidia = 0;
+ if (auto ommatidia_element = eyes_element->find("ommatidia"); ommatidia_element != eyes_element->end())
+ eyes->ommatidia = ommatidia_element->get();
+
+ // Free JSON data
+ delete data;
+
+ return eyes;
+}
diff --git a/src/game/ant/trait/loader/foraging-time-loader.cpp b/src/game/ant/trait/loader/foraging-time-loader.cpp
new file mode 100644
index 0000000..04b27fe
--- /dev/null
+++ b/src/game/ant/trait/loader/foraging-time-loader.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#include "resources/resource-loader.hpp"
+#include "resources/resource-manager.hpp"
+#include "resources/json.hpp"
+#include "game/ant/trait/foraging-time.hpp"
+#include "math/angles.hpp"
+#include
+
+using namespace game::ant;
+
+template <>
+trait::foraging_time* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
+{
+ // Load JSON data
+ json* data = resource_loader::load(resource_manager, file, path);
+
+ auto foraging_time_element = data->find("foraging_time");
+ if (foraging_time_element == data->end())
+ throw std::runtime_error("Invalid foraging time trait.");
+
+ auto solar_altitude_element = foraging_time_element->find("solar_altitude");
+ if (solar_altitude_element == foraging_time_element->end())
+ throw std::runtime_error("Foraging time trait doesn't specify solar altitude.");
+
+ if (!solar_altitude_element->is_array() || solar_altitude_element->size() != 2)
+ throw std::runtime_error("Foraging time trait solar altitude must contain two values.");
+
+ trait::foraging_time* foraging_time = new trait::foraging_time();
+ foraging_time->solar_altitude_min = math::radians(solar_altitude_element->front().get());
+ foraging_time->solar_altitude_max = math::radians(solar_altitude_element->back().get());
+
+ // Free JSON data
+ delete data;
+
+ return foraging_time;
+}
diff --git a/src/game/ant/trait/loader/gaster-loader.cpp b/src/game/ant/trait/loader/gaster-loader.cpp
new file mode 100644
index 0000000..dfaed7f
--- /dev/null
+++ b/src/game/ant/trait/loader/gaster-loader.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#include "resources/resource-loader.hpp"
+#include "resources/resource-manager.hpp"
+#include "resources/json.hpp"
+#include "game/ant/trait/gaster.hpp"
+#include "render/model.hpp"
+#include
+
+using namespace game::ant;
+
+template <>
+trait::gaster* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
+{
+ // Load JSON data
+ json* data = resource_loader::load(resource_manager, file, path);
+
+ // Validate trait file
+ auto gaster_element = data->find("gaster");
+ if (gaster_element == data->end())
+ throw std::runtime_error("Invalid gaster trait.");
+
+ // Allocate gaster trait
+ trait::gaster* gaster = new trait::gaster();
+
+ // Load gaster model
+ auto model_element = gaster_element->find("model");
+ if (model_element == gaster_element->end())
+ throw std::runtime_error("Gaster trait doesn't specify gaster model.");
+ gaster->model = resource_manager->load(model_element->get());
+
+ // Free JSON data
+ delete data;
+
+ return gaster;
+}
diff --git a/src/game/ant/trait/loader/head-loader.cpp b/src/game/ant/trait/loader/head-loader.cpp
new file mode 100644
index 0000000..a00fc42
--- /dev/null
+++ b/src/game/ant/trait/loader/head-loader.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#include "resources/resource-loader.hpp"
+#include "resources/resource-manager.hpp"
+#include "resources/json.hpp"
+#include "game/ant/trait/head.hpp"
+#include "render/model.hpp"
+#include
+
+using namespace game::ant;
+
+template <>
+trait::head* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
+{
+ // Load JSON data
+ json* data = resource_loader::load(resource_manager, file, path);
+
+ // Validate trait file
+ auto head_element = data->find("head");
+ if (head_element == data->end())
+ throw std::runtime_error("Invalid head trait.");
+
+ // Allocate head trait
+ trait::head* head = new trait::head();
+
+ // Load head model
+ auto model_element = head_element->find("model");
+ if (model_element == head_element->end())
+ throw std::runtime_error("Head trait doesn't specify head model.");
+ head->model = resource_manager->load(model_element->get());
+
+ // Parse head length
+ head->length = 0.0f;
+ if (auto length_element = head_element->find("length"); length_element != head_element->end())
+ head->length = length_element->get();
+
+ // Parse head width
+ head->width = 0.0f;
+ if (auto width_element = head_element->find("width"); width_element != head_element->end())
+ head->width = width_element->get();
+
+ // Parse head phragmotic
+ head->phragmotic = false;
+ if (auto phragmotic_element = head_element->find("phragmotic"); phragmotic_element != head_element->end())
+ head->phragmotic = phragmotic_element->get();
+
+ // Free JSON data
+ delete data;
+
+ return head;
+}
diff --git a/src/game/ant/trait/loader/larva-loader.cpp b/src/game/ant/trait/loader/larva-loader.cpp
new file mode 100644
index 0000000..7eb19b2
--- /dev/null
+++ b/src/game/ant/trait/loader/larva-loader.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#include "resources/resource-loader.hpp"
+#include "resources/resource-manager.hpp"
+#include "resources/json.hpp"
+#include "game/ant/trait/larva.hpp"
+#include "render/model.hpp"
+#include
+
+using namespace game::ant;
+
+template <>
+trait::larva* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
+{
+ // Load JSON data
+ json* data = resource_loader::load(resource_manager, file, path);
+
+ // Validate trait file
+ auto larva_element = data->find("larva");
+ if (larva_element == data->end())
+ throw std::runtime_error("Invalid larva trait.");
+
+ // Allocate larva trait
+ trait::larva* larva = new trait::larva();
+
+ // Load larva model
+ auto model_element = larva_element->find("model");
+ if (model_element == larva_element->end())
+ throw std::runtime_error("Larva trait doesn't specify larva model.");
+ larva->model = resource_manager->load(model_element->get());
+
+ // Parse larva instars
+ larva->instars = 0;
+ if (auto instars_element = larva_element->find("instars"); instars_element != larva_element->end())
+ larva->instars = instars_element->get();
+
+ // Free JSON data
+ delete data;
+
+ return larva;
+}
diff --git a/src/game/ant/trait/loader/legs-loader.cpp b/src/game/ant/trait/loader/legs-loader.cpp
new file mode 100644
index 0000000..aebff06
--- /dev/null
+++ b/src/game/ant/trait/loader/legs-loader.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#include "resources/resource-loader.hpp"
+#include "resources/resource-manager.hpp"
+#include "resources/json.hpp"
+#include "game/ant/trait/legs.hpp"
+#include "render/model.hpp"
+#include
+
+using namespace game::ant;
+
+template <>
+trait::legs* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
+{
+ // Load JSON data
+ json* data = resource_loader::load(resource_manager, file, path);
+
+ // Validate trait file
+ auto legs_element = data->find("legs");
+ if (legs_element == data->end())
+ throw std::runtime_error("Invalid legs trait.");
+
+ // Allocate legs trait
+ trait::legs* legs = new trait::legs();
+
+ // Load legs model
+ auto model_element = legs_element->find("model");
+ if (model_element == legs_element->end())
+ throw std::runtime_error("Legs trait doesn't specify legs model.");
+ legs->model = resource_manager->load(model_element->get());
+
+ // Parse legs speed
+ legs->speed = 0.0f;
+ if (auto speed_element = legs_element->find("speed"); speed_element != legs_element->end())
+ legs->speed = speed_element->get();
+
+ // Free JSON data
+ delete data;
+
+ return legs;
+}
diff --git a/src/game/ant/trait/loader/mandibles-loader.cpp b/src/game/ant/trait/loader/mandibles-loader.cpp
new file mode 100644
index 0000000..495d823
--- /dev/null
+++ b/src/game/ant/trait/loader/mandibles-loader.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#include "resources/resource-loader.hpp"
+#include "resources/resource-manager.hpp"
+#include "resources/json.hpp"
+#include "game/ant/trait/mandibles.hpp"
+#include "render/model.hpp"
+#include
+
+using namespace game::ant;
+
+template <>
+trait::mandibles* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
+{
+ // Load JSON data
+ json* data = resource_loader::load(resource_manager, file, path);
+
+ // Validate trait file
+ auto mandibles_element = data->find("mandibles");
+ if (mandibles_element == data->end())
+ throw std::runtime_error("Invalid mandibles trait.");
+
+ // Allocate mandibles trait
+ trait::mandibles* mandibles = new trait::mandibles();
+
+ // Load mandibles model
+ auto model_element = mandibles_element->find("model");
+ if (model_element == mandibles_element->end())
+ throw std::runtime_error("Mandibles trait doesn't specify mandibles model.");
+ mandibles->model = resource_manager->load(model_element->get());
+
+ // Parse mandibles length
+ mandibles->length = 0.0f;
+ if (auto length_element = mandibles_element->find("length"); length_element != mandibles_element->end())
+ mandibles->length = length_element->get();
+
+ // Parse mandibles locking
+ mandibles->locking = false;
+ if (auto locking_element = mandibles_element->find("locking"); locking_element != mandibles_element->end())
+ mandibles->locking = locking_element->get();
+
+ // Free JSON data
+ delete data;
+
+ return mandibles;
+}
diff --git a/src/game/ant/trait/loader/mesosoma-loader.cpp b/src/game/ant/trait/loader/mesosoma-loader.cpp
new file mode 100644
index 0000000..0256a65
--- /dev/null
+++ b/src/game/ant/trait/loader/mesosoma-loader.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#include "resources/resource-loader.hpp"
+#include "resources/resource-manager.hpp"
+#include "resources/json.hpp"
+#include "game/ant/trait/mesosoma.hpp"
+#include "render/model.hpp"
+#include
+
+using namespace game::ant;
+
+template <>
+trait::mesosoma* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
+{
+ // Load JSON data
+ json* data = resource_loader::load(resource_manager, file, path);
+
+ // Validate trait file
+ auto mesosoma_element = data->find("mesosoma");
+ if (mesosoma_element == data->end())
+ throw std::runtime_error("Invalid mesosoma trait.");
+
+ // Allocate mesosoma trait
+ trait::mesosoma* mesosoma = new trait::mesosoma();
+
+ // Load mesosoma model
+ auto model_element = mesosoma_element->find("model");
+ if (model_element == mesosoma_element->end())
+ throw std::runtime_error("Mesosoma trait doesn't specify mesosoma model.");
+ mesosoma->model = resource_manager->load(model_element->get());
+
+ // Parse mesosoma length
+ mesosoma->length = 0.0f;
+ if (auto length_element = mesosoma_element->find("length"); length_element != mesosoma_element->end())
+ mesosoma->length = length_element->get();
+
+ // Parse mesosoma width
+ mesosoma->width = 0.0f;
+ if (auto width_element = mesosoma_element->find("width"); width_element != mesosoma_element->end())
+ mesosoma->width = width_element->get();
+
+ // Parse mesosoma spinescence
+ mesosoma->spinescence = 0.0f;
+ if (auto spinescence_element = mesosoma_element->find("spinescence"); spinescence_element != mesosoma_element->end())
+ mesosoma->spinescence = spinescence_element->get();
+
+ // Free JSON data
+ delete data;
+
+ return mesosoma;
+}
diff --git a/src/game/ant/trait/loader/nest-loader.cpp b/src/game/ant/trait/loader/nest-loader.cpp
new file mode 100644
index 0000000..c9feb77
--- /dev/null
+++ b/src/game/ant/trait/loader/nest-loader.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#include "resources/resource-loader.hpp"
+#include "resources/resource-manager.hpp"
+#include "resources/json.hpp"
+#include "game/ant/trait/nest.hpp"
+#include "game/ant/nest-site.hpp"
+#include
+
+using namespace game::ant;
+
+template <>
+trait::nest* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
+{
+ // Load JSON data
+ json* data = resource_loader::load(resource_manager, file, path);
+
+ // Validate trait file
+ auto nest_element = data->find("nest");
+ if (nest_element == data->end())
+ throw std::runtime_error("Invalid nest trait.");
+
+ // Allocate nest trait
+ trait::nest* nest = new trait::nest();
+
+ // Parse nest site
+ nest->site = nest_site::hypogeic;
+ if (auto site_element = nest_element->find("site"); site_element != nest_element->end())
+ {
+ std::string site = site_element->get();
+ if (site == "hypogeic")
+ nest->site = nest_site::hypogeic;
+ else if (site == "arboreal")
+ nest->site = nest_site::arboreal;
+ }
+
+ // Free JSON data
+ delete data;
+
+ return nest;
+}
diff --git a/src/game/ant/trait/loader/ocelli-loader.cpp b/src/game/ant/trait/loader/ocelli-loader.cpp
new file mode 100644
index 0000000..2ba46ba
--- /dev/null
+++ b/src/game/ant/trait/loader/ocelli-loader.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#include "resources/resource-loader.hpp"
+#include "resources/resource-manager.hpp"
+#include "resources/json.hpp"
+#include "game/ant/trait/ocelli.hpp"
+#include "render/model.hpp"
+#include
+
+using namespace game::ant;
+
+template <>
+trait::ocelli* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
+{
+ // Load JSON data
+ json* data = resource_loader::load(resource_manager, file, path);
+
+ // Validate trait file
+ auto ocelli_element = data->find("ocelli");
+ if (ocelli_element == data->end())
+ throw std::runtime_error("Invalid ocelli trait.");
+
+ // Allocate ocelli trait
+ trait::ocelli* ocelli = new trait::ocelli();
+
+ // Load ocelli model (if not null)
+ auto model_element = ocelli_element->find("model");
+ if (model_element == ocelli_element->end())
+ throw std::runtime_error("Ocelli trait doesn't specify ocelli model.");
+ if (model_element->is_null())
+ {
+ ocelli->model = nullptr;
+ }
+ else
+ {
+ ocelli->model = resource_manager->load(model_element->get());
+ }
+
+ // Parse median ocellus
+ ocelli->median_ocellus = false;
+ if (auto median_ocellus_element = ocelli_element->find("median_ocellus"); median_ocellus_element != ocelli_element->end())
+ ocelli->median_ocellus = median_ocellus_element->get();
+
+ // Parse lateral ocelli
+ ocelli->lateral_ocelli = false;
+ if (auto lateral_ocelli_element = ocelli_element->find("lateral_ocelli"); lateral_ocelli_element != ocelli_element->end())
+ ocelli->lateral_ocelli = lateral_ocelli_element->get();
+
+ // Parse ocelli width
+ ocelli->width = 0.0f;
+ if (auto width_element = ocelli_element->find("width"); width_element != ocelli_element->end())
+ ocelli->width = width_element->get();
+
+ // Parse ocelli height
+ ocelli->height = 0.0f;
+ if (auto height_element = ocelli_element->find("height"); height_element != ocelli_element->end())
+ ocelli->height = height_element->get();
+
+ // Free JSON data
+ delete data;
+
+ return ocelli;
+}
diff --git a/src/game/ant/trait/loader/pigmentation-loader.cpp b/src/game/ant/trait/loader/pigmentation-loader.cpp
new file mode 100644
index 0000000..f9cff8e
--- /dev/null
+++ b/src/game/ant/trait/loader/pigmentation-loader.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#include "resources/resource-loader.hpp"
+#include "resources/resource-manager.hpp"
+#include "resources/json.hpp"
+#include "game/ant/trait/pigmentation.hpp"
+#include
+
+using namespace game::ant;
+
+template <>
+trait::pigmentation* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
+{
+ // Load JSON data
+ json* data = resource_loader::load(resource_manager, file, path);
+
+ // Validate trait file
+ auto pigmentation_element = data->find("pigmentation");
+ if (pigmentation_element == data->end())
+ throw std::runtime_error("Invalid pigmentation trait.");
+
+ // Allocate pigmentation trait
+ trait::pigmentation* pigmentation = new trait::pigmentation();
+
+ // Parse pigmentation primary albedo
+ pigmentation->primary_albedo = {0.0, 0.0, 0.0};
+ if (auto primary_albedo_element = pigmentation_element->find("primary_albedo"); primary_albedo_element != pigmentation_element->end())
+ {
+ pigmentation->primary_albedo.x = (*primary_albedo_element)[0].get();
+ pigmentation->primary_albedo.y = (*primary_albedo_element)[1].get();
+ pigmentation->primary_albedo.z = (*primary_albedo_element)[2].get();
+ }
+
+ // Parse pigmentation secondary albedo
+ pigmentation->secondary_albedo = {0.0, 0.0, 0.0};
+ if (auto secondary_albedo_element = pigmentation_element->find("secondary_albedo"); secondary_albedo_element != pigmentation_element->end())
+ {
+ pigmentation->secondary_albedo.x = (*secondary_albedo_element)[0].get();
+ pigmentation->secondary_albedo.y = (*secondary_albedo_element)[1].get();
+ pigmentation->secondary_albedo.z = (*secondary_albedo_element)[2].get();
+ }
+
+ // Free JSON data
+ delete data;
+
+ return pigmentation;
+}
diff --git a/src/game/ant/trait/loader/pilosity-loader.cpp b/src/game/ant/trait/loader/pilosity-loader.cpp
new file mode 100644
index 0000000..910dc70
--- /dev/null
+++ b/src/game/ant/trait/loader/pilosity-loader.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#include "resources/resource-loader.hpp"
+#include "resources/resource-manager.hpp"
+#include "resources/json.hpp"
+#include "game/ant/trait/pilosity.hpp"
+#include
+
+using namespace game::ant;
+
+template <>
+trait::pilosity* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
+{
+ // Load JSON data
+ json* data = resource_loader::load(resource_manager, file, path);
+
+ // Validate trait file
+ auto pilosity_element = data->find("pilosity");
+ if (pilosity_element == data->end())
+ throw std::runtime_error("Invalid pilosity trait.");
+
+ // Allocate pilosity trait
+ trait::pilosity* pilosity = new trait::pilosity();
+
+ // Parse pilosity density
+ pilosity->density = 0.0f;
+ if (auto density_element = pilosity_element->find("density"); density_element != pilosity_element->end())
+ pilosity->density = density_element->get();
+
+ // Free JSON data
+ delete data;
+
+ return pilosity;
+}
diff --git a/src/game/ant/trait/loader/sculpturing-loader.cpp b/src/game/ant/trait/loader/sculpturing-loader.cpp
new file mode 100644
index 0000000..5c1e5bc
--- /dev/null
+++ b/src/game/ant/trait/loader/sculpturing-loader.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#include "resources/resource-loader.hpp"
+#include "resources/resource-manager.hpp"
+#include "resources/json.hpp"
+#include "game/ant/trait/sculpturing.hpp"
+#include "gl/texture-2d.hpp"
+#include
+
+using namespace game::ant;
+
+template <>
+trait::sculpturing* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
+{
+ // Load JSON data
+ json* data = resource_loader::load(resource_manager, file, path);
+
+ // Validate trait file
+ auto sculpturing_element = data->find("sculpturing");
+ if (sculpturing_element == data->end())
+ throw std::runtime_error("Invalid sculpturing trait.");
+
+ // Allocate sculpturing trait
+ trait::sculpturing* sculpturing = new trait::sculpturing();
+
+ // Load sculpturing normal map
+ auto normal_map_element = sculpturing_element->find("normal_map");
+ if (normal_map_element == sculpturing_element->end())
+ throw std::runtime_error("Sculpturing trait doesn't specify sculpturing normal map.");
+ sculpturing->normal_map = resource_manager->load(normal_map_element->get());
+
+ // Parse sculpturing roughness
+ sculpturing->roughness = 0.0f;
+ if (auto roughness_element = sculpturing_element->find("roughness"); roughness_element != sculpturing_element->end())
+ sculpturing->roughness = roughness_element->get();
+
+ // Free JSON data
+ delete data;
+
+ return sculpturing;
+}
diff --git a/src/game/ant/trait/loader/sting-loader.cpp b/src/game/ant/trait/loader/sting-loader.cpp
new file mode 100644
index 0000000..cfa51df
--- /dev/null
+++ b/src/game/ant/trait/loader/sting-loader.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#include "resources/resource-loader.hpp"
+#include "resources/resource-manager.hpp"
+#include "resources/json.hpp"
+#include "game/ant/trait/sting.hpp"
+#include "render/model.hpp"
+#include
+
+using namespace game::ant;
+
+template <>
+trait::sting* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
+{
+ // Load JSON data
+ json* data = resource_loader::load(resource_manager, file, path);
+
+ // Validate trait file
+ auto sting_element = data->find("sting");
+ if (sting_element == data->end())
+ throw std::runtime_error("Invalid sting trait.");
+
+ // Allocate sting trait
+ trait::sting* sting = new trait::sting();
+
+ // Parse sting present
+ sting->present = false;
+ if (auto present_element = sting_element->find("present"); present_element != sting_element->end())
+ sting->present = present_element->get();
+
+ // Load sting model (if present)
+ if (sting->present)
+ {
+ auto model_element = sting_element->find("model");
+ if (model_element == sting_element->end())
+ throw std::runtime_error("Sting trait doesn't specify sting model.");
+ sting->model = resource_manager->load(model_element->get());
+ }
+ else
+ {
+ sting->model = nullptr;
+ }
+
+ // Free JSON data
+ delete data;
+
+ return sting;
+}
diff --git a/src/game/ant/trait/loader/waist-loader.cpp b/src/game/ant/trait/loader/waist-loader.cpp
new file mode 100644
index 0000000..3856709
--- /dev/null
+++ b/src/game/ant/trait/loader/waist-loader.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#include "resources/resource-loader.hpp"
+#include "resources/resource-manager.hpp"
+#include "resources/json.hpp"
+#include "game/ant/trait/waist.hpp"
+#include "render/model.hpp"
+#include
+
+using namespace game::ant;
+
+template <>
+trait::waist* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
+{
+ // Load JSON data
+ json* data = resource_loader::load(resource_manager, file, path);
+
+ // Validate trait file
+ auto waist_element = data->find("waist");
+ if (waist_element == data->end())
+ throw std::runtime_error("Invalid waist trait.");
+
+ // Allocate waist trait
+ trait::waist* waist = new trait::waist();
+
+ // Load waist model
+ auto model_element = waist_element->find("model");
+ if (model_element == waist_element->end())
+ throw std::runtime_error("Waist trait doesn't specify waist model.");
+ waist->model = resource_manager->load(model_element->get());
+
+ // Parse waist spinescence
+ waist->spinescence = 0.0f;
+ if (auto spinescence_element = waist_element->find("spinescence"); spinescence_element != waist_element->end())
+ waist->spinescence = spinescence_element->get();
+
+ // Parse waist petiole length
+ waist->petiole_length = 0.0f;
+ if (auto petiole_length_element = waist_element->find("petiole_length"); petiole_length_element != waist_element->end())
+ waist->petiole_length = petiole_length_element->get();
+
+ // Parse waist petiole width
+ waist->petiole_width = 0.0f;
+ if (auto petiole_width_element = waist_element->find("petiole_width"); petiole_width_element != waist_element->end())
+ waist->petiole_width = petiole_width_element->get();
+
+ // Parse waist petiole height
+ waist->petiole_height = 0.0f;
+ if (auto petiole_height_element = waist_element->find("petiole_height"); petiole_height_element != waist_element->end())
+ waist->petiole_height = petiole_height_element->get();
+
+ // Parse waist postpetiole
+ waist->postpetiole = false;
+ if (auto postpetiole_element = waist_element->find("postpetiole"); postpetiole_element != waist_element->end())
+ waist->postpetiole = postpetiole_element->get();
+
+ waist->postpetiole_length = 0.0f;
+ waist->postpetiole_width = 0.0f;
+ waist->postpetiole_height = 0.0f;
+
+ if (waist->postpetiole)
+ {
+ // Parse waist postpetiole length
+ if (auto postpetiole_length_element = waist_element->find("postpetiole_length"); postpetiole_length_element != waist_element->end())
+ waist->postpetiole_length = postpetiole_length_element->get();
+
+ // Parse waist postpetiole width
+ if (auto postpetiole_width_element = waist_element->find("postpetiole_width"); postpetiole_width_element != waist_element->end())
+ waist->postpetiole_width = postpetiole_width_element->get();
+
+ // Parse waist postpetiole height
+ if (auto postpetiole_height_element = waist_element->find("postpetiole_height"); postpetiole_height_element != waist_element->end())
+ waist->postpetiole_height = postpetiole_height_element->get();
+ }
+
+ // Free JSON data
+ delete data;
+
+ return waist;
+}
diff --git a/src/game/ant/trait/mandibles.hpp b/src/game/ant/trait/mandibles.hpp
new file mode 100644
index 0000000..4b58c8d
--- /dev/null
+++ b/src/game/ant/trait/mandibles.hpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_TRAIT_MANDIBLES_HPP
+#define ANTKEEPER_GAME_ANT_TRAIT_MANDIBLES_HPP
+
+#include "render/model.hpp"
+
+namespace game {
+namespace ant {
+namespace trait {
+
+/**
+ * Trait that describes the mandibles of an ant.
+ */
+struct mandibles
+{
+ /// Length of the closed mandibles in full face view (MandL), measured in mesosomal lengths.
+ float length;
+
+ /// Indicates the mandibles are able to lock open, such as in trap-jaw ants.
+ bool locking;
+
+ /// 3D model of the mandibles.
+ render::model* model;
+};
+
+} // namespace trait
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_TRAIT_MANDIBLES_HPP
diff --git a/src/game/ant/trait/mesosoma.hpp b/src/game/ant/trait/mesosoma.hpp
new file mode 100644
index 0000000..5f96394
--- /dev/null
+++ b/src/game/ant/trait/mesosoma.hpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_TRAIT_MESOSOMA_HPP
+#define ANTKEEPER_GAME_ANT_TRAIT_MESOSOMA_HPP
+
+#include "render/model.hpp"
+
+namespace game {
+namespace ant {
+namespace trait {
+
+/**
+ * Trait that describes the mesosoma of an ant.
+ */
+struct mesosoma
+{
+ /// Mesosoma length (ML), also known as the Weber's length (WL).
+ float length;
+
+ /// Pronotum width in dorsal view (PrW).
+ float width;
+
+ /// Degree of spinescence.
+ float spinescence;
+
+ /// 3D model of the mesosoma.
+ render::model* model;
+};
+
+} // namespace trait
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_TRAIT_MESOSOMA_HPP
diff --git a/src/game/ant/trait/nest.hpp b/src/game/ant/trait/nest.hpp
new file mode 100644
index 0000000..3349b13
--- /dev/null
+++ b/src/game/ant/trait/nest.hpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_TRAIT_NEST_HPP
+#define ANTKEEPER_GAME_ANT_TRAIT_NEST_HPP
+
+#include "game/ant/nest-site.hpp"
+
+namespace game {
+namespace ant {
+namespace trait {
+
+/**
+ * Trait that describes the nest site of an ant.
+ */
+struct nest
+{
+ /// Site of the nest.
+ game::ant::nest_site site;
+};
+
+} // namespace trait
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_TRAIT_NEST_HPP
diff --git a/src/game/ant/trait/ocelli.hpp b/src/game/ant/trait/ocelli.hpp
new file mode 100644
index 0000000..03fb800
--- /dev/null
+++ b/src/game/ant/trait/ocelli.hpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_TRAIT_OCELLI_HPP
+#define ANTKEEPER_GAME_ANT_TRAIT_OCELLI_HPP
+
+#include "render/model.hpp"
+
+namespace game {
+namespace ant {
+namespace trait {
+
+/**
+ * Trait that describes the ocelli of an ant.
+ */
+struct ocelli
+{
+ /// Median ocellus present.
+ bool median_ocellus;
+
+ /// Lateral ocelli present.
+ bool lateral_ocelli;
+
+ /// Ocellus width, in mesosomal lengths.
+ float width;
+
+ /// Ocellus height, in mesosomal lengths.
+ float height;
+
+ /// 3D model of the ocelli.
+ render::model* model;
+};
+
+} // namespace trait
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_TRAIT_OCELLI_HPP
diff --git a/src/game/ant/trait/pigmentation.hpp b/src/game/ant/trait/pigmentation.hpp
new file mode 100644
index 0000000..b981ab9
--- /dev/null
+++ b/src/game/ant/trait/pigmentation.hpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_TRAIT_PIGMENTATION_HPP
+#define ANTKEEPER_GAME_ANT_TRAIT_PIGMENTATION_HPP
+
+#include "utility/fundamental-types.hpp"
+
+namespace game {
+namespace ant {
+namespace trait {
+
+/**
+ * Trait that describes the pigmentation of an ant.
+ */
+struct pigmentation
+{
+ /// Primary albedo color.
+ float3 primary_albedo;
+
+ /// Secondary albedo color.
+ float3 secondary_albedo;
+};
+
+} // namespace trait
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_TRAIT_PIGMENTATION_HPP
diff --git a/src/game/ant/trait/pilosity.hpp b/src/game/ant/trait/pilosity.hpp
new file mode 100644
index 0000000..4139e83
--- /dev/null
+++ b/src/game/ant/trait/pilosity.hpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_TRAIT_PILOSITY_HPP
+#define ANTKEEPER_GAME_ANT_TRAIT_PILOSITY_HPP
+
+namespace game {
+namespace ant {
+namespace trait {
+
+/**
+ * Trait that describes the pilosity of an ant.
+ */
+struct pilosity
+{
+ /// Hair density.
+ float density;
+};
+
+} // namespace trait
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_TRAIT_PILOSITY_HPP
diff --git a/src/game/ant/trait/sculpturing.hpp b/src/game/ant/trait/sculpturing.hpp
new file mode 100644
index 0000000..bc2b130
--- /dev/null
+++ b/src/game/ant/trait/sculpturing.hpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_TRAIT_SCULPTURING_HPP
+#define ANTKEEPER_GAME_ANT_TRAIT_SCULPTURING_HPP
+
+#include "gl/texture-2d.hpp"
+
+namespace game {
+namespace ant {
+namespace trait {
+
+/**
+ * Trait that describes the surface sculpturing of an ant.
+ */
+struct sculpturing
+{
+ /// Surface roughness.
+ float roughness;
+
+ /// Surface culpturing normal map.
+ gl::texture_2d* normal_map;
+};
+
+} // namespace trait
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_TRAIT_SCULPTURING_HPP
diff --git a/src/game/ant/trait/size.hpp b/src/game/ant/trait/size.hpp
new file mode 100644
index 0000000..a333c23
--- /dev/null
+++ b/src/game/ant/trait/size.hpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_TRAIT_SIZE_HPP
+#define ANTKEEPER_GAME_ANT_TRAIT_SIZE_HPP
+
+namespace game {
+namespace ant {
+namespace trait {
+
+/**
+ * Trait that describes the sizes of an ant caste.
+ */
+struct size
+{
+ /// Size-frequency distribution, with sizes measured in mesosomal lengths.
+ std::vector> distribution;
+};
+
+} // namespace trait
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_TRAIT_SIZE_HPP
diff --git a/src/game/ant/trait/sting.hpp b/src/game/ant/trait/sting.hpp
new file mode 100644
index 0000000..9fec63f
--- /dev/null
+++ b/src/game/ant/trait/sting.hpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_TRAIT_STING_HPP
+#define ANTKEEPER_GAME_ANT_TRAIT_STING_HPP
+
+#include "render/model.hpp"
+
+namespace game {
+namespace ant {
+namespace trait {
+
+/**
+ * Trait that describes the sting of an ant.
+ */
+struct sting
+{
+ /// Indicates whether a sting present or not.
+ bool present;
+
+ /// 3D model of the sting.
+ render::model* model;
+};
+
+} // namespace trait
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_TRAIT_STING_HPP
diff --git a/src/game/ant/trait/waist.hpp b/src/game/ant/trait/waist.hpp
new file mode 100644
index 0000000..39ed15b
--- /dev/null
+++ b/src/game/ant/trait/waist.hpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_ANT_TRAIT_WAIST_HPP
+#define ANTKEEPER_GAME_ANT_TRAIT_WAIST_HPP
+
+#include "render/model.hpp"
+
+namespace game {
+namespace ant {
+namespace trait {
+
+/**
+ * Trait that describes the waist (petiole plus postpetiole) of an ant.
+ */
+struct waist
+{
+ /// 3D model of the waist.
+ render::model* model;
+
+ /// Degree of spinescence.
+ float spinescence;
+
+ /// Postpetiole presence.
+ bool postpetiole;
+
+ /// Petiole length in dorsal view (PetL).
+ float petiole_length;
+
+ /// Petiole width in dorsal view (PetW).
+ float petiole_width;
+
+ /// Petiole height in in lateral profile (PetH).
+ float petiole_height;
+
+ /// Postpetiole length in dorsal view (PPL).
+ float postpetiole_length;
+
+ /// Postpetiole width in dorsal view (PPW).
+ float postpetiole_width;
+
+ /// Postpetiole height in in lateral profile (PPH).
+ float postpetiole_height;
+};
+
+} // namespace trait
+} // namespace ant
+} // namespace game
+
+#endif // ANTKEEPER_GAME_ANT_TRAIT_WAIST_HPP
diff --git a/src/game/load.cpp b/src/game/load.cpp
new file mode 100644
index 0000000..525dbf4
--- /dev/null
+++ b/src/game/load.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#include "game/load.hpp"
+#include "application.hpp"
+#include "debug/logger.hpp"
+#include "resources/json.hpp"
+#include "resources/resource-manager.hpp"
+#include "render/model.hpp"
+#include "render/material.hpp"
+#include "render/passes/sky-pass.hpp"
+#include "render/passes/ground-pass.hpp"
+#include "entity/systems/astronomy.hpp"
+#include
+
+namespace game {
+namespace load {
+
+void biome(game::context& ctx, const std::filesystem::path& path)
+{
+ ctx.logger->push_task("Loading biome from \"" + path.string() + "\"");
+ try
+ {
+ json* data = ctx.resource_manager->load(path);
+
+ // Load location
+ if (auto location = data->find("location"); location != data->end())
+ {
+ double elevation = 0.0;
+ double latitude = 0.0;
+ double longitude = 0.0;
+
+ if (auto location_ele = location->find("elevation"); location_ele != location->end())
+ elevation = location_ele->get();
+ else
+ ctx.logger->warning("Biome elevation undefined");
+
+ if (auto location_lat = location->find("latitude"); location_lat != location->end())
+ latitude = math::radians(location_lat->get());
+ else
+ ctx.logger->warning("Biome latitude undefined");
+
+ if (auto location_lon = location->find("longitude"); location_lon != location->end())
+ longitude = math::radians(location_lon->get());
+ else
+ ctx.logger->warning("Biome longitude undefined");
+
+ ctx.astronomy_system->set_observer_location({elevation, latitude, longitude});
+ }
+ else
+ {
+ ctx.logger->warning("Biome location undefined");
+ }
+
+ // Setup sky
+ ctx.sky_pass->set_sky_model(ctx.resource_manager->load("celestial-hemisphere.mdl"));
+
+ // Load terrain
+ if (auto terrain = data->find("terrain"); terrain != data->end())
+ {
+ if (auto material = terrain->find("material"); material != terrain->end())
+ {
+ render::model* terrestrial_hemisphere_model = ctx.resource_manager->load("terrestrial-hemisphere.mdl");
+ (*terrestrial_hemisphere_model->get_groups())[0]->set_material(ctx.resource_manager->load(material->get()));
+ ctx.ground_pass->set_ground_model(terrestrial_hemisphere_model);
+ }
+ else
+ {
+ ctx.logger->warning("Biome terrain material undefined");
+ }
+ }
+ else
+ {
+ ctx.logger->warning("Biome terrain undefined");
+ }
+ }
+ catch (...)
+ {
+ ctx.logger->pop_task(EXIT_FAILURE);
+ }
+ ctx.logger->pop_task(EXIT_SUCCESS);
+}
+
+void colony(game::context& ctx, const std::filesystem::path& path)
+{
+ ctx.logger->push_task("Loading colony from \"" + path.string() + "\"");
+ try
+ {
+ json* data = ctx.resource_manager->load(path);
+
+ }
+ catch (...)
+ {
+ ctx.logger->pop_task(EXIT_FAILURE);
+ }
+ ctx.logger->pop_task(EXIT_SUCCESS);
+}
+
+} // namespace load
+} // namespace game
diff --git a/src/game/load.hpp b/src/game/load.hpp
new file mode 100644
index 0000000..532b24a
--- /dev/null
+++ b/src/game/load.hpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 Christopher J. Howard
+ *
+ * This file is part of Antkeeper source code.
+ *
+ * Antkeeper source code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper source code. If not, see .
+ */
+
+#ifndef ANTKEEPER_GAME_LOAD_HPP
+#define ANTKEEPER_GAME_LOAD_HPP
+
+#include "game/context.hpp"
+
+namespace game {
+namespace load {
+
+/**
+ * Loads a biome.
+ */
+void biome(game::context& ctx, const std::filesystem::path& path);
+
+/**
+ * Loads a colony
+ */
+void colony(game::context& ctx, const std::filesystem::path& path);
+
+} // namespace load
+} // namespace game
+
+#endif // ANTKEEPER_GAME_LOAD_HPP
diff --git a/src/game/save.cpp b/src/game/save.cpp
index a33985c..3752a36 100644
--- a/src/game/save.cpp
+++ b/src/game/save.cpp
@@ -20,18 +20,69 @@
#include "game/save.hpp"
#include "application.hpp"
#include "debug/logger.hpp"
+#include "resources/json.hpp"
#include
namespace game {
+namespace save {
-void save_config(game::context& ctx)
+void colony(game::context& ctx)
+{
+ std::filesystem::path path = ctx.saves_path / "colony.sav";
+ ctx.logger->push_task("Saving colony to \"" + path.string() + "\"");
+ try
+ {
+ // Construct JSON data describing the colony
+ json data;
+
+ auto& colony = data["colony"];
+ {
+ auto& species = colony["species"];
+ {
+ auto& morphology = species["morphology"];
+ {
+
+ }
+
+ auto& diet = species["diet"];
+ auto& aggression = species["aggression"];
+ auto& nest = species["nest"];
+ }
+
+ auto& habitat = colony["habitat"];
+ {
+ auto& biome = habitat["biome"];
+ auto& nest = habitat["nest"];
+ {
+ nest["entrance"] = {0, 0, 0};
+ }
+ }
+
+ auto& members = colony["members"];
+ members = json::array();
+ {
+
+ }
+ }
+
+ std::ofstream file(path);
+ file << data;
+ }
+ catch (...)
+ {
+ ctx.logger->pop_task(EXIT_FAILURE);
+ }
+ ctx.logger->pop_task(EXIT_SUCCESS);
+}
+
+void config(game::context& ctx)
{
std::filesystem::path path = ctx.config_path / "config.json";
ctx.logger->push_task("Saving config to \"" + path.string() + "\"");
try
{
- std::ofstream config_file(path);
- config_file << *(ctx.config);
+ std::ofstream file(path);
+ file << *(ctx.config);
}
catch (...)
{
@@ -40,4 +91,5 @@ void save_config(game::context& ctx)
ctx.logger->pop_task(EXIT_SUCCESS);
}
+} // namespace save
} // namespace game
diff --git a/src/game/save.hpp b/src/game/save.hpp
index dc60af5..e25fa9c 100644
--- a/src/game/save.hpp
+++ b/src/game/save.hpp
@@ -23,9 +23,19 @@
#include "game/context.hpp"
namespace game {
+namespace save {
-void save_config(game::context& ctx);
+/**
+ * Saves the current ant colony.
+ */
+void colony(game::context& ctx);
+
+/**
+ * Saves the current configuration.
+ */
+void config(game::context& ctx);
+} // namespace save
} // namespace game
#endif // ANTKEEPER_GAME_SAVE_HPP
diff --git a/src/game/state/boot.cpp b/src/game/state/boot.cpp
index 95ed1b2..1ddf52a 100644
--- a/src/game/state/boot.cpp
+++ b/src/game/state/boot.cpp
@@ -309,18 +309,7 @@ void boot::setup_resources()
ctx.resource_manager->mount(ctx.data_package_path);
// Include resource search paths in order of priority
- ctx.resource_manager->include("/shaders/");
- ctx.resource_manager->include("/models/");
- ctx.resource_manager->include("/images/");
- ctx.resource_manager->include("/textures/");
- ctx.resource_manager->include("/materials/");
- ctx.resource_manager->include("/entities/");
- ctx.resource_manager->include("/behaviors/");
ctx.resource_manager->include("/controls/");
- ctx.resource_manager->include("/localization/");
- ctx.resource_manager->include("/localization/fonts/");
- ctx.resource_manager->include("/biomes/");
- ctx.resource_manager->include("/traits/");
ctx.resource_manager->include("/");
}
@@ -722,21 +711,7 @@ void boot::setup_scenes()
// Setup underground scene
{
ctx.underground_scene = new scene::collection();
-
- ctx.underground_ambient_light = new scene::ambient_light();
- ctx.underground_ambient_light->set_color({1, 1, 1});
- ctx.underground_ambient_light->set_intensity(0.1f);
- ctx.underground_ambient_light->update_tweens();
-
- ctx.flashlight_spot_light = new scene::spot_light();
- ctx.flashlight_spot_light->set_color({1, 1, 1});
- ctx.flashlight_spot_light->set_intensity(1.0f);
- ctx.flashlight_spot_light->set_attenuation({1.0f, 0.0f, 0.0f});
- ctx.flashlight_spot_light->set_cutoff({math::radians(10.0f), math::radians(19.0f)});
-
ctx.underground_scene->add_object(ctx.underground_camera);
- ctx.underground_scene->add_object(ctx.underground_ambient_light);
- //ctx.underground_scene->add_object(ctx.flashlight_spot_light);
}
// Setup surface scene
@@ -926,7 +901,7 @@ void boot::setup_systems()
// Setup render system
ctx.render_system = new entity::system::render(*ctx.entity_registry);
- ctx.render_system->add_layer(ctx.underground_scene);
+ //ctx.render_system->add_layer(ctx.underground_scene);
ctx.render_system->add_layer(ctx.surface_scene);
ctx.render_system->add_layer(ctx.ui_scene);
ctx.render_system->set_renderer(ctx.renderer);
@@ -1024,7 +999,7 @@ void boot::setup_controls()
// Save display mode config
(*ctx.config)["fullscreen"] = fullscreen;
- game::save_config(ctx);
+ game::save::config(ctx);
}
);
diff --git a/src/game/state/nuptial-flight.cpp b/src/game/state/nuptial-flight.cpp
index 850d91a..80286f4 100644
--- a/src/game/state/nuptial-flight.cpp
+++ b/src/game/state/nuptial-flight.cpp
@@ -22,10 +22,11 @@
#include "entity/archetype.hpp"
#include "entity/systems/camera.hpp"
#include "entity/systems/astronomy.hpp"
-#include "entity/components/observer.hpp"
+#include "entity/components/locomotion.hpp"
#include "entity/components/transform.hpp"
#include "entity/components/terrain.hpp"
#include "entity/components/camera.hpp"
+#include "entity/components/model.hpp"
#include "entity/components/constraints/spring-to.hpp"
#include "entity/components/constraints/three-dof.hpp"
#include "entity/components/constraint-stack.hpp"
@@ -38,8 +39,12 @@
#include "render/passes/clear-pass.hpp"
#include "render/passes/ground-pass.hpp"
#include "state-machine.hpp"
-#include "scene/ambient-light.hpp"
#include "config.hpp"
+#include "game/load.hpp"
+#include "game/ant/breed.hpp"
+#include "game/ant/morphogenesis.hpp"
+
+using namespace game::ant;
namespace game {
namespace state {
@@ -49,81 +54,67 @@ nuptial_flight::nuptial_flight(game::context& ctx):
{
ctx.logger->push_task("Entering nuptial flight state");
+ // Allocate ant breed
+ ant::breed breed;
+
+ // Load morphological traits
+ breed.head = ctx.resource_manager->load("collared-harvester-head.dna");
+ breed.mandibles = ctx.resource_manager->load("harvester-mandibles.dna");
+ breed.antennae = ctx.resource_manager->load("slender-antennae.dna");
+ breed.eyes = ctx.resource_manager->load("vestigial-eyes.dna");
+ breed.mesosoma = ctx.resource_manager->load("humpback-mesosoma.dna");
+ breed.legs = ctx.resource_manager->load("trekking-legs.dna");
+ breed.waist = ctx.resource_manager->load("harvester-waist.dna");
+ breed.gaster = ctx.resource_manager->load("ovoid-gaster.dna");
+ breed.ocelli = ctx.resource_manager->load("absent-ocelli.dna");
+ breed.sting = ctx.resource_manager->load("bullet-sting.dna");
+ breed.sculpturing = ctx.resource_manager->load("politus-sculpturing.dna");
+ breed.pigmentation = ctx.resource_manager->load("onyx-pigmentation.dna");
+ breed.egg = ctx.resource_manager->load("ellipsoid-egg.dna");
+ breed.larva = ctx.resource_manager->load("old-larva.dna");
+ breed.cocoon = ctx.resource_manager->load("cocoon-present.dna");
+ breed.pilosity = ctx.resource_manager->load("hairless-pilosity.dna");
+ breed.forewings = nullptr;
+ breed.hindwings = nullptr;
+
+ // Load behavioral traits
+ breed.foraging_time = ctx.resource_manager->load("crepuscular-foraging-time.dna");
+ breed.diet = nullptr;
+ breed.nest = ctx.resource_manager->load("hypogeic-nest.dna");
+
+ // Build caste models
+ render::model* worker_model = ant::morphogenesis(breed, ant::caste::worker);
+
// Disable UI color clear
ctx.ui_clear_pass->set_cleared_buffers(false, true, false);
- // Setup and enable sky pass
- ctx.sky_pass->set_sky_model(ctx.resource_manager->load("celestial-hemisphere.mdl"));
- ctx.sky_pass->set_enabled(true);
-
- // Setup and enable ground pass
- render::model* terrestrial_hemisphere_model = ctx.resource_manager->load("terrestrial-hemisphere.mdl");
- (*terrestrial_hemisphere_model->get_groups())[0]->set_material(ctx.resource_manager->load("scrub-terrestrial-hemisphere.mtl"));
- ctx.ground_pass->set_ground_model(terrestrial_hemisphere_model);
- ctx.ground_pass->set_enabled(true);
-
- // Create world
- game::world::create_stars(ctx);
- game::world::create_sun(ctx);
- game::world::create_planet(ctx);
- game::world::create_moon(ctx);
-
- // Set time to solar noon
- game::world::set_time(ctx, 0.0);
-
- // Freeze time
- game::world::set_time_scale(ctx, 0.0);
-
- // Find planet EID by name
- entity::id planet_eid = ctx.entities["planet"];
-
- // Remove terrain component from planet (if any)
- //if (ctx.entity_registry->has(planet_eid))
- // ctx.entity_registry->remove(planet_eid);
-
- // Enable clouds in sky pass
- //ctx.sky_pass->set_clouds_model(ctx.resource_manager->load("cloud-plane.mdl"));
-
- // Create biome terrain component
- /*
- entity::component::terrain biome_terrain;
- biome_terrain.max_lod = 18;
- biome_terrain.patch_material = ctx.resource_manager->load("desert-terrain.mtl");
- biome_terrain.elevation = [](double, double) -> double
- {
- return 0.0;
- };
- // Replace planet terrain component with biome terrain component
- ctx.entity_registry->replace(planet_eid, biome_terrain);
- */
-
- // Create observer
- entity::id observer_eid = ctx.entity_registry->create();
+ // Create world if not yet created
+ if (ctx.entities.find("planet") == ctx.entities.end())
{
- entity::component::observer observer;
- observer.reference_body_eid = planet_eid;
- observer.elevation = 2000.0;
- observer.latitude = 0.0;
- observer.longitude = 0.0;
- observer.camera = ctx.surface_camera;
- ctx.entity_registry->assign(observer_eid, observer);
+ game::world::create_stars(ctx);
+ game::world::create_sun(ctx);
+ game::world::create_planet(ctx);
+ game::world::create_moon(ctx);
+
+ // Set time to solar noon
+ game::world::set_time(ctx, 0.3);
- // Set reference location of astronomy system
- ctx.astronomy_system->set_reference_body(planet_eid);
- ctx.astronomy_system->set_observer_location(double3{observer.elevation, observer.latitude, observer.longitude});
+ // Freeze time
+ game::world::set_time_scale(ctx, 0.0);
}
- /*
- scene::ambient_light* light = new scene::ambient_light();
- light->set_color(float3{1, 1, 1} * 10000.0f);
- ctx.surface_scene->add_object(light);
- */
+ // Load biome
+ game::load::biome(ctx, "desert-scrub.bio");
+
+ // Setup and enable sky and ground passes
+ ctx.sky_pass->set_enabled(true);
+ ctx.ground_pass->set_enabled(true);
// Create color checker
{
entity::archetype* color_checker_archetype = ctx.resource_manager->load("color-checker.ent");
auto color_checker_eid = color_checker_archetype->create(*ctx.entity_registry);
- entity::command::warp_to(*ctx.entity_registry, color_checker_eid, {0, 0, 0});
+ entity::command::warp_to(*ctx.entity_registry, color_checker_eid, {0, 0, -10});
}
// Create ruler
@@ -133,6 +124,48 @@ nuptial_flight::nuptial_flight(game::context& ctx):
entity::command::warp_to(*ctx.entity_registry, ruler_10cm_eid, {0, 0, 10});
}
+ // Create ant_test
+ {
+ entity::archetype* ant_test_10cm_archetype = ctx.resource_manager->load("ant-test.ent");
+ auto ant_test_eid = ant_test_10cm_archetype->create(*ctx.entity_registry);
+ entity::command::warp_to(*ctx.entity_registry, ant_test_eid, {10, 0, 0});
+ }
+
+ // Create keeper if not yet created
+ if (ctx.entities.find("keeper") == ctx.entities.end())
+ {
+ entity::id keeper_eid = ctx.entity_registry->create();
+ ctx.entities["keeper"] = keeper_eid;
+ }
+
+ // Create ant if not created
+ if (ctx.entities.find("ant") == ctx.entities.end())
+ {
+ auto boid_eid = ctx.entity_registry->create();
+
+ entity::component::model model;
+ model.render_model = ctx.resource_manager->load("ant-test.mdl");
+ model.instance_count = 0;
+ model.layers = 1;
+ ctx.entity_registry->assign(boid_eid, model);
+
+ entity::component::transform transform;
+ transform.local = math::identity_transform;
+ transform.world = math::identity_transform;
+ transform.warp = true;
+ ctx.entity_registry->assign(boid_eid, transform);
+
+ entity::component::locomotion locomotion;
+ locomotion.yaw = 0.0f;
+ ctx.entity_registry->assign(boid_eid, locomotion);
+
+ // Set target ant
+ ctx.entities["ant"] = boid_eid;
+ }
+
+ // Start as ant-keeper
+ is_keeper = true;
+
// Setup camera
setup_camera();
@@ -141,7 +174,7 @@ nuptial_flight::nuptial_flight(game::context& ctx):
ctx.function_queue.push(std::bind(&screen_transition::transition, ctx.fade_transition, config::nuptial_flight_fade_in_duration, true, ease::out_sine, true, nullptr));
// Queue control setup
- ctx.function_queue.push(std::bind(&nuptial_flight::enable_controls, this));
+ ctx.function_queue.push(std::bind(&nuptial_flight::enable_keeper_controls, this));
ctx.logger->pop_task(EXIT_SUCCESS);
}
@@ -150,10 +183,6 @@ nuptial_flight::~nuptial_flight()
{
ctx.logger->push_task("Exiting nuptial flight state");
- // Resume time
- //const double time_scale = (*ctx.config)["time_scale"].get();
- //game::world::set_time_scale(ctx, time_scale);
-
ctx.logger->pop_task(EXIT_SUCCESS);
}
@@ -244,7 +273,7 @@ void nuptial_flight::setup_camera()
ctx.surface_camera->set_exposure(ev100);
}
-void nuptial_flight::enable_controls()
+void nuptial_flight::enable_keeper_controls()
{
// Get camera entities
entity::id camera_eid = ctx.entities["surface_cam"];
@@ -516,49 +545,322 @@ void nuptial_flight::enable_controls()
three_dof.pitch = std::min(math::radians(90.0f), three_dof.pitch);
}
);
- /*
- // Use tool
- ctx.controls["use_tool"]->set_activated_callback
+
+ // Setup switch POV control
+ ctx.controls["switch_pov"]->set_activated_callback
(
- [&ctx]()
+ [this]()
{
- if (ctx.entities.count("active_tool"))
- {
- entity::id tool_eid = ctx.entities["active_tool"];
- const auto& tool = ctx.entity_registry->get(tool_eid);
- if (tool.activated)
- tool.activated();
- }
+ // Disable keeper controls
+ this->disable_keeper_controls();
+
+ // Switch to ant
+ this->is_keeper = false;
+
+ // Enable ant controls
+ this->enable_ant_controls();
}
);
- ctx.controls["use_tool"]->set_deactivated_callback
+
+ // Fast-forward
+ ctx.controls["fast_forward"]->set_activated_callback
(
- [&ctx]()
+ [&ctx = this->ctx, time_scale]()
{
- if (ctx.entities.count("active_tool"))
- {
- entity::id tool_eid = ctx.entities["active_tool"];
- const auto& tool = ctx.entity_registry->get(tool_eid);
- if (tool.deactivated)
- tool.deactivated();
- }
+ game::world::set_time_scale(ctx, time_scale);
+ }
+ );
+ ctx.controls["fast_forward"]->set_deactivated_callback
+ (
+ [&ctx = this->ctx, time_scale]()
+ {
+ game::world::set_time_scale(ctx, 0.0);
}
);
- ctx.controls["use_tool"]->set_active_callback
+ ctx.controls["rewind"]->set_activated_callback
(
- [&ctx](float value)
+ [&ctx = this->ctx, time_scale]()
{
- if (ctx.entities.count("active_tool"))
+ game::world::set_time_scale(ctx, -time_scale);
+ }
+ );
+ ctx.controls["rewind"]->set_deactivated_callback
+ (
+ [&ctx = this->ctx, time_scale]()
+ {
+ game::world::set_time_scale(ctx, 0.0);
+ }
+ );
+
+ // Setup pause control
+ ctx.controls["pause"]->set_activated_callback
+ (
+ [this, &ctx = this->ctx]()
+ {
+ // Disable controls
+ this->disable_controls();
+
+ // Set resume callback
+ ctx.resume_callback = [this, &ctx]()
{
- entity::id tool_eid = ctx.entities["active_tool"];
- const auto& tool = ctx.entity_registry->get(tool_eid);
- if (tool.active)
- tool.active();
- }
+ this->enable_controls();
+ ctx.resume_callback = nullptr;
+ };
+
+ // Push pause menu state
+ ctx.state_machine.emplace(new game::state::pause_menu(ctx));
+ }
+ );
+}
+
+void nuptial_flight::disable_keeper_controls()
+{
+ ctx.controls["move_forward"]->set_active_callback(nullptr);
+ ctx.controls["move_back"]->set_active_callback(nullptr);
+ ctx.controls["move_right"]->set_active_callback(nullptr);
+ ctx.controls["move_left"]->set_active_callback(nullptr);
+ ctx.controls["move_up"]->set_active_callback(nullptr);
+ ctx.controls["move_down"]->set_active_callback(nullptr);
+ ctx.controls["mouse_look"]->set_activated_callback(nullptr);
+ ctx.controls["mouse_look"]->set_deactivated_callback(nullptr);
+ ctx.controls["look_left_gamepad"]->set_active_callback(nullptr);
+ ctx.controls["look_left_mouse"]->set_active_callback(nullptr);
+ ctx.controls["look_right_gamepad"]->set_active_callback(nullptr);
+ ctx.controls["look_right_mouse"]->set_active_callback(nullptr);
+ ctx.controls["look_up_gamepad"]->set_active_callback(nullptr);
+ ctx.controls["look_up_mouse"]->set_active_callback(nullptr);
+ ctx.controls["look_down_gamepad"]->set_active_callback(nullptr);
+ ctx.controls["look_down_mouse"]->set_active_callback(nullptr);
+ ctx.controls["switch_pov"]->set_activated_callback(nullptr);
+ ctx.controls["fast_forward"]->set_activated_callback(nullptr);
+ ctx.controls["rewind"]->set_activated_callback(nullptr);
+ ctx.controls["pause"]->set_activated_callback(nullptr);
+}
+
+void nuptial_flight::enable_ant_controls()
+{
+ // Get ant controller entities
+ entity::id ant_eid = ctx.entities["ant"];
+
+ const float move_forward_speed = 5.0f;
+ const float move_back_speed = move_forward_speed * 0.5f;
+ const float strafe_speed = move_forward_speed * 0.5f;
+ const float turn_speed = math::radians(270.0f);
+ const float slow_modifier = 0.5f;
+ const float fast_modifier = 2.0f;
+ float mouse_tilt_sensitivity = 1.0f;
+ float mouse_pan_sensitivity = 1.0f;
+ bool mouse_invert_tilt = false;
+ bool mouse_invert_pan = false;
+ float gamepad_tilt_sensitivity = 1.0f;
+ float gamepad_pan_sensitivity = 1.0f;
+ bool gamepad_invert_tilt = false;
+ bool gamepad_invert_pan = false;
+ const double time_scale = 5000.0;
+
+ if (ctx.config->contains("mouse_tilt_sensitivity"))
+ mouse_tilt_sensitivity = math::radians((*ctx.config)["mouse_tilt_sensitivity"].get());
+ if (ctx.config->contains("mouse_pan_sensitivity"))
+ mouse_pan_sensitivity = math::radians((*ctx.config)["mouse_pan_sensitivity"].get());
+ if (ctx.config->contains("mouse_invert_tilt"))
+ mouse_invert_tilt = math::radians((*ctx.config)["mouse_invert_tilt"].get());
+ if (ctx.config->contains("mouse_invert_pan"))
+ mouse_invert_pan = math::radians((*ctx.config)["mouse_invert_pan"].get());
+
+ if (ctx.config->contains("gamepad_tilt_sensitivity"))
+ gamepad_tilt_sensitivity = math::radians((*ctx.config)["gamepad_tilt_sensitivity"].get());
+ if (ctx.config->contains("gamepad_pan_sensitivity"))
+ gamepad_pan_sensitivity = math::radians((*ctx.config)["gamepad_pan_sensitivity"].get());
+ if (ctx.config->contains("gamepad_invert_tilt"))
+ gamepad_invert_tilt = math::radians((*ctx.config)["gamepad_invert_tilt"].get());
+ if (ctx.config->contains("gamepad_invert_pan"))
+ gamepad_invert_pan = math::radians((*ctx.config)["gamepad_invert_pan"].get());
+
+ const input::control* move_slow = ctx.controls["move_slow"];
+ const input::control* move_fast = ctx.controls["move_fast"];
+ const input::control* mouse_look = ctx.controls["mouse_look"];
+
+ float mouse_tilt_factor = mouse_tilt_sensitivity * (mouse_invert_tilt ? -1.0f : 1.0f);
+ float mouse_pan_factor = mouse_pan_sensitivity * (mouse_invert_pan ? -1.0f : 1.0f);
+ float gamepad_tilt_factor = gamepad_tilt_sensitivity * (gamepad_invert_tilt ? -1.0f : 1.0f);
+ float gamepad_pan_factor = gamepad_pan_sensitivity * (gamepad_invert_pan ? -1.0f : 1.0f);
+
+ // Move forward
+ ctx.controls["move_forward"]->set_active_callback
+ (
+ [&ctx = this->ctx, ant_eid, move_forward_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value)
+ {
+ if (move_slow->is_active())
+ value *= slow_modifier;
+ if (move_fast->is_active())
+ value *= fast_modifier;
+
+ auto& locomotion = ctx.entity_registry->get(ant_eid);
+ const math::quaternion yaw = math::angle_axis(locomotion.yaw, {0.0f, 1.0f, 0.0f});
+
+ const float3 movement = {0.0f, 0.0f, move_forward_speed * value * (1.0f / 60.0f)};
+ entity::command::translate(*ctx.entity_registry, ant_eid, yaw * movement);
+ }
+ );
+
+ // Move back
+ ctx.controls["move_back"]->set_active_callback
+ (
+ [&ctx = this->ctx, ant_eid, move_back_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value)
+ {
+ if (move_slow->is_active())
+ value *= slow_modifier;
+ if (move_fast->is_active())
+ value *= fast_modifier;
+
+ auto& locomotion = ctx.entity_registry->get(ant_eid);
+ const math::quaternion yaw = math::angle_axis(locomotion.yaw, {0.0f, 1.0f, 0.0f});
+
+ const float3 movement = {0.0f, 0.0f, -move_back_speed * value * (1.0f / 60.0f)};
+ entity::command::translate(*ctx.entity_registry, ant_eid, yaw * movement);
+ }
+ );
+
+ // Turn right
+ ctx.controls["move_right"]->set_active_callback
+ (
+ [&ctx = this->ctx, ant_eid, turn_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value)
+ {
+ if (move_slow->is_active())
+ value *= slow_modifier;
+ if (move_fast->is_active())
+ value *= fast_modifier;
+
+ auto& locomotion = ctx.entity_registry->get(ant_eid);
+ float delta_yaw = -turn_speed * value * (1.0f / 60.0f);
+ locomotion.yaw += delta_yaw;
+
+ entity::command::rotate(*ctx.entity_registry, ant_eid, delta_yaw, {0.0f, 1.0f, 0.0f});
+ }
+ );
+
+ // Truck left
+ ctx.controls["move_left"]->set_active_callback
+ (
+ [&ctx = this->ctx, ant_eid, turn_speed, move_slow, move_fast, slow_modifier, fast_modifier](float value)
+ {
+ if (move_slow->is_active())
+ value *= slow_modifier;
+ if (move_fast->is_active())
+ value *= fast_modifier;
+
+ auto& locomotion = ctx.entity_registry->get(ant_eid);
+ float delta_yaw = turn_speed * value * (1.0f / 60.0f);
+ locomotion.yaw += delta_yaw;
+
+ entity::command::rotate(*ctx.entity_registry, ant_eid, delta_yaw, {0.0f, 1.0f, 0.0f});
+ }
+ );
+
+ // Pan left
+ /*
+ ctx.controls["look_left_gamepad"]->set_active_callback
+ (
+ [&ctx = this->ctx, three_dof_eid, gamepad_pan_factor](float value)
+ {
+ auto& three_dof = ctx.entity_registry->get(three_dof_eid);
+ three_dof.yaw += gamepad_pan_factor * value * (1.0f / 60.0f);
+ }
+ );
+ ctx.controls["look_left_mouse"]->set_active_callback
+ (
+ [&ctx = this->ctx, three_dof_eid, mouse_pan_factor](float value)
+ {
+ if (!ctx.mouse_look)
+ return;
+
+ auto& three_dof = ctx.entity_registry->get(three_dof_eid);
+ three_dof.yaw += mouse_pan_factor * value * (1.0f / 60.0f);
+ }
+ );
+
+ // Pan right
+ ctx.controls["look_right_gamepad"]->set_active_callback
+ (
+ [&ctx = this->ctx, three_dof_eid, gamepad_pan_factor](float value)
+ {
+ auto& three_dof = ctx.entity_registry->get(three_dof_eid);
+ three_dof.yaw -= gamepad_pan_factor * value * (1.0f / 60.0f);
+ }
+ );
+ ctx.controls["look_right_mouse"]->set_active_callback
+ (
+ [&ctx = this->ctx, three_dof_eid, mouse_pan_factor](float value)
+ {
+ if (!ctx.mouse_look)
+ return;
+
+ auto& three_dof = ctx.entity_registry->get(three_dof_eid);
+ three_dof.yaw -= mouse_pan_factor * value * (1.0f / 60.0f);
+ }
+ );
+ // Tilt up
+ ctx.controls["look_up_gamepad"]->set_active_callback
+ (
+ [&ctx = this->ctx, three_dof_eid, gamepad_tilt_factor](float value)
+ {
+ auto& three_dof = ctx.entity_registry->get(three_dof_eid);
+ three_dof.pitch -= gamepad_tilt_factor * value * (1.0f / 60.0f);
+ three_dof.pitch = std::max(math::radians(-90.0f), three_dof.pitch);
+ }
+ );
+ ctx.controls["look_up_mouse"]->set_active_callback
+ (
+ [&ctx = this->ctx, three_dof_eid, mouse_tilt_factor](float value)
+ {
+ if (!ctx.mouse_look)
+ return;
+
+ auto& three_dof = ctx.entity_registry->get(three_dof_eid);
+ three_dof.pitch -= mouse_tilt_factor * value * (1.0f / 60.0f);
+ three_dof.pitch = std::max(math::radians(-90.0f), three_dof.pitch);
+ }
+ );
+ // Tilt down
+ ctx.controls["look_down_gamepad"]->set_active_callback
+ (
+ [&ctx = this->ctx, three_dof_eid, gamepad_tilt_factor](float value)
+ {
+ auto& three_dof = ctx.entity_registry->get(three_dof_eid);
+ three_dof.pitch += gamepad_tilt_factor * value * (1.0f / 60.0f);
+ three_dof.pitch = std::min(math::radians(90.0f), three_dof.pitch);
+ }
+ );
+ ctx.controls["look_down_mouse"]->set_active_callback
+ (
+ [&ctx = this->ctx, three_dof_eid, mouse_tilt_factor](float value)
+ {
+ if (!ctx.mouse_look)
+ return;
+
+ auto& three_dof = ctx.entity_registry->get(three_dof_eid);
+ three_dof.pitch += mouse_tilt_factor * value * (1.0f / 60.0f);
+ three_dof.pitch = std::min(math::radians(90.0f), three_dof.pitch);
}
);
*/
+ // Setup switch POV control
+ ctx.controls["switch_pov"]->set_activated_callback
+ (
+ [this]()
+ {
+ // Disable ant controls
+ this->disable_ant_controls();
+
+ // Switch to keeper
+ this->is_keeper = true;
+
+ // Enable keeper controls
+ this->enable_keeper_controls();
+ }
+ );
+
// Fast-forward
ctx.controls["fast_forward"]->set_activated_callback
(
@@ -610,16 +912,12 @@ void nuptial_flight::enable_controls()
);
}
-void nuptial_flight::disable_controls()
+void nuptial_flight::disable_ant_controls()
{
ctx.controls["move_forward"]->set_active_callback(nullptr);
ctx.controls["move_back"]->set_active_callback(nullptr);
ctx.controls["move_right"]->set_active_callback(nullptr);
ctx.controls["move_left"]->set_active_callback(nullptr);
- ctx.controls["move_up"]->set_active_callback(nullptr);
- ctx.controls["move_down"]->set_active_callback(nullptr);
- ctx.controls["mouse_look"]->set_activated_callback(nullptr);
- ctx.controls["mouse_look"]->set_deactivated_callback(nullptr);
ctx.controls["look_left_gamepad"]->set_active_callback(nullptr);
ctx.controls["look_left_mouse"]->set_active_callback(nullptr);
ctx.controls["look_right_gamepad"]->set_active_callback(nullptr);
@@ -628,8 +926,27 @@ void nuptial_flight::disable_controls()
ctx.controls["look_up_mouse"]->set_active_callback(nullptr);
ctx.controls["look_down_gamepad"]->set_active_callback(nullptr);
ctx.controls["look_down_mouse"]->set_active_callback(nullptr);
+ ctx.controls["switch_pov"]->set_activated_callback(nullptr);
+ ctx.controls["fast_forward"]->set_activated_callback(nullptr);
+ ctx.controls["rewind"]->set_activated_callback(nullptr);
ctx.controls["pause"]->set_activated_callback(nullptr);
}
+void nuptial_flight::enable_controls()
+{
+ if (is_keeper)
+ enable_keeper_controls();
+ else
+ enable_ant_controls();
+}
+
+void nuptial_flight::disable_controls()
+{
+ if (is_keeper)
+ disable_keeper_controls();
+ else
+ disable_ant_controls();
+}
+
} // namespace state
} // namespace game
diff --git a/src/game/state/nuptial-flight.hpp b/src/game/state/nuptial-flight.hpp
index 60b412e..51f22cd 100644
--- a/src/game/state/nuptial-flight.hpp
+++ b/src/game/state/nuptial-flight.hpp
@@ -33,6 +33,12 @@ public:
private:
void setup_camera();
+
+ bool is_keeper;
+ void enable_keeper_controls();
+ void disable_keeper_controls();
+ void enable_ant_controls();
+ void disable_ant_controls();
void enable_controls();
void disable_controls();
};
diff --git a/src/game/state/options-menu.cpp b/src/game/state/options-menu.cpp
index e02e36f..019e810 100644
--- a/src/game/state/options-menu.cpp
+++ b/src/game/state/options-menu.cpp
@@ -171,7 +171,7 @@ options_menu::options_menu(game::context& ctx):
game::menu::clear_controls(ctx);
// Save config
- game::save_config(ctx);
+ game::save::config(ctx);
game::menu::fade_out
(
diff --git a/src/game/state/pause-menu.cpp b/src/game/state/pause-menu.cpp
index ca49af0..4723830 100644
--- a/src/game/state/pause-menu.cpp
+++ b/src/game/state/pause-menu.cpp
@@ -30,6 +30,7 @@
#include "debug/logger.hpp"
#include "animation/screen-transition.hpp"
#include "config.hpp"
+#include "game/save.hpp"
namespace game {
namespace state {
@@ -202,6 +203,9 @@ pause_menu::pause_menu(game::context& ctx):
if (!ctx.menu_bg_billboard->is_active())
game::menu::fade_in_bg(ctx);
+ // Save colony
+ game::save::colony(ctx);
+
ctx.logger->pop_task(EXIT_SUCCESS);
}
diff --git a/src/game/world.cpp b/src/game/world.cpp
index 8eab747..a3ed583 100644
--- a/src/game/world.cpp
+++ b/src/game/world.cpp
@@ -194,7 +194,7 @@ void create_sun(game::context& ctx)
// Create ambient sun light scene object
scene::ambient_light* sun_ambient = new scene::ambient_light();
sun_ambient->set_color({1, 1, 1});
- sun_ambient->set_intensity(0.0f);
+ sun_ambient->set_intensity(30000.0f);
sun_ambient->update_tweens();
// Add sun light scene objects to surface scene
diff --git a/src/render/passes/ground-pass.cpp b/src/render/passes/ground-pass.cpp
index eec7199..8b41326 100644
--- a/src/render/passes/ground-pass.cpp
+++ b/src/render/passes/ground-pass.cpp
@@ -68,8 +68,8 @@ void ground_pass::render(const render::context& ctx, render::queue& queue) const
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_ALWAYS);
glDepthMask(GL_TRUE);
- glDepthFunc(GL_GREATER);
glDepthRange(-1.0f, 1.0f);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
diff --git a/src/resources/entity-archetype-loader.cpp b/src/resources/entity-archetype-loader.cpp
index 55bd08f..97ff38b 100644
--- a/src/resources/entity-archetype-loader.cpp
+++ b/src/resources/entity-archetype-loader.cpp
@@ -134,7 +134,8 @@ static bool load_component_model(entity::archetype& archetype, resource_manager&
{
entity::component::model component;
component.instance_count = 0;
- component.layers = ~0;
+ //component.layers = ~0;
+ component.layers = 1;
if (element.contains("file"))
{
diff --git a/src/resources/json-loader.cpp b/src/resources/json-loader.cpp
index 517586f..ec2767d 100644
--- a/src/resources/json-loader.cpp
+++ b/src/resources/json-loader.cpp
@@ -17,9 +17,9 @@
* along with Antkeeper source code. If not, see .
*/
-#include "resource-loader.hpp"
-#include "resource-manager.hpp"
-#include "json.hpp"
+#include "resources/resource-loader.hpp"
+#include "resources/resource-manager.hpp"
+#include "resources/json.hpp"
#include
template <>