diff --git a/CMakeLists.txt b/CMakeLists.txt index a28abac700..d469f6d49a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -393,6 +393,8 @@ set(MAIN_SOURCES src/systems/maneuvering.cpp src/systems/beamweapon.h src/systems/beamweapon.cpp + src/systems/lifetimesystem.h + src/systems/lifetimesystem.cpp src/systems/missilesystem.h src/systems/missilesystem.cpp src/systems/warpsystem.h diff --git a/scripts/api/entity/scanprobe.lua b/scripts/api/entity/scanprobe.lua index 2bbda31424..450de4e74d 100644 --- a/scripts/api/entity/scanprobe.lua +++ b/scripts/api/entity/scanprobe.lua @@ -9,7 +9,7 @@ function ScanProbe() local e = createEntity() e.components = { transform = {}, - lifetime = {lifetime=60*10}, + lifetime = {maximum=60*10}, radar_trace = { icon="radar/probe.png", min_size=10.0, @@ -54,13 +54,13 @@ end --- Defaults to 600 seconds (10 minutes). --- Example: probe:setLifetime(60 * 5) -- sets the lifetime to 5 minutes function Entity:setLifetime(lifetime) - if self.components.lifetime then self.components.lifetime.lifetime = lifetime end + if self.components.lifetime then self.components.lifetime.maximum = lifetime end return self end --- Returns this ScanProbe's remaining lifetime. --- Example: probe:getLifetime() function Entity:getLifetime() - if self.components.lifetime then return self.components.lifetime.lifetime end + if self.components.lifetime then return self.components.lifetime.maximum - self.components.alive_for end return 0.0 end --- Sets this ScanProbe's owner entity. diff --git a/scripts/api/gm.lua b/scripts/api/gm.lua index 45e22e3122..8516665d0b 100644 --- a/scripts/api/gm.lua +++ b/scripts/api/gm.lua @@ -555,8 +555,8 @@ end function __exportScanProbe(entity) local extras = __exportBasics(entity) local lt = entity.components.lifetime - if lt and lt.lifetime then - extras = extras .. string.format(":setLifetime(%.0f)", lt.lifetime) + if lt and lt.maximum then + extras = extras .. string.format(":setLifetime(%.0f)", lt.maximum) end local mt = entity.components.move_to if mt and mt.speed then diff --git a/scripts/science_db.lua b/scripts/science_db.lua index 13818a76b9..fa53eff025 100644 --- a/scripts/science_db.lua +++ b/scripts/science_db.lua @@ -230,7 +230,7 @@ item:addKeyValue(_('Sizes'), _('Small (S) / Medium (M) / Large (L)')) populateMissileStats(item, missile_stat_keys, hvli_stats) item:setLongDescription(_([[A high-velocity lead impactor (HVLI) fires a simple slug of lead at a high velocity. This weapon is usually found in simpler ships since it does not require guidance computers. This also means its projectiles fly in a straight line from its tube and can't pursue a target. -Each shot from an HVLI fires a burst of 5 projectiles, which increases the chance to hit but requires precision aiming to be effective. It reaches its full damage potential at a range of 2u.]])) +Each shot from an HVLI fires a burst of 5 projectiles, which increases the chance to hit but requires precision aiming to be effective. It reaches its full damage potential at a range of 1u.]])) local function angleDifference(angle_a, angle_b) local ret = (angle_b or 0) - (angle_a or 0) diff --git a/src/components/lifetime.h b/src/components/lifetime.h index d054f38158..f2cef54b9c 100644 --- a/src/components/lifetime.h +++ b/src/components/lifetime.h @@ -5,6 +5,7 @@ class LifeTime { public: - float lifetime = 1.0; + float maximum = 1.0; + float alive_for = 0.0; sp::script::Callback on_expire; }; diff --git a/src/components/missile.h b/src/components/missile.h index 891639e0cd..45495f4571 100644 --- a/src/components/missile.h +++ b/src/components/missile.h @@ -31,6 +31,7 @@ class ExplodeOnTouch sp::ecs::Entity owner; DamageType damage_type = DamageType::Kinetic; string explosion_sfx; + float full_damage_after = 0.0f; }; class ExplodeOnTimeout { diff --git a/src/init/ecs.cpp b/src/init/ecs.cpp index 294db64331..6e6cbd7986 100644 --- a/src/init/ecs.cpp +++ b/src/init/ecs.cpp @@ -49,6 +49,7 @@ #include "systems/shieldsystem.h" #include "systems/shipsystemssystem.h" #include "systems/coolantsystem.h" +#include "systems/lifetimesystem.h" #include "systems/missilesystem.h" #include "systems/maneuvering.h" #include "systems/energysystem.h" @@ -145,6 +146,7 @@ void initSystemsAndComponents() engine->registerSystem(); engine->registerSystem(); engine->registerSystem(); + engine->registerSystem(); engine->registerSystem(); engine->registerSystem(); engine->registerSystem(); diff --git a/src/script/components.cpp b/src/script/components.cpp index 22ff85fa09..dda7e66f9b 100644 --- a/src/script/components.cpp +++ b/src/script/components.cpp @@ -310,6 +310,7 @@ void initComponentScriptBindings() BIND_MEMBER(ExplodeOnTouch, owner); BIND_MEMBER(ExplodeOnTouch, damage_type); BIND_MEMBER(ExplodeOnTouch, explosion_sfx); + BIND_MEMBER(ExplodeOnTouch, full_damage_after); sp::script::ComponentHandler::name("delayed_explode_on_touch"); BIND_MEMBER(DelayedExplodeOnTouch, delay); @@ -669,7 +670,8 @@ void initComponentScriptBindings() BIND_MEMBER(MoveTo, target); BIND_MEMBER(MoveTo, on_arrival); sp::script::ComponentHandler::name("lifetime"); - BIND_MEMBER(LifeTime, lifetime); + BIND_MEMBER(LifeTime, maximum); + BIND_MEMBER(LifeTime, alive_for); BIND_MEMBER(LifeTime, on_expire); sp::script::ComponentHandler::name("faction"); diff --git a/src/systems/lifetimesystem.cpp b/src/systems/lifetimesystem.cpp new file mode 100644 index 0000000000..8510c74937 --- /dev/null +++ b/src/systems/lifetimesystem.cpp @@ -0,0 +1,28 @@ +#include "systems/lifetimesystem.h" + + +#include "components/missile.h" +#include "components/lifetime.h" +#include "ecs/query.h" +#include "multiplayer_server.h" +#include "systems/missilesystem.h" + +void LifeTimeSystem::update(float delta) +{ + if (game_server) { + // TODO: Not really part of missile + for(auto [entity, lifetime] : sp::ecs::Query()) { + lifetime.alive_for += delta; + if (lifetime.alive_for >= lifetime.maximum) { + if (entity.hasComponent() and entity.hasComponent()) { + if (auto eot = entity.getComponent()) { + if (auto missilesystem = entity.getComponent()){ + missilesystem->explode(entity, {}, *eot); + } + } + } + entity.destroy(); + } + } + } +} diff --git a/src/systems/lifetimesystem.h b/src/systems/lifetimesystem.h new file mode 100644 index 0000000000..6c716e25ee --- /dev/null +++ b/src/systems/lifetimesystem.h @@ -0,0 +1,9 @@ +#pragma once + +#include "ecs/system.h" + +class LifeTimeSystem: public sp::ecs::System +{ +public: + void update(float delta) override; +}; diff --git a/src/systems/missilesystem.cpp b/src/systems/missilesystem.cpp index 2c93d2a1d8..b0405cc7c9 100644 --- a/src/systems/missilesystem.cpp +++ b/src/systems/missilesystem.cpp @@ -115,21 +115,6 @@ void MissileSystem::update(float delta) explode(entity, {}, deot); } } - - if (game_server) { - // TODO: Not really part of missile - for(auto [entity, lifetime] : sp::ecs::Query()) { - lifetime.lifetime -= delta; - if (lifetime.lifetime <= 0.0f) { - if (entity.hasComponent()) { - if (auto eot = entity.getComponent()) { - explode(entity, {}, *eot); - } - } - entity.destroy(); - } - } - } } void MissileSystem::collision(sp::ecs::Entity a, sp::ecs::Entity b, float force) @@ -166,7 +151,16 @@ void MissileSystem::explode(sp::ecs::Entity source, sp::ecs::Entity target, Expl if (eot.blast_range > 100.0f || !target) { DamageSystem::damageArea(transform->getPosition(), eot.blast_range, eot.damage_at_edge, eot.damage_at_center, info, eot.blast_range / 2); } else { - DamageSystem::applyDamage(target, eot.damage_at_center, info); + if (eot.full_damage_after > 0.0f){ + auto lifetime = source.getComponent(); + if (lifetime->alive_for > eot.full_damage_after){ + DamageSystem::applyDamage(target, eot.damage_at_center, info); + } else { + DamageSystem::applyDamage(target, eot.damage_at_center * (lifetime->alive_for / eot.full_damage_after), info); + } + } else { + DamageSystem::applyDamage(target, eot.damage_at_center, info); + } } auto e = sp::ecs::Entity::create(); @@ -293,6 +287,7 @@ void MissileSystem::spawnProjectile(sp::ecs::Entity source, MissileTubes::MountP mc.damage_at_edge = 10.0f * category_modifier; mc.blast_range = 20.0f * category_modifier; mc.explosion_sfx = "sfx/explosion.wav"; + mc.full_damage_after = 1000.0f / (mwd.speed / category_modifier); // Full damage after 1U missile.addComponent(0.1f, 0.0f, 0.0f); } break; @@ -350,8 +345,10 @@ void MissileSystem::spawnProjectile(sp::ecs::Entity source, MissileTubes::MountP cpe.life_time = 10.0f; } - if (tube.type_loaded != MW_Mine) - missile.addComponent().lifetime = mwd.lifetime * category_modifier; + if (tube.type_loaded != MW_Mine){ + auto& lifetime = missile.addComponent(); + lifetime.maximum = mwd.lifetime * category_modifier; + } if (tube.type_loaded != MW_Mine) { auto& dbad = missile.addComponent(); diff --git a/src/systems/missilesystem.h b/src/systems/missilesystem.h index 634a35fc15..520caed6ae 100644 --- a/src/systems/missilesystem.h +++ b/src/systems/missilesystem.h @@ -23,8 +23,8 @@ class MissileSystem static void startUnload(sp::ecs::Entity source, MissileTubes::MountPoint& tube); static void fire(sp::ecs::Entity source, MissileTubes::MountPoint& tube, float target_angle, sp::ecs::Entity target); static float calculateFiringSolution(sp::ecs::Entity source, const MissileTubes::MountPoint& tube, sp::ecs::Entity target); + static void explode(sp::ecs::Entity source, sp::ecs::Entity target, ExplodeOnTouch& eot); private: - static void explode(sp::ecs::Entity source, sp::ecs::Entity target, ExplodeOnTouch& eot); static void spawnProjectile(sp::ecs::Entity source, MissileTubes::MountPoint& tube, float angle, sp::ecs::Entity target); }; diff --git a/src/systems/probe.cpp b/src/systems/probe.cpp index 8eb69984e4..c35278d752 100644 --- a/src/systems/probe.cpp +++ b/src/systems/probe.cpp @@ -26,7 +26,7 @@ sp::ecs::Entity ProbeSystem::launch(sp::ecs::Entity ship, glm::vec2 target) auto probe = sp::ecs::Entity::create(); probe.addComponent(*ship_transform); probe.addComponent().callsign = probe.toString().split(":", 1)[0] + "P"; - probe.addComponent().lifetime = 600.0f; // 600 sec., 10 min. + probe.addComponent().maximum = 600.0f; // 600 sec., 10 min. auto& hull = probe.addComponent(); hull.current = hull.max = 1;