unify Weapon and StationWeapon components
This commit is contained in:
@@ -114,7 +114,7 @@ void ArenaSimulation::placeStructures()
|
|||||||
auto placeArenaStation = [&](const ArenaStationEntry& entry, bool isEnemy)
|
auto placeArenaStation = [&](const ArenaStationEntry& entry, bool isEnemy)
|
||||||
{
|
{
|
||||||
float hp = 0.0f;
|
float hp = 0.0f;
|
||||||
StationWeapon weapon;
|
Weapon weapon;
|
||||||
weapon.cooldownTicks = 0.0f;
|
weapon.cooldownTicks = 0.0f;
|
||||||
weapon.currentTarget = std::nullopt;
|
weapon.currentTarget = std::nullopt;
|
||||||
const double lv = static_cast<double>(entry.level);
|
const double lv = static_cast<double>(entry.level);
|
||||||
@@ -155,7 +155,7 @@ void ArenaSimulation::placeStructures()
|
|||||||
}
|
}
|
||||||
const entt::entity stationEntity = m_admin.spawnStation(
|
const entt::entity stationEntity = m_admin.spawnStation(
|
||||||
anchor, parsed.footprint, absCells, hp, hp, isEnemy);
|
anchor, parsed.footprint, absCells, hp, hp, isEnemy);
|
||||||
m_admin.addComponent<StationWeapon>(stationEntity, weapon);
|
m_admin.addComponent<Weapon>(stationEntity, weapon);
|
||||||
m_buildingSystem->registerTileOccupancy(absCells, allocateId());
|
m_buildingSystem->registerTileOccupancy(absCells, allocateId());
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -500,3 +500,4 @@ void ArenaSimulation::updateStatus()
|
|||||||
std::lock_guard<std::mutex> lock(m_statusMutex);
|
std::lock_guard<std::mutex> lock(m_statusMutex);
|
||||||
m_status = newStatus;
|
m_status = newStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,8 +84,6 @@ struct StationBody
|
|||||||
std::vector<QPoint> bodyCells;
|
std::vector<QPoint> bodyCells;
|
||||||
};
|
};
|
||||||
|
|
||||||
// StationWeapon remains defined in Building.h.
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Scrap components
|
// Scrap components
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -105,3 +103,4 @@ struct DespawnAt
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
struct HqProxy { char unused = 0; };
|
struct HqProxy { char unused = 0; };
|
||||||
|
|
||||||
|
|||||||
@@ -56,17 +56,6 @@ struct ConstructionSite
|
|||||||
std::optional<ShipLayoutConfig> shipLayout;
|
std::optional<ShipLayoutConfig> shipLayout;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Weapon state for stationary structures (defence stations).
|
|
||||||
// Distinct from Ship::Weapon; stations have no movement intent.
|
|
||||||
struct StationWeapon
|
|
||||||
{
|
|
||||||
float damage;
|
|
||||||
float range;
|
|
||||||
float fireRateHz;
|
|
||||||
float cooldownTicks;
|
|
||||||
std::optional<entt::entity> currentTarget;
|
|
||||||
};
|
|
||||||
|
|
||||||
// A fully constructed, operational building.
|
// A fully constructed, operational building.
|
||||||
struct Building
|
struct Building
|
||||||
{
|
{
|
||||||
@@ -90,3 +79,4 @@ struct Building
|
|||||||
// Module layout for shipyards (REQ-MOD-LAYOUT).
|
// Module layout for shipyards (REQ-MOD-LAYOUT).
|
||||||
std::optional<ShipLayoutConfig> shipLayout;
|
std::optional<ShipLayoutConfig> shipLayout;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -16,31 +16,30 @@ void CombatSystem::tick(Tick currentTick,
|
|||||||
std::vector<FireEvent>& outFireEvents)
|
std::vector<FireEvent>& outFireEvents)
|
||||||
{
|
{
|
||||||
// Ship weapons.
|
// Ship weapons.
|
||||||
admin.forEach<Weapon, ThreatResponse, Position>(
|
admin.forEach<Weapon, ThreatResponse, Position, Faction>(
|
||||||
[&](entt::entity e, Weapon& weapon, ThreatResponse& threat, Position& pos)
|
[&](entt::entity e, Weapon& weapon, ThreatResponse& threat, Position& pos, Faction& faction)
|
||||||
{
|
{
|
||||||
resolveShipWeapon(e, weapon, threat, pos, currentTick, admin, outFireEvents);
|
weapon.currentTarget = threat.currentTarget;
|
||||||
|
resolveWeapon(e, weapon, pos, faction, currentTick, admin, outFireEvents);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Station weapons.
|
// Station weapons.
|
||||||
admin.forEach<StationWeapon, Position, Faction>(
|
admin.forEach<Weapon, Position, Faction>(
|
||||||
[&](entt::entity e, StationWeapon& weapon, Position& pos, Faction& faction)
|
[&](entt::entity e, Weapon& weapon, Position& pos, Faction& faction)
|
||||||
{
|
{
|
||||||
resolveStationWeapon(e, weapon, pos, faction, currentTick, admin, outFireEvents);
|
resolveWeapon(e, weapon, pos, faction, currentTick, admin, outFireEvents);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CombatSystem::resolveShipWeapon(entt::entity shipEntity, Weapon& weapon,
|
void CombatSystem::resolveWeapon(
|
||||||
const ThreatResponse& threat,
|
entt::entity shipEntity,
|
||||||
const Position& pos, Tick currentTick,
|
Weapon& weapon,
|
||||||
|
const Position& ownPos,
|
||||||
|
const Faction& ownFaction,
|
||||||
|
Tick currentTick,
|
||||||
EntityAdmin& admin,
|
EntityAdmin& admin,
|
||||||
std::vector<FireEvent>& out)
|
std::vector<FireEvent>& out)
|
||||||
{
|
{
|
||||||
if (!threat.currentTarget)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (weapon.cooldownTicks > 0.0f)
|
if (weapon.cooldownTicks > 0.0f)
|
||||||
{
|
{
|
||||||
weapon.cooldownTicks -= 1.0f;
|
weapon.cooldownTicks -= 1.0f;
|
||||||
@@ -50,39 +49,6 @@ void CombatSystem::resolveShipWeapon(entt::entity shipEntity, Weapon& weapon,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const entt::entity targetEntity = *threat.currentTarget;
|
|
||||||
if (!admin.isValid(targetEntity) || !admin.hasAll<Position>(targetEntity))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QVector2D targetPos = admin.get<Position>(targetEntity).value;
|
|
||||||
const float dist = (pos.value - targetPos).length();
|
|
||||||
if (dist > weapon.range)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_pendingDamage.push_back({targetEntity, weapon.damage,
|
|
||||||
currentTick + kWeaponImpactDelayTicks});
|
|
||||||
|
|
||||||
FireEvent evt;
|
|
||||||
evt.shooter = shipEntity;
|
|
||||||
evt.target = targetEntity;
|
|
||||||
evt.emittedAt = currentTick;
|
|
||||||
out.push_back(evt);
|
|
||||||
|
|
||||||
weapon.cooldownTicks = static_cast<float>(kTickRateHz) / weapon.fireRateHz;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CombatSystem::resolveStationWeapon(entt::entity stationEntity,
|
|
||||||
StationWeapon& weapon,
|
|
||||||
const Position& stationPos,
|
|
||||||
const Faction& stationFaction,
|
|
||||||
Tick currentTick,
|
|
||||||
EntityAdmin& admin,
|
|
||||||
std::vector<FireEvent>& out)
|
|
||||||
{
|
|
||||||
// Validate or clear existing target.
|
// Validate or clear existing target.
|
||||||
if (weapon.currentTarget)
|
if (weapon.currentTarget)
|
||||||
{
|
{
|
||||||
@@ -93,8 +59,8 @@ void CombatSystem::resolveStationWeapon(entt::entity stationEntity,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const float dist = (stationPos.value - admin.get<Position>(t).value).length();
|
const float distanceSquared = (ownPos.value - admin.get<Position>(t).value).lengthSquared();
|
||||||
if (dist > weapon.range)
|
if (distanceSquared > weapon.range * weapon.range)
|
||||||
{
|
{
|
||||||
weapon.currentTarget = std::nullopt;
|
weapon.currentTarget = std::nullopt;
|
||||||
}
|
}
|
||||||
@@ -104,22 +70,22 @@ void CombatSystem::resolveStationWeapon(entt::entity stationEntity,
|
|||||||
// Acquire a new target if needed (nearest opposing-faction ship).
|
// Acquire a new target if needed (nearest opposing-faction ship).
|
||||||
if (!weapon.currentTarget)
|
if (!weapon.currentTarget)
|
||||||
{
|
{
|
||||||
float bestDist = weapon.range;
|
float bestDistanceSquared = weapon.range * weapon.range;
|
||||||
admin.forEach<ShipIdentity, Position, Faction>(
|
admin.forEach<ShipIdentity, Position, Faction>(
|
||||||
[&](entt::entity candidate, const ShipIdentity& /*si*/,
|
[&](entt::entity candidate, const ShipIdentity& /*si*/,
|
||||||
const Position& candidatePos, const Faction& candidateFaction)
|
const Position& candidatePos, const Faction& candidateFaction)
|
||||||
{
|
{
|
||||||
const bool isValidTarget = stationFaction.isEnemy
|
const bool isValidTarget = ownFaction.isEnemy
|
||||||
? !candidateFaction.isEnemy
|
? !candidateFaction.isEnemy
|
||||||
: candidateFaction.isEnemy;
|
: candidateFaction.isEnemy;
|
||||||
if (!isValidTarget)
|
if (!isValidTarget)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const float dist = (candidatePos.value - stationPos.value).length();
|
const float distanceSquared = (candidatePos.value - ownPos.value).lengthSquared();
|
||||||
if (dist < bestDist)
|
if (distanceSquared < bestDistanceSquared)
|
||||||
{
|
{
|
||||||
bestDist = dist;
|
bestDistanceSquared = distanceSquared;
|
||||||
weapon.currentTarget = candidate;
|
weapon.currentTarget = candidate;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -130,33 +96,12 @@ void CombatSystem::resolveStationWeapon(entt::entity stationEntity,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (weapon.cooldownTicks > 0.0f)
|
|
||||||
{
|
|
||||||
weapon.cooldownTicks -= 1.0f;
|
|
||||||
}
|
|
||||||
if (weapon.cooldownTicks > 0.0f)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const entt::entity targetEntity = *weapon.currentTarget;
|
const entt::entity targetEntity = *weapon.currentTarget;
|
||||||
if (!admin.isValid(targetEntity) || !admin.hasAll<Position>(targetEntity))
|
|
||||||
{
|
|
||||||
weapon.currentTarget = std::nullopt;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QVector2D targetPos = admin.get<Position>(targetEntity).value;
|
|
||||||
if ((stationPos.value - targetPos).length() > weapon.range)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_pendingDamage.push_back({targetEntity, weapon.damage,
|
m_pendingDamage.push_back({targetEntity, weapon.damage,
|
||||||
currentTick + kWeaponImpactDelayTicks});
|
currentTick + kWeaponImpactDelayTicks});
|
||||||
|
|
||||||
FireEvent evt;
|
FireEvent evt;
|
||||||
evt.shooter = stationEntity;
|
evt.shooter = shipEntity;
|
||||||
evt.target = targetEntity;
|
evt.target = targetEntity;
|
||||||
evt.emittedAt = currentTick;
|
evt.emittedAt = currentTick;
|
||||||
out.push_back(evt);
|
out.push_back(evt);
|
||||||
@@ -183,3 +128,4 @@ void CombatSystem::applyPendingDamage(Tick currentTick, EntityAdmin& admin)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,19 +39,15 @@ private:
|
|||||||
|
|
||||||
std::vector<PendingDamage> m_pendingDamage;
|
std::vector<PendingDamage> m_pendingDamage;
|
||||||
|
|
||||||
void resolveShipWeapon(entt::entity shipEntity, Weapon& weapon,
|
void resolveWeapon(
|
||||||
const ThreatResponse& threat,
|
entt::entity shipEntity,
|
||||||
const Position& pos, Tick currentTick,
|
Weapon& weapon,
|
||||||
EntityAdmin& admin,
|
const Position& ownPos,
|
||||||
std::vector<FireEvent>& out);
|
const Faction& ownFaction,
|
||||||
|
|
||||||
void resolveStationWeapon(entt::entity stationEntity,
|
|
||||||
StationWeapon& weapon,
|
|
||||||
const Position& stationPos,
|
|
||||||
const Faction& stationFaction,
|
|
||||||
Tick currentTick,
|
Tick currentTick,
|
||||||
EntityAdmin& admin,
|
EntityAdmin& admin,
|
||||||
std::vector<FireEvent>& out);
|
std::vector<FireEvent>& out);
|
||||||
|
|
||||||
const GameConfig& m_config;
|
const GameConfig& m_config;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ void Simulation::placeInitialStructures()
|
|||||||
const float psHp = static_cast<float>(
|
const float psHp = static_cast<float>(
|
||||||
m_config.stations.playerStation.hpFormula.evaluate(psLevel));
|
m_config.stations.playerStation.hpFormula.evaluate(psLevel));
|
||||||
|
|
||||||
StationWeapon psWeapon;
|
Weapon psWeapon;
|
||||||
psWeapon.damage = static_cast<float>(
|
psWeapon.damage = static_cast<float>(
|
||||||
m_config.stations.playerStation.damageFormula.evaluate(psLevel));
|
m_config.stations.playerStation.damageFormula.evaluate(psLevel));
|
||||||
psWeapon.range = static_cast<float>(
|
psWeapon.range = static_cast<float>(
|
||||||
@@ -246,7 +246,7 @@ void Simulation::placeInitialStructures()
|
|||||||
}
|
}
|
||||||
m_playerStation1Entity = m_admin.spawnStation(
|
m_playerStation1Entity = m_admin.spawnStation(
|
||||||
anchor, psParsed.footprint, absCells, psHp, psHp, false);
|
anchor, psParsed.footprint, absCells, psHp, psHp, false);
|
||||||
m_admin.addComponent<StationWeapon>(m_playerStation1Entity, psWeapon);
|
m_admin.addComponent<Weapon>(m_playerStation1Entity, psWeapon);
|
||||||
m_buildingSystem->registerTileOccupancy(absCells, allocateId());
|
m_buildingSystem->registerTileOccupancy(absCells, allocateId());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@@ -258,7 +258,7 @@ void Simulation::placeInitialStructures()
|
|||||||
}
|
}
|
||||||
m_playerStation2Entity = m_admin.spawnStation(
|
m_playerStation2Entity = m_admin.spawnStation(
|
||||||
anchor, psParsed.footprint, absCells, psHp, psHp, false);
|
anchor, psParsed.footprint, absCells, psHp, psHp, false);
|
||||||
m_admin.addComponent<StationWeapon>(m_playerStation2Entity, psWeapon);
|
m_admin.addComponent<Weapon>(m_playerStation2Entity, psWeapon);
|
||||||
m_buildingSystem->registerTileOccupancy(absCells, allocateId());
|
m_buildingSystem->registerTileOccupancy(absCells, allocateId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,7 +285,7 @@ void Simulation::placeEnemyStationSet(int generation)
|
|||||||
const float esHp = static_cast<float>(
|
const float esHp = static_cast<float>(
|
||||||
m_config.stations.enemyStation.hpFormula.evaluate(genD));
|
m_config.stations.enemyStation.hpFormula.evaluate(genD));
|
||||||
|
|
||||||
StationWeapon esWeapon;
|
Weapon esWeapon;
|
||||||
esWeapon.damage = static_cast<float>(
|
esWeapon.damage = static_cast<float>(
|
||||||
m_config.stations.enemyStation.damageFormula.evaluate(genD));
|
m_config.stations.enemyStation.damageFormula.evaluate(genD));
|
||||||
esWeapon.range = static_cast<float>(
|
esWeapon.range = static_cast<float>(
|
||||||
@@ -307,7 +307,7 @@ void Simulation::placeEnemyStationSet(int generation)
|
|||||||
}
|
}
|
||||||
m_currentEnemyStationEntities[0] = m_admin.spawnStation(
|
m_currentEnemyStationEntities[0] = m_admin.spawnStation(
|
||||||
anchor, esParsed.footprint, absCells, esHp, esHp, true);
|
anchor, esParsed.footprint, absCells, esHp, esHp, true);
|
||||||
m_admin.addComponent<StationWeapon>(m_currentEnemyStationEntities[0], esWeapon);
|
m_admin.addComponent<Weapon>(m_currentEnemyStationEntities[0], esWeapon);
|
||||||
m_buildingSystem->registerTileOccupancy(absCells, allocateId());
|
m_buildingSystem->registerTileOccupancy(absCells, allocateId());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@@ -319,7 +319,7 @@ void Simulation::placeEnemyStationSet(int generation)
|
|||||||
}
|
}
|
||||||
m_currentEnemyStationEntities[1] = m_admin.spawnStation(
|
m_currentEnemyStationEntities[1] = m_admin.spawnStation(
|
||||||
anchor, esParsed.footprint, absCells, esHp, esHp, true);
|
anchor, esParsed.footprint, absCells, esHp, esHp, true);
|
||||||
m_admin.addComponent<StationWeapon>(m_currentEnemyStationEntities[1], esWeapon);
|
m_admin.addComponent<Weapon>(m_currentEnemyStationEntities[1], esWeapon);
|
||||||
m_buildingSystem->registerTileOccupancy(absCells, allocateId());
|
m_buildingSystem->registerTileOccupancy(absCells, allocateId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,9 +165,9 @@ TEST_CASE("WaveSystem: player stations have weapon set", "[wave]")
|
|||||||
const Simulation sim(loadConfig(), 42);
|
const Simulation sim(loadConfig(), 42);
|
||||||
|
|
||||||
int armedPlayerStations = 0;
|
int armedPlayerStations = 0;
|
||||||
sim.admin().forEach<StationBody, Faction, StationWeapon>(
|
sim.admin().forEach<StationBody, Faction, Weapon>(
|
||||||
[&](entt::entity /*e*/, const StationBody& /*sb*/, const Faction& f,
|
[&](entt::entity /*e*/, const StationBody& /*sb*/, const Faction& f,
|
||||||
const StationWeapon& w)
|
const Weapon& w)
|
||||||
{
|
{
|
||||||
if (!f.isEnemy)
|
if (!f.isEnemy)
|
||||||
{
|
{
|
||||||
@@ -185,9 +185,9 @@ TEST_CASE("WaveSystem: enemy stations have weapon set", "[wave]")
|
|||||||
const Simulation sim(loadConfig(), 42);
|
const Simulation sim(loadConfig(), 42);
|
||||||
|
|
||||||
int armedEnemyStations = 0;
|
int armedEnemyStations = 0;
|
||||||
sim.admin().forEach<StationBody, Faction, StationWeapon>(
|
sim.admin().forEach<StationBody, Faction, Weapon>(
|
||||||
[&](entt::entity /*e*/, const StationBody& /*sb*/, const Faction& f,
|
[&](entt::entity /*e*/, const StationBody& /*sb*/, const Faction& f,
|
||||||
const StationWeapon& w)
|
const Weapon& w)
|
||||||
{
|
{
|
||||||
if (f.isEnemy)
|
if (f.isEnemy)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user