Browse Source

Merge pull request #236 from djeada/copilot/update-ai-knight-production

⚔️ Enable AI Knight Production for Kingdom of Iron Nation
Adam Djellouli 2 months ago
parent
commit
37a07051a0

+ 12 - 4
game/systems/ai_system/ai_reasoner.cpp

@@ -1,5 +1,6 @@
 #include "ai_reasoner.h"
 #include "../../game_config.h"
+#include "../nation_registry.h"
 #include "ai_utils.h"
 #include <algorithm>
 #include <cmath>
@@ -9,6 +10,11 @@ namespace Game::Systems::AI {
 
 void AIReasoner::updateContext(const AISnapshot &snapshot, AIContext &ctx) {
 
+  if (!ctx.nation) {
+    ctx.nation =
+        Game::Systems::NationRegistry::instance().getNationForPlayer(ctx.playerId);
+  }
+
   cleanupDeadUnits(snapshot, ctx);
 
   ctx.militaryUnits.clear();
@@ -73,10 +79,12 @@ void AIReasoner::updateContext(const AISnapshot &snapshot, AIContext &ctx) {
     ctx.militaryUnits.push_back(entity.id);
     ctx.totalUnits++;
 
-    if (entity.unitType == "archer") {
-      ctx.rangedCount++;
-    } else if (entity.unitType == "swordsman" || entity.unitType == "warrior") {
-      ctx.meleeCount++;
+    if (ctx.nation) {
+      if (ctx.nation->isRangedUnit(entity.unitType)) {
+        ctx.rangedCount++;
+      } else if (ctx.nation->isMeleeUnit(entity.unitType)) {
+        ctx.meleeCount++;
+      }
     }
 
     if (!entity.movement.hasComponent || !entity.movement.hasTarget) {

+ 11 - 8
game/systems/ai_system/ai_tactical.cpp

@@ -1,4 +1,5 @@
 #include "ai_tactical.h"
+#include "../nation_registry.h"
 #include "ai_utils.h"
 #include <algorithm>
 #include <cmath>
@@ -97,7 +98,7 @@ TacticalUtils::TargetScore TacticalUtils::selectFocusFireTarget(
       }
     }
 
-    float typePriority = getUnitTypePriority(enemy->unitType);
+    float typePriority = getUnitTypePriority(enemy->unitType, context.nation);
     score += typePriority * 3.0f;
 
     if (!enemy->isBuilding) {
@@ -196,14 +197,16 @@ bool TacticalUtils::isTargetIsolated(
   return (nearbyAllies <= 1);
 }
 
-float TacticalUtils::getUnitTypePriority(const std::string &unitType) {
+float TacticalUtils::getUnitTypePriority(const std::string &unitType,
+                                         const Game::Systems::Nation *nation) {
 
-  if (unitType == "archer" || unitType == "ranged") {
-    return 3.0f;
-  }
-
-  if (unitType == "warrior" || unitType == "melee") {
-    return 2.0f;
+  if (nation) {
+    if (nation->isRangedUnit(unitType)) {
+      return 3.0f;
+    }
+    if (nation->isMeleeUnit(unitType)) {
+      return 2.0f;
+    }
   }
 
   if (unitType == "worker" || unitType == "villager") {

+ 2 - 1
game/systems/ai_system/ai_tactical.h

@@ -48,7 +48,8 @@ public:
                    const std::vector<const ContactSnapshot *> &allEnemies,
                    float isolationRadius = 8.0f);
 
-  static float getUnitTypePriority(const std::string &unitType);
+  static float getUnitTypePriority(const std::string &unitType,
+                                   const Game::Systems::Nation *nation = nullptr);
 };
 
 } // namespace Game::Systems::AI

+ 6 - 0
game/systems/ai_system/ai_types.h

@@ -8,6 +8,10 @@ namespace Engine::Core {
 using EntityID = unsigned int;
 }
 
+namespace Game::Systems {
+struct Nation;
+}
+
 namespace Game::Systems::AI {
 
 enum class AIState {
@@ -91,6 +95,8 @@ struct AIContext {
   float stateTimer = 0.0f;
   float decisionTimer = 0.0f;
 
+  const Game::Systems::Nation *nation = nullptr;
+
   std::vector<Engine::Core::EntityID> militaryUnits;
   std::vector<Engine::Core::EntityID> buildings;
   Engine::Core::EntityID primaryBarracks = 0;

+ 19 - 0
game/systems/nation_registry.cpp

@@ -59,6 +59,16 @@ const TroopType *Nation::getBestRangedTroop() const {
   return *it;
 }
 
+bool Nation::isMeleeUnit(const std::string &unitType) const {
+  const auto *troop = getTroop(unitType);
+  return troop != nullptr && troop->isMelee;
+}
+
+bool Nation::isRangedUnit(const std::string &unitType) const {
+  const auto *troop = getTroop(unitType);
+  return troop != nullptr && !troop->isMelee;
+}
+
 NationRegistry &NationRegistry::instance() {
   static NationRegistry inst;
   return inst;
@@ -123,6 +133,15 @@ void NationRegistry::initializeDefaults() {
   archer.priority = 10;
   kingdomOfIron.availableTroops.push_back(archer);
 
+  TroopType knight;
+  knight.unitType = "knight";
+  knight.displayName = "Knight";
+  knight.isMelee = true;
+  knight.cost = 100;
+  knight.buildTime = 8.0f;
+  knight.priority = 10;
+  kingdomOfIron.availableTroops.push_back(knight);
+
   registerNation(std::move(kingdomOfIron));
 
   m_defaultNation = "kingdom_of_iron";

+ 3 - 0
game/systems/nation_registry.h

@@ -32,6 +32,9 @@ struct Nation {
 
   const TroopType *getBestMeleeTroop() const;
   const TroopType *getBestRangedTroop() const;
+
+  bool isMeleeUnit(const std::string &unitType) const;
+  bool isRangedUnit(const std::string &unitType) const;
 };
 
 class NationRegistry {