LCOV - code coverage report
Current view: top level - core/state - StateManager.cpp (source / functions) Coverage Total Hit
Test: coverage-src.info Lines: 0.0 % 451 0
Test Date: 2025-05-27 23:26:07 Functions: 0.0 % 38 0

            Line data    Source code
       1              : #include "core/state/StateManager.hpp"
       2              : 
       3              : #include "core/entities/Weapon.hpp"
       4              : #include "core/math/Calc.hpp"
       5              : #include "core/physics/Particles.hpp"
       6              : #include "core/physics/SoldierSkeletonPhysics.hpp"
       7              : #include "core/state/Control.hpp"
       8              : #include "core/entities/WeaponParametersFactory.hpp"
       9              : 
      10              : #include "core/types/ItemType.hpp"
      11              : #include "spdlog/spdlog.h"
      12              : #include <algorithm>
      13              : #include <utility>
      14              : 
      15              : namespace Soldank
      16              : {
      17              : // TODO: Move these somewhere
      18              : const int SECOND = 60;
      19              : const int GUN_RADIUS = 10;
      20              : const int BOW_RADIUS = 20;
      21              : const int KIT_RADIUS = 12;
      22              : const int STAT_RADIUS = 15;
      23              : const int FLAG_RADIUS = 19;
      24              : const int FLAG_TIMEOUT = SECOND * 25;
      25              : const int GUN_TIMEOUT = SECOND * 20;
      26              : // TODO: why the duplication?
      27              : const int WAYPOINT_TIMEOUT_SMALL = SECOND * 5 + 20; // = 320
      28              : const int WAYPOINT_TIMEOUT_BIG = SECOND * 8;        // = 480
      29              : const float FLAGTHROW_POWER = 4.225;
      30              : const int SOLDIER_START_HEALTH = 150;
      31              : const int SOLDIER_DEFAULT_VEST = 100;
      32              : 
      33            0 : WeaponType ItemTypeToWeaponType(ItemType item_type)
      34              : {
      35            0 :     switch (item_type) {
      36            0 :         case ItemType::USSOCOM:
      37            0 :             return WeaponType::USSOCOM;
      38            0 :         case ItemType::DesertEagles:
      39            0 :             return WeaponType::DesertEagles;
      40            0 :         case ItemType::MP5:
      41            0 :             return WeaponType::MP5;
      42            0 :         case ItemType::Ak74:
      43            0 :             return WeaponType::Ak74;
      44            0 :         case ItemType::SteyrAUG:
      45            0 :             return WeaponType::SteyrAUG;
      46            0 :         case ItemType::Spas12:
      47            0 :             return WeaponType::Spas12;
      48            0 :         case ItemType::Ruger77:
      49            0 :             return WeaponType::Ruger77;
      50            0 :         case ItemType::M79:
      51            0 :             return WeaponType::M79;
      52            0 :         case ItemType::Barrett:
      53            0 :             return WeaponType::Barrett;
      54            0 :         case ItemType::Minimi:
      55            0 :             return WeaponType::Minimi;
      56            0 :         case ItemType::Minigun:
      57            0 :             return WeaponType::Minigun;
      58            0 :         case ItemType::Bow:
      59            0 :             return WeaponType::Bow;
      60            0 :         case ItemType::Knife:
      61            0 :             return WeaponType::Knife;
      62            0 :         case ItemType::Chainsaw:
      63            0 :             return WeaponType::Chainsaw;
      64            0 :         case ItemType::LAW:
      65            0 :             return WeaponType::LAW;
      66            0 :         case ItemType::AlphaFlag:
      67              :         case ItemType::BravoFlag:
      68              :         case ItemType::PointmatchFlag:
      69              :         case ItemType::MedicalKit:
      70              :         case ItemType::GrenadeKit:
      71              :         case ItemType::FlamerKit:
      72              :         case ItemType::PredatorKit:
      73              :         case ItemType::VestKit:
      74              :         case ItemType::BerserkKit:
      75              :         case ItemType::ClusterKit:
      76              :         case ItemType::Parachute:
      77              :         case ItemType::M2:
      78            0 :             break;
      79              :     }
      80              : 
      81            0 :     spdlog::critical("Invalid ItemType to WeaponType conversion");
      82              :     std::unreachable();
      83              : }
      84              : 
      85            0 : StateManager::StateManager(AnimationDataManager& animation_data_manager,
      86            0 :                            std::shared_ptr<ParticleSystem> skeleton)
      87            0 :     : state_(animation_data_manager, std::move(skeleton))
      88              : {
      89            0 : }
      90              : 
      91            0 : void StateManager::ChangeSoldierControlActionState(std::uint8_t soldier_id,
      92              :                                                    ControlActionType control_action_type,
      93              :                                                    bool new_state)
      94              : {
      95            0 :     Soldier& soldier = GetSoldierRef(soldier_id);
      96            0 :     auto get_action_field = [](Control& soldier_control,
      97              :                                ControlActionType control_action_type) -> bool& {
      98            0 :         switch (control_action_type) {
      99            0 :             case ControlActionType::MoveLeft:
     100            0 :                 return soldier_control.left;
     101            0 :             case ControlActionType::MoveRight:
     102            0 :                 return soldier_control.right;
     103            0 :             case ControlActionType::Jump:
     104            0 :                 return soldier_control.up;
     105            0 :             case ControlActionType::Crouch:
     106            0 :                 return soldier_control.down;
     107            0 :             case ControlActionType::Fire:
     108            0 :                 return soldier_control.fire;
     109            0 :             case ControlActionType::UseJets:
     110            0 :                 return soldier_control.jets;
     111            0 :             case ControlActionType::ChangeWeapon:
     112            0 :                 return soldier_control.change;
     113            0 :             case ControlActionType::ThrowGrenade:
     114            0 :                 return soldier_control.throw_grenade;
     115            0 :             case ControlActionType::DropWeapon:
     116            0 :                 return soldier_control.drop;
     117            0 :             case ControlActionType::Reload:
     118            0 :                 return soldier_control.reload;
     119            0 :             case ControlActionType::Prone:
     120            0 :                 return soldier_control.prone;
     121            0 :             case ControlActionType::ThrowFlag:
     122            0 :                 return soldier_control.flag_throw;
     123              :         }
     124              :     };
     125            0 :     bool& target_field_to_change = get_action_field(soldier.control, control_action_type);
     126            0 :     target_field_to_change = new_state;
     127            0 : }
     128              : 
     129            0 : void StateManager::SoldierControlApply(
     130              :   std::uint8_t soldier_id,
     131              :   const std::function<void(const Soldier& soldier, Control& control)>& apply_function)
     132              : {
     133            0 :     Soldier& soldier = GetSoldierRef(soldier_id);
     134            0 :     apply_function(soldier, soldier.control);
     135            0 : }
     136              : 
     137            0 : void StateManager::ChangeSoldierMouseMapPosition(std::uint8_t soldier_id,
     138              :                                                  glm::ivec2 new_mouse_position)
     139              : {
     140            0 :     Soldier& soldier = GetSoldierRef(soldier_id);
     141            0 :     soldier.control.mouse_aim_x = new_mouse_position.x;
     142            0 :     soldier.control.mouse_aim_y = new_mouse_position.y;
     143            0 : }
     144              : 
     145            0 : void StateManager::SwitchSoldierWeapon(std::uint8_t soldier_id)
     146              : {
     147            0 :     Soldier& soldier = GetSoldierRef(soldier_id);
     148            0 :     int new_active_weapon = (soldier.active_weapon + 1) % 2;
     149            0 :     soldier.active_weapon = new_active_weapon;
     150              :     // weapons[new_active_weapon].start_up_time_count =
     151              :     //   weapons[new_active_weapon].GetWeaponParameters().start_up_time;
     152            0 :     soldier.weapons[new_active_weapon].ResetStartUpTimeCount();
     153              :     // weapons[new_active_weapon].reload_time_prev = weapons[new_active_weapon].reload_time_count;
     154            0 :     soldier.weapons[new_active_weapon].SetReloadTimePrev(
     155            0 :       soldier.weapons[new_active_weapon].GetReloadTimeCount());
     156            0 : }
     157              : 
     158            0 : void StateManager::ChangeSoldierPrimaryWeapon(std::uint8_t soldier_id, WeaponType new_weapon_type)
     159              : {
     160            0 :     Soldier& soldier = GetSoldierRef(soldier_id);
     161            0 :     auto new_weapon_parameters = WeaponParametersFactory::GetParameters(new_weapon_type, false);
     162            0 :     soldier.weapons[soldier.active_weapon] = new_weapon_parameters;
     163            0 : }
     164              : 
     165            0 : void StateManager::SoldierPickupWeapon(std::uint8_t soldier_id, const Item& item)
     166              : {
     167            0 :     Soldier& soldier = GetSoldierRef(soldier_id);
     168            0 :     WeaponType new_weapon_type = ItemTypeToWeaponType(item.style);
     169            0 :     auto new_weapon_parameters = WeaponParametersFactory::GetParameters(new_weapon_type, false);
     170            0 :     new_weapon_parameters.ammo = item.ammo_count;
     171            0 :     soldier.weapons[soldier.active_weapon] = new_weapon_parameters;
     172            0 : }
     173              : 
     174            0 : void StateManager::SoldierPickupKit(std::uint8_t soldier_id, std::uint8_t item_id)
     175              : {
     176            0 :     Soldier& soldier = GetSoldierRef(soldier_id);
     177            0 :     Item& item = GetItemRef(item_id);
     178              : 
     179            0 :     if (item.style == ItemType::MedicalKit) {
     180            0 :         if (soldier.health >= SOLDIER_START_HEALTH) {
     181            0 :             return;
     182              :         }
     183              : 
     184            0 :         soldier.health = SOLDIER_START_HEALTH;
     185            0 :         item.active = false;
     186              :     }
     187              : 
     188            0 :     if (item.style == ItemType::GrenadeKit) {
     189            0 :         if (soldier.weapons[2].GetWeaponParameters().kind == WeaponType::ClusterGrenade &&
     190            0 :             soldier.weapons[2].GetAmmoCount() > 0) {
     191              :             // Don't pickup normal grenades if Soldier has any Cluster grenades already
     192            0 :             return;
     193              :         }
     194              : 
     195            0 :         if (soldier.weapons[2].GetAmmoCount() >= soldier.weapons[2].GetWeaponParameters().ammo) {
     196              :             // Don't pickup if Soldier has all the grenades (or more)
     197            0 :             return;
     198              :         }
     199              : 
     200            0 :         soldier.weapons[2] = WeaponParametersFactory::GetParameters(WeaponType::FragGrenade, false);
     201            0 :         item.active = false;
     202              :     }
     203              : 
     204            0 :     if (item.style == ItemType::FlamerKit) {
     205              :         // TODO
     206              :     }
     207              : 
     208            0 :     if (item.style == ItemType::PredatorKit) {
     209              :         // TODO
     210              :     }
     211              : 
     212            0 :     if (item.style == ItemType::VestKit) {
     213            0 :         soldier.vest = SOLDIER_DEFAULT_VEST;
     214            0 :         item.active = false;
     215              :     }
     216              : 
     217            0 :     if (item.style == ItemType::BerserkKit) {
     218              :         // TODO
     219              :     }
     220              : 
     221            0 :     if (item.style == ItemType::ClusterKit) {
     222            0 :         if (soldier.weapons[2].GetWeaponParameters().kind == WeaponType::ClusterGrenade &&
     223            0 :             soldier.weapons[2].GetAmmoCount() > 0) {
     224              :             // Don't pickup more cluster grenades if Soldier has already some
     225            0 :             return;
     226              :         }
     227              : 
     228            0 :         soldier.weapons[2] =
     229            0 :           WeaponParametersFactory::GetParameters(WeaponType::ClusterGrenade, false);
     230            0 :         item.active = false;
     231              :     }
     232              : }
     233              : 
     234            0 : void StateManager::MoveSoldier(std::uint8_t soldier_id, const glm::vec2& move_offset)
     235              : {
     236            0 :     Soldier& soldier = GetSoldierRef(soldier_id);
     237            0 :     glm::vec2 new_soldier_position = soldier.particle.position + move_offset;
     238            0 :     soldier.particle.position = new_soldier_position;
     239            0 :     soldier.particle.old_position = new_soldier_position;
     240            0 :     RepositionSoldierSkeletonParts(soldier);
     241            0 : }
     242              : 
     243            0 : void StateManager::SetSoldierPosition(std::uint8_t soldier_id, const glm::vec2& new_position)
     244              : {
     245            0 :     Soldier& soldier = GetSoldierRef(soldier_id);
     246            0 :     soldier.particle.position = new_position;
     247            0 :     soldier.particle.old_position = new_position;
     248            0 :     RepositionSoldierSkeletonParts(soldier);
     249            0 : }
     250              : 
     251            0 : void StateManager::ThrowSoldierFlags(std::uint8_t soldier_id)
     252              : {
     253            0 :     Soldier& soldier = GetSoldierRef(soldier_id);
     254            0 :     for (auto item_it = state_.items.begin(); item_it != state_.items.end(); ++item_it) {
     255            0 :         if (IsItemTypeFlag(item_it->style)) {
     256            0 :             glm::vec2 aim_direction = GetSoldierAimDirection(soldier_id);
     257            0 :             aim_direction = Calc::Vec2Scale(aim_direction, FLAGTHROW_POWER);
     258              : 
     259            0 :             glm::vec2 flagger_offset = Calc::Vec2Scale(aim_direction, 5);
     260              : 
     261            0 :             glm::vec2 flagger_velocity = aim_direction + soldier.particle.GetVelocity();
     262              : 
     263            0 :             glm::vec2 new_pos_diff = flagger_offset + flagger_velocity;
     264            0 :             glm::vec2 look_point_1 = item_it->skeleton->GetPos(1) + new_pos_diff;
     265            0 :             glm::vec2 future_point_1 = look_point_1 + glm::vec2{ -10, -8 };
     266            0 :             glm::vec2 future_point_2 = look_point_1 + glm::vec2{ 10, -8 };
     267            0 :             glm::vec2 future_point_3 = look_point_1 + glm::vec2{ -10, 8 };
     268            0 :             glm::vec2 future_point_4 = look_point_1 + glm::vec2{ 10, 8 };
     269              : 
     270              :             glm::vec2 perp;
     271            0 :             float distance = 0.0F;
     272              : 
     273            0 :             glm::vec2 look_point_2 = item_it->skeleton->GetPos(2) + new_pos_diff;
     274            0 :             glm::vec2 look_point_3 = item_it->skeleton->GetPos(3) + new_pos_diff;
     275            0 :             glm::vec2 look_point_4 = item_it->skeleton->GetPos(4) + new_pos_diff;
     276              : 
     277            0 :             if (!state_.map.RayCast(
     278            0 :                   soldier.skeleton->GetPos(15), look_point_2, distance, 200, false, true, false) &&
     279            0 :                 !state_.map.RayCast(
     280            0 :                   soldier.skeleton->GetPos(15), look_point_3, distance, 200, false, true, false) &&
     281            0 :                 !state_.map.RayCast(
     282            0 :                   soldier.skeleton->GetPos(15), look_point_4, distance, 200, false, true, false) &&
     283            0 :                 !state_.map.CollisionTest(future_point_1, perp, true) &&
     284            0 :                 !state_.map.CollisionTest(future_point_2, perp, true) &&
     285            0 :                 !state_.map.CollisionTest(future_point_3, perp, true) &&
     286            0 :                 !state_.map.CollisionTest(future_point_4, perp, true)) {
     287              : 
     288            0 :                 for (unsigned int j = 1; j <= 4; ++j) {
     289              :                     // Apply offset from flagger
     290            0 :                     item_it->skeleton->SetPos(j, item_it->skeleton->GetPos(j) + flagger_offset);
     291              : 
     292              :                     // Apply velocities
     293            0 :                     item_it->skeleton->SetPos(j, item_it->skeleton->GetPos(j) + flagger_velocity);
     294            0 :                     item_it->skeleton->SetOldPos(j,
     295            0 :                                                  item_it->skeleton->GetPos(j) - flagger_velocity);
     296              :                 }
     297              : 
     298              :                 // Add some spin for visual effect
     299            0 :                 perp = { -flagger_velocity.y, flagger_velocity.x };
     300            0 :                 perp = Calc::Vec2Normalize(perp);
     301            0 :                 perp = Calc::Vec2Scale(perp, soldier.direction);
     302            0 :                 item_it->skeleton->SetPos(1, item_it->skeleton->GetPos(1) - perp);
     303            0 :                 item_it->skeleton->SetPos(2, item_it->skeleton->GetPos(2) + perp);
     304              : 
     305              :                 // Release the flag
     306            0 :                 item_it->static_type = false;
     307            0 :                 item_it->holding_soldier_id = 0;
     308            0 :                 soldier.is_holding_flags = false;
     309              :             }
     310              :         }
     311              :     }
     312            0 : }
     313              : 
     314            0 : glm::vec2 StateManager::GetSoldierAimDirection(std::uint8_t soldier_id)
     315              : {
     316            0 :     Soldier& soldier = GetSoldierRef(soldier_id);
     317            0 :     glm::vec2 mouse_aim = { soldier.control.mouse_aim_x, soldier.control.mouse_aim_y };
     318              : 
     319            0 :     glm::vec2 aim_direction = mouse_aim - soldier.skeleton->GetPos(15);
     320            0 :     aim_direction = Calc::Vec2Normalize(aim_direction);
     321              : 
     322            0 :     return aim_direction;
     323              : }
     324              : 
     325            0 : void StateManager::TransformSoldier(std::uint8_t soldier_id,
     326              :                                     const std::function<void(Soldier&)>& transform_soldier_function)
     327              : {
     328            0 :     Soldier& soldier = GetSoldierRef(soldier_id);
     329            0 :     if (!soldier.active) {
     330            0 :         spdlog::warn("Trying to transform inactive soldier of id: {}", soldier_id);
     331            0 :         return;
     332              :     }
     333            0 :     transform_soldier_function(soldier);
     334              : }
     335              : 
     336            0 : void StateManager::TransformSoldiers(
     337              :   const std::function<void(Soldier&)>& transform_soldier_function)
     338              : {
     339            0 :     for (auto& soldier : state_.soldiers) {
     340            0 :         if (!soldier.active) {
     341            0 :             continue;
     342              :         }
     343              : 
     344            0 :         transform_soldier_function(soldier);
     345              :     }
     346            0 : }
     347              : 
     348            0 : const Soldier& StateManager::GetSoldier(std::uint8_t soldier_id) const
     349              : {
     350            0 :     if (soldier_id >= state_.soldiers.size()) {
     351            0 :         spdlog::critical("Trying to access soldier of invalid id: {}", soldier_id);
     352              :         std::unreachable();
     353              :     }
     354              : 
     355            0 :     return state_.soldiers.at(soldier_id);
     356              : }
     357              : 
     358            0 : const Soldier& StateManager::CreateSoldier(std::optional<unsigned int> force_soldier_id)
     359              : {
     360            0 :     unsigned int new_soldier_id = NAN;
     361              : 
     362            0 :     if (!force_soldier_id.has_value()) {
     363            0 :         unsigned int free_soldier_id = 0;
     364            0 :         for (const auto& soldier : state_.soldiers) {
     365            0 :             if (!soldier.active) {
     366            0 :                 break;
     367              :             }
     368              : 
     369            0 :             ++free_soldier_id;
     370              :         }
     371              : 
     372            0 :         new_soldier_id = free_soldier_id;
     373              :     } else {
     374            0 :         new_soldier_id = *force_soldier_id;
     375              :     }
     376              : 
     377              :     std::vector<Weapon> weapons{
     378            0 :         { WeaponParametersFactory::GetParameters(WeaponType::DesertEagles, false) },
     379            0 :         { WeaponParametersFactory::GetParameters(WeaponType::Knife, false) },
     380            0 :         { WeaponParametersFactory::GetParameters(WeaponType::FragGrenade, false) }
     381            0 :     };
     382              : 
     383            0 :     spdlog::debug("new_soldier_id {}", new_soldier_id);
     384            0 :     state_.soldiers.at(new_soldier_id).SetDefaultValues();
     385            0 :     state_.soldiers.at(new_soldier_id).active = true;
     386            0 :     state_.soldiers.at(new_soldier_id).id = new_soldier_id;
     387              : 
     388            0 :     return state_.soldiers.back();
     389            0 : }
     390              : 
     391            0 : glm::vec2 StateManager::SpawnSoldier(unsigned int soldier_id,
     392              :                                      std::optional<glm::vec2> spawn_position)
     393              : {
     394            0 :     glm::vec2 initial_player_position{ 0.0F, 0.0F };
     395            0 :     if (spawn_position.has_value()) {
     396            0 :         initial_player_position = *spawn_position;
     397              :     } else {
     398            0 :         std::vector<glm::vec2> possible_spawn_point_positions;
     399            0 :         for (const auto& spawn_point : state_.map.GetSpawnPoints()) {
     400            0 :             if (spawn_point.type == PMSSpawnPointType::General ||
     401            0 :                 spawn_point.type == PMSSpawnPointType::Alpha ||
     402            0 :                 spawn_point.type == PMSSpawnPointType::Bravo ||
     403            0 :                 spawn_point.type == PMSSpawnPointType::Charlie ||
     404            0 :                 spawn_point.type == PMSSpawnPointType::Delta) {
     405              : 
     406            0 :                 possible_spawn_point_positions.emplace_back(spawn_point.x, spawn_point.y);
     407              :             }
     408              :         }
     409              : 
     410            0 :         if (possible_spawn_point_positions.empty()) {
     411            0 :             for (const auto& spawn_point : state_.map.GetSpawnPoints()) {
     412            0 :                 possible_spawn_point_positions.emplace_back(spawn_point.x, spawn_point.y);
     413              :             }
     414              :         }
     415              : 
     416            0 :         if (!possible_spawn_point_positions.empty()) {
     417              :             std::uniform_int_distribution<unsigned int> spawnpoint_id_random_distribution(
     418            0 :               0, possible_spawn_point_positions.size() - 1);
     419              : 
     420              :             unsigned int random_spawnpoint_id =
     421            0 :               spawnpoint_id_random_distribution(mersenne_twister_engine_);
     422              : 
     423            0 :             initial_player_position = possible_spawn_point_positions.at(random_spawnpoint_id);
     424              :         }
     425            0 :     }
     426              : 
     427            0 :     auto& soldier = GetSoldierRef(soldier_id);
     428            0 :     soldier.particle.position = initial_player_position;
     429            0 :     soldier.particle.old_position = initial_player_position;
     430            0 :     soldier.active = true;
     431            0 :     soldier.particle.active = true;
     432            0 :     soldier.health = 150.0;
     433            0 :     soldier.dead_meat = false;
     434            0 :     soldier.weapons[0] = WeaponParametersFactory::GetParameters(soldier.weapon_choices[0], false);
     435            0 :     soldier.weapons[1] = WeaponParametersFactory::GetParameters(soldier.weapon_choices[1], false);
     436            0 :     soldier.active_weapon = 0;
     437            0 :     RepositionSoldierSkeletonParts(soldier);
     438              : 
     439            0 :     return initial_player_position;
     440              : }
     441              : 
     442            0 : void StateManager::ForEachSoldier(
     443              :   const std::function<void(const Soldier& soldier)>& for_each_soldier_function) const
     444              : {
     445            0 :     for (const Soldier& soldier : state_.soldiers) {
     446            0 :         if (!soldier.active) {
     447            0 :             continue;
     448              :         }
     449              : 
     450            0 :         for_each_soldier_function(soldier);
     451              :     }
     452            0 : }
     453              : 
     454            0 : void StateManager::ForSoldier(
     455              :   std::uint8_t soldier_id,
     456              :   const std::function<void(const Soldier& soldier)>& for_soldier_function) const
     457              : {
     458            0 :     if (soldier_id >= state_.soldiers.size()) {
     459            0 :         spdlog::critical("Trying to access soldier of invalid id: {}", soldier_id);
     460              :         std::unreachable();
     461              :     }
     462              : 
     463            0 :     for_soldier_function(state_.soldiers.at(soldier_id));
     464            0 : }
     465              : 
     466            0 : const Soldier* StateManager::FindSoldier(
     467              :   const std::function<bool(const Soldier& soldier)>& predicate) const
     468              : {
     469            0 :     for (const Soldier& soldier : state_.soldiers) {
     470            0 :         if (!soldier.active) {
     471            0 :             continue;
     472              :         }
     473              : 
     474            0 :         if (predicate(soldier)) {
     475            0 :             return &soldier;
     476              :         }
     477              :     }
     478              : 
     479            0 :     return nullptr;
     480              : }
     481              : 
     482            0 : void StateManager::RemoveSoldier(std::uint8_t soldier_id)
     483              : {
     484            0 :     if (soldier_id >= state_.soldiers.size()) {
     485            0 :         spdlog::critical("Trying to access soldier of invalid id: {}", soldier_id);
     486              :         std::unreachable();
     487              :     }
     488              : 
     489            0 :     state_.soldiers.at(soldier_id).active = false;
     490            0 : }
     491              : 
     492            0 : std::size_t StateManager::GetSoldiersCount() const
     493              : {
     494            0 :     return state_.soldiers.size();
     495              : }
     496              : 
     497            0 : void StateManager::EnqueueNewProjectile(const BulletParams& bullet_params)
     498              : {
     499            0 :     bullet_emitter_.push_back(bullet_params);
     500            0 : }
     501              : 
     502            0 : void StateManager::CreateProjectile(const BulletParams& bullet_params)
     503              : {
     504            0 :     bool is_bullet_created = false;
     505            0 :     for (auto& bullet : state_.bullets) {
     506            0 :         if (bullet.active) {
     507            0 :             continue;
     508              :         }
     509              : 
     510            0 :         bullet = bullet_params;
     511            0 :         bullet.active = true;
     512            0 :         is_bullet_created = true;
     513              : 
     514            0 :         break;
     515              :     }
     516              : 
     517            0 :     if (!is_bullet_created) {
     518            0 :         spdlog::warn("Could not create a new projectile because the limit is exceeded");
     519              :     }
     520            0 : }
     521              : 
     522            0 : const std::vector<BulletParams>& StateManager::GetBulletEmitter() const
     523              : {
     524            0 :     return bullet_emitter_;
     525              : }
     526              : 
     527            0 : void StateManager::ClearBulletEmitter()
     528              : {
     529            0 :     bullet_emitter_.clear();
     530            0 : }
     531              : 
     532            0 : void StateManager::ForEachBullet(
     533              :   const std::function<void(const Bullet& bullet)>& for_each_bullet_function) const
     534              : {
     535            0 :     for (const auto& bullet : state_.bullets) {
     536            0 :         if (!bullet.active) {
     537            0 :             continue;
     538              :         }
     539              : 
     540            0 :         for_each_bullet_function(bullet);
     541              :     }
     542            0 : }
     543              : 
     544            0 : std::size_t StateManager::GetBulletsCount() const
     545              : {
     546            0 :     std::size_t bullets_count = 0;
     547              : 
     548            0 :     for (const auto& bullet : state_.bullets) {
     549            0 :         if (!bullet.active) {
     550            0 :             continue;
     551              :         }
     552              : 
     553            0 :         ++bullets_count;
     554              :     }
     555              : 
     556            0 :     return bullets_count;
     557              : }
     558              : 
     559            0 : void StateManager::TransformBullets(
     560              :   const std::function<void(Bullet& bullet)>& transform_bullet_function)
     561              : {
     562            0 :     for (auto& bullet : state_.bullets) {
     563            0 :         if (!bullet.active) {
     564            0 :             continue;
     565              :         }
     566              : 
     567            0 :         transform_bullet_function(bullet);
     568              :     }
     569            0 : }
     570              : 
     571            0 : Item& StateManager::CreateItem(glm::vec2 position, std::uint8_t owner_id, ItemType style)
     572              : {
     573            0 :     std::uint8_t new_id = 0;
     574            0 :     for (const auto& item : state_.items) {
     575            0 :         if (!item.active) {
     576            0 :             break;
     577              :         }
     578              : 
     579            0 :         ++new_id;
     580              :     }
     581              : 
     582            0 :     Item new_item;
     583            0 :     new_item.active = true;
     584            0 :     new_item.style = style;
     585            0 :     new_item.id = new_id;
     586            0 :     new_item.holding_soldier_id = 0;
     587            0 :     new_item.owner = owner_id;
     588            0 :     new_item.time_out = 0;
     589              :     // new_item.skeleton = std::make_shared<ParticleSystem>();
     590            0 :     new_item.static_type = false;
     591            0 :     new_item.in_base = false;
     592            0 :     new_item.flipped = false;
     593              : 
     594            0 :     for (std::uint8_t& i : new_item.collide_count) {
     595            0 :         i = 0;
     596              :     }
     597              : 
     598            0 :     if (owner_id != 255 && owner_id != 0) {
     599            0 :         Soldier& soldier = GetSoldierRef(owner_id);
     600            0 :         if (soldier.direction == -1) {
     601            0 :             new_item.flipped = true;
     602              :         }
     603              :     }
     604              : 
     605              :     // TODO: handle this better
     606            0 :     float particle_scale = 1.0F;
     607              : 
     608            0 :     switch (style) {
     609            0 :         case ItemType::USSOCOM:
     610            0 :             particle_scale = 1.0F;
     611            0 :             break;
     612            0 :         case ItemType::DesertEagles:
     613            0 :             particle_scale = 1.1F;
     614            0 :             break;
     615            0 :         case ItemType::Knife:
     616            0 :             particle_scale = 1.8F;
     617            0 :             break;
     618            0 :         case ItemType::MedicalKit:
     619              :         case ItemType::GrenadeKit:
     620              :         case ItemType::FlamerKit:
     621              :         case ItemType::PredatorKit:
     622              :         case ItemType::VestKit:
     623              :         case ItemType::BerserkKit:
     624              :         case ItemType::ClusterKit:
     625            0 :             particle_scale = 2.15F;
     626            0 :             break;
     627            0 :         case ItemType::MP5:
     628            0 :             particle_scale = 2.2F;
     629            0 :             break;
     630            0 :         case ItemType::M79:
     631              :         case ItemType::Chainsaw:
     632              :         case ItemType::LAW:
     633            0 :             particle_scale = 2.8F;
     634            0 :             break;
     635            0 :         case ItemType::Spas12:
     636              :         case ItemType::Ruger77:
     637            0 :             particle_scale = 3.6F;
     638            0 :             break;
     639            0 :         case ItemType::Ak74:
     640              :         case ItemType::SteyrAUG:
     641            0 :             particle_scale = 3.7F;
     642            0 :             break;
     643            0 :         case ItemType::Minimi:
     644            0 :             particle_scale = 3.9F;
     645            0 :             break;
     646            0 :         case ItemType::AlphaFlag:
     647              :         case ItemType::BravoFlag:
     648              :         case ItemType::PointmatchFlag:
     649              :         case ItemType::M2:
     650            0 :             particle_scale = 4.0F;
     651            0 :             break;
     652            0 :         case ItemType::Barrett:
     653            0 :             particle_scale = 4.3F;
     654            0 :             break;
     655            0 :         case ItemType::Bow:
     656              :         case ItemType::Parachute:
     657            0 :             particle_scale = 5.0F;
     658            0 :             break;
     659            0 :         case ItemType::Minigun:
     660            0 :             particle_scale = 5.5F;
     661            0 :             break;
     662              :     }
     663              : 
     664            0 :     switch (style) {
     665            0 :         case ItemType::AlphaFlag:
     666              :         case ItemType::BravoFlag:
     667              :         case ItemType::PointmatchFlag: {
     668            0 :             new_item.skeleton = ParticleSystem::Load(ParticleSystemType::Flag, particle_scale);
     669            0 :             new_item.radius = FLAG_RADIUS;
     670            0 :             new_item.time_out = FLAG_TIMEOUT;
     671            0 :             new_item.collide_with_bullets = true;
     672              :             // TODO: inf flag doesn't collide
     673            0 :             break;
     674              :         }
     675            0 :         case ItemType::DesertEagles:
     676              :         case ItemType::MP5:
     677              :         case ItemType::Ak74:
     678              :         case ItemType::SteyrAUG:
     679              :         case ItemType::Spas12:
     680              :         case ItemType::Ruger77:
     681              :         case ItemType::M79:
     682              :         case ItemType::Barrett:
     683              :         case ItemType::Minimi:
     684              :         case ItemType::Minigun:
     685              :         case ItemType::USSOCOM:
     686              :         case ItemType::Knife:
     687              :         case ItemType::Chainsaw:
     688              :         case ItemType::LAW:
     689              :         case ItemType::Bow: // TODO: bow has different condition
     690            0 :             new_item.skeleton = ParticleSystem::Load(ParticleSystemType::Weapon, particle_scale);
     691              :             // new_item.skeleton->VDamping = 0.989;
     692              :             // new_item.skeleton->GravityMultiplier = 1.07;
     693            0 :             new_item.radius = GUN_RADIUS;
     694            0 :             new_item.time_out = GUN_TIMEOUT;
     695              :             // new_item.interest : = DEFAULT_INTEREST_TIME;
     696            0 :             new_item.collide_with_bullets = true; // TODO: sv_guns_collide.Value;
     697            0 :             break;
     698            0 :         case ItemType::FlamerKit:
     699              :         case ItemType::PredatorKit:
     700              :         case ItemType::BerserkKit:
     701              :         case ItemType::MedicalKit:
     702              :         case ItemType::ClusterKit:
     703              :         case ItemType::VestKit:
     704              :         case ItemType::GrenadeKit:
     705            0 :             new_item.skeleton = ParticleSystem::Load(ParticleSystemType::Kit, particle_scale);
     706              :             // new_item.skeleton->VDamping = 0.989;
     707              :             // new_item.skeleton->GravityMultiplier = 1.07;
     708            0 :             new_item.radius = KIT_RADIUS;
     709            0 :             new_item.time_out = FLAG_TIMEOUT; // TODO
     710              :             // new_item.interest : = DEFAULT_INTEREST_TIME;
     711            0 :             new_item.collide_with_bullets = true; // TODO: sv_kits_collide.Value;
     712            0 :             break;
     713            0 :         case ItemType::Parachute:
     714            0 :             new_item.skeleton = ParticleSystem::Load(ParticleSystemType::Parachute, particle_scale);
     715            0 :             new_item.time_out = 3600;
     716            0 :             break;
     717            0 :         case ItemType::M2:
     718              :             new_item.skeleton =
     719            0 :               ParticleSystem::Load(ParticleSystemType::StationaryGun, particle_scale);
     720            0 :             new_item.time_out = 60;
     721            0 :             new_item.radius = STAT_RADIUS;
     722            0 :             new_item.collide_with_bullets = false;
     723            0 :             break;
     724              :     }
     725              : 
     726            0 :     if (new_id >= state_.items.size()) {
     727            0 :         spdlog::critical("Trying to create a new item but array is full, id: {}", new_id);
     728              :     }
     729              : 
     730            0 :     state_.items.at(new_id) = new_item;
     731            0 :     SetItemPosition(new_id, position);
     732              : 
     733            0 :     return state_.items.back();
     734            0 : }
     735              : 
     736            0 : void StateManager::SetItemPosition(unsigned int id, glm::vec2 new_position)
     737              : {
     738            0 :     Item& item = state_.items.at(id);
     739            0 :     glm::vec2 direction = new_position - item.skeleton->GetPos(1);
     740            0 :     MoveItemIntoDirection(id, direction);
     741            0 : }
     742              : 
     743            0 : void StateManager::MoveItemIntoDirection(unsigned int id, glm::vec2 direction)
     744              : {
     745            0 :     Item& item = state_.items.at(id);
     746            0 :     for (unsigned int i = 1; i <= item.skeleton->GetParticles().size(); ++i) {
     747            0 :         glm::vec2 new_position = item.skeleton->GetPos(i) + direction;
     748            0 :         item.skeleton->SetPos(i, new_position);
     749            0 :         item.skeleton->SetOldPos(i, new_position);
     750              :     }
     751            0 : }
     752              : 
     753            0 : void StateManager::TransformItems(const std::function<void(Item& item)>& transform_item_function)
     754              : {
     755            0 :     for (auto& item : state_.items) {
     756            0 :         if (!item.active) {
     757            0 :             continue;
     758              :         }
     759              : 
     760            0 :         transform_item_function(item);
     761              :     }
     762            0 : }
     763              : 
     764            0 : void StateManager::ForEachItem(
     765              :   const std::function<void(const Item& item)>& for_each_item_function) const
     766              : {
     767            0 :     for (const Item& item : state_.items) {
     768            0 :         if (!item.active) {
     769            0 :             continue;
     770              :         }
     771              : 
     772            0 :         for_each_item_function(item);
     773              :     }
     774            0 : }
     775              : 
     776            0 : Soldier& StateManager::GetSoldierRef(std::uint8_t soldier_id)
     777              : {
     778            0 :     if (soldier_id >= state_.soldiers.size()) {
     779            0 :         spdlog::critical("Trying to access soldier of invalid id: {}", soldier_id);
     780              :         std::unreachable();
     781              :     }
     782              : 
     783            0 :     return state_.soldiers.at(soldier_id);
     784              : }
     785              : 
     786            0 : Item& StateManager::GetItemRef(std::uint8_t item_id)
     787              : {
     788            0 :     if (item_id >= state_.items.size()) {
     789            0 :         spdlog::critical("Trying to access item of invalid id: {}", item_id);
     790              :         std::unreachable();
     791              :     }
     792              : 
     793            0 :     return state_.items.at(item_id);
     794              : }
     795              : } // namespace Soldank
        

Generated by: LCOV version 2.0-1