define ship roles via added modules and allow multiple weapons
This commit is contained in:
@@ -2,10 +2,13 @@
|
||||
|
||||
#include <random>
|
||||
|
||||
#include <QPoint>
|
||||
#include <QVector2D>
|
||||
|
||||
#include "AiSystem.h"
|
||||
#include "BeltSystem.h"
|
||||
#include "ModuleOwnerComponent.h"
|
||||
#include "ShipLayout.h"
|
||||
#include "Building.h"
|
||||
#include "BuildingSystem.h"
|
||||
#include "BuildingType.h"
|
||||
@@ -81,6 +84,7 @@ struct Fixture
|
||||
ai.tickHomeReturnBehavior(admin);
|
||||
ai.tickThreatResponseBehavior(admin, buildings);
|
||||
ai.tickRepairBehavior(admin, buildings);
|
||||
ai.tickRepairTools(admin);
|
||||
ai.tickSalvageBehavior(admin, scraps, buildings);
|
||||
movementIntent.tick(admin);
|
||||
dynamicBody.tick(admin);
|
||||
@@ -88,6 +92,28 @@ struct Fixture
|
||||
}
|
||||
};
|
||||
|
||||
static ShipLayoutConfig makeSingleModuleLayout(const std::string& moduleId)
|
||||
{
|
||||
PlacedModule pm;
|
||||
pm.moduleId = moduleId;
|
||||
pm.position = QPoint(1, 1);
|
||||
pm.rotation = Rotation::East;
|
||||
ShipLayoutConfig layout;
|
||||
layout.placedModules.push_back(pm);
|
||||
return layout;
|
||||
}
|
||||
|
||||
static entt::entity firstSalvageChild(EntityAdmin& admin, entt::entity ship)
|
||||
{
|
||||
entt::entity result = entt::null;
|
||||
admin.forEach<SalvageCargoComponent, ModuleOwnerComponent>(
|
||||
[&](entt::entity ce, const SalvageCargoComponent&, const ModuleOwnerComponent& o)
|
||||
{
|
||||
if (o.owner == ship && result == entt::null) { result = ce; }
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
// Helpers to read ECS data for a ship entity.
|
||||
static const MovementIntentComponent& intent(EntityAdmin& a, entt::entity e)
|
||||
{
|
||||
@@ -299,7 +325,9 @@ TEST_CASE("BehaviorSystem: repair ship writes intent toward damaged friendly shi
|
||||
"[behavior]")
|
||||
{
|
||||
Fixture f;
|
||||
const entt::entity repairShip = f.ships.spawn("repair_ship", 1, QVector2D(0.0f, 0.0f));
|
||||
const ShipLayoutConfig repairLayout = makeSingleModuleLayout("repair_tool_module");
|
||||
const entt::entity repairShip = f.ships.spawn("repair_ship", 1, QVector2D(0.0f, 0.0f),
|
||||
false, repairLayout);
|
||||
const entt::entity friendly = f.ships.spawn("interceptor", 1, QVector2D(5.0f, 0.0f));
|
||||
|
||||
f.admin.get<HealthComponent>(friendly).hp = f.admin.get<HealthComponent>(friendly).maxHp * 0.5f;
|
||||
@@ -315,7 +343,9 @@ TEST_CASE("BehaviorSystem: repair ship heals damaged ally within repair range",
|
||||
"[behavior]")
|
||||
{
|
||||
Fixture f;
|
||||
const entt::entity repairShip = f.ships.spawn("repair_ship", 1, QVector2D(0.0f, 0.0f));
|
||||
const ShipLayoutConfig repairLayout = makeSingleModuleLayout("repair_tool_module");
|
||||
const entt::entity repairShip = f.ships.spawn("repair_ship", 1, QVector2D(0.0f, 0.0f),
|
||||
false, repairLayout);
|
||||
const entt::entity friendly = f.ships.spawn("interceptor", 1, QVector2D(1.0f, 0.0f));
|
||||
|
||||
const float initialHp = f.admin.get<HealthComponent>(friendly).maxHp * 0.5f;
|
||||
@@ -323,6 +353,7 @@ TEST_CASE("BehaviorSystem: repair ship heals damaged ally within repair range",
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
f.ai.tickRepairBehavior(f.admin, f.buildings);
|
||||
f.ai.tickRepairTools(f.admin);
|
||||
|
||||
REQUIRE(health(f.admin, friendly).hp > initialHp);
|
||||
}
|
||||
@@ -330,7 +361,8 @@ TEST_CASE("BehaviorSystem: repair ship heals damaged ally within repair range",
|
||||
TEST_CASE("BehaviorSystem: repair ship does not heal above maxHp", "[behavior]")
|
||||
{
|
||||
Fixture f;
|
||||
f.ships.spawn("repair_ship", 1, QVector2D(0.0f, 0.0f));
|
||||
const ShipLayoutConfig repairLayout = makeSingleModuleLayout("repair_tool_module");
|
||||
f.ships.spawn("repair_ship", 1, QVector2D(0.0f, 0.0f), false, repairLayout);
|
||||
const entt::entity friendly = f.ships.spawn("interceptor", 1, QVector2D(1.0f, 0.0f));
|
||||
|
||||
f.admin.get<HealthComponent>(friendly).hp = f.admin.get<HealthComponent>(friendly).maxHp - 0.001f;
|
||||
@@ -339,6 +371,7 @@ TEST_CASE("BehaviorSystem: repair ship does not heal above maxHp", "[behavior]")
|
||||
{
|
||||
f.ships.clearMovementIntents();
|
||||
f.ai.tickRepairBehavior(f.admin, f.buildings);
|
||||
f.ai.tickRepairTools(f.admin);
|
||||
}
|
||||
|
||||
const HealthComponent& h = health(f.admin, friendly);
|
||||
@@ -353,7 +386,9 @@ TEST_CASE("BehaviorSystem: repair ship does not heal above maxHp", "[behavior]")
|
||||
TEST_CASE("BehaviorSystem: salvage ship writes intent toward nearest scrap", "[behavior]")
|
||||
{
|
||||
Fixture f;
|
||||
const entt::entity ship = f.ships.spawn("salvage_ship", 1, QVector2D(0.0f, 0.0f));
|
||||
const ShipLayoutConfig salvageLayout = makeSingleModuleLayout("salvage_bay_module");
|
||||
const entt::entity ship = f.ships.spawn("salvage_ship", 1, QVector2D(0.0f, 0.0f),
|
||||
false, salvageLayout);
|
||||
|
||||
const QVector2D scrapPos(100.0f, 0.0f);
|
||||
f.scraps.spawn(scrapPos, 1, 100000);
|
||||
@@ -368,13 +403,17 @@ TEST_CASE("BehaviorSystem: salvage ship writes intent toward nearest scrap", "[b
|
||||
TEST_CASE("BehaviorSystem: salvage ship collects scrap on arrival", "[behavior]")
|
||||
{
|
||||
Fixture f;
|
||||
const entt::entity ship = f.ships.spawn("salvage_ship", 1, QVector2D(0.0f, 0.0f));
|
||||
const ShipLayoutConfig salvageLayout = makeSingleModuleLayout("salvage_bay_module");
|
||||
const entt::entity ship = f.ships.spawn("salvage_ship", 1, QVector2D(0.0f, 0.0f),
|
||||
false, salvageLayout);
|
||||
const entt::entity scrapEntity = f.scraps.spawn(QVector2D(0.0f, 0.0f), 1, 100000);
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
f.ai.tickSalvageBehavior(f.admin, f.scraps, f.buildings);
|
||||
|
||||
REQUIRE(f.admin.get<SalvageCargoComponent>(ship).current == 1);
|
||||
const entt::entity sc = firstSalvageChild(f.admin, ship);
|
||||
REQUIRE(f.admin.isValid(sc));
|
||||
REQUIRE(f.admin.get<SalvageCargoComponent>(sc).current == 1);
|
||||
REQUIRE_FALSE(f.admin.isValid(scrapEntity));
|
||||
}
|
||||
|
||||
@@ -395,9 +434,15 @@ TEST_CASE("BehaviorSystem: full-cargo salvage ship moves toward SalvageBay", "[b
|
||||
}
|
||||
REQUIRE(f.buildings.findBuilding(bayId) != nullptr);
|
||||
|
||||
const entt::entity ship = f.ships.spawn("salvage_ship", 1, QVector2D(5.0f, 0.0f));
|
||||
SalvageCargoComponent& cargo = f.admin.get<SalvageCargoComponent>(ship);
|
||||
cargo.current = cargo.capacity; // full cargo
|
||||
const ShipLayoutConfig salvageLayout = makeSingleModuleLayout("salvage_bay_module");
|
||||
const entt::entity ship = f.ships.spawn("salvage_ship", 1, QVector2D(5.0f, 0.0f),
|
||||
false, salvageLayout);
|
||||
{
|
||||
const entt::entity sc = firstSalvageChild(f.admin, ship);
|
||||
REQUIRE(f.admin.isValid(sc));
|
||||
SalvageCargoComponent& cargo = f.admin.get<SalvageCargoComponent>(sc);
|
||||
cargo.current = cargo.capacity; // full cargo
|
||||
}
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
f.ai.tickSalvageBehavior(f.admin, f.scraps, f.buildings);
|
||||
@@ -467,7 +512,9 @@ TEST_CASE("SensorRange: enemy ship ignores player just outside sensor range", "[
|
||||
TEST_CASE("SensorRange: repair ship retreats from enemy within sensor range", "[sensor]")
|
||||
{
|
||||
Fixture f;
|
||||
const entt::entity repairShip = f.ships.spawn("repair_ship", 1, QVector2D(0.0f, 0.0f));
|
||||
const ShipLayoutConfig repairLayout = makeSingleModuleLayout("repair_tool_module");
|
||||
const entt::entity repairShip = f.ships.spawn("repair_ship", 1, QVector2D(0.0f, 0.0f),
|
||||
false, repairLayout);
|
||||
f.ships.spawn("interceptor", 1, QVector2D(200.0f, 0.0f), /*isEnemy=*/true);
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
@@ -480,7 +527,9 @@ TEST_CASE("SensorRange: repair ship retreats from enemy within sensor range", "[
|
||||
TEST_CASE("SensorRange: repair ship does not retreat from enemy beyond sensor range", "[sensor]")
|
||||
{
|
||||
Fixture f;
|
||||
const entt::entity repairShip = f.ships.spawn("repair_ship", 1, QVector2D(0.0f, 0.0f));
|
||||
const ShipLayoutConfig repairLayout = makeSingleModuleLayout("repair_tool_module");
|
||||
const entt::entity repairShip = f.ships.spawn("repair_ship", 1, QVector2D(0.0f, 0.0f),
|
||||
false, repairLayout);
|
||||
f.ships.spawn("interceptor", 1, QVector2D(300.0f, 0.0f), /*isEnemy=*/true);
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
@@ -492,7 +541,9 @@ TEST_CASE("SensorRange: repair ship does not retreat from enemy beyond sensor ra
|
||||
TEST_CASE("SensorRange: repair ship does not acquire damaged ally beyond sensor range", "[sensor]")
|
||||
{
|
||||
Fixture f;
|
||||
const entt::entity repairShip = f.ships.spawn("repair_ship", 1, QVector2D(0.0f, 0.0f));
|
||||
const ShipLayoutConfig repairLayout = makeSingleModuleLayout("repair_tool_module");
|
||||
const entt::entity repairShip = f.ships.spawn("repair_ship", 1, QVector2D(0.0f, 0.0f),
|
||||
false, repairLayout);
|
||||
const entt::entity friendly = f.ships.spawn("interceptor", 1, QVector2D(300.0f, 0.0f));
|
||||
f.admin.get<HealthComponent>(friendly).hp = f.admin.get<HealthComponent>(friendly).maxHp * 0.5f;
|
||||
|
||||
@@ -509,7 +560,9 @@ TEST_CASE("SensorRange: repair ship does not acquire damaged ally beyond sensor
|
||||
TEST_CASE("SensorRange: salvage ship ignores scrap beyond sensor range", "[sensor]")
|
||||
{
|
||||
Fixture f;
|
||||
const entt::entity ship = f.ships.spawn("salvage_ship", 1, QVector2D(0.0f, 0.0f));
|
||||
const ShipLayoutConfig salvageLayout = makeSingleModuleLayout("salvage_bay_module");
|
||||
const entt::entity ship = f.ships.spawn("salvage_ship", 1, QVector2D(0.0f, 0.0f),
|
||||
false, salvageLayout);
|
||||
f.scraps.spawn(QVector2D(300.0f, 0.0f), 1, 100000);
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
|
||||
Reference in New Issue
Block a user