From 6a084e95d7f2fdeff4c1e53192ff4c470cd00f55 Mon Sep 17 00:00:00 2001 From: Oznogon Date: Fri, 17 Apr 2026 08:21:06 -0700 Subject: [PATCH 1/4] Move probe launch logic to ProbeSystem::launch() Move scan probe launch logic from PlayerInfo to a new ProbeSystem::launch() function so it can be reused by the script bind. --- CMakeLists.txt | 2 ++ src/playerInfo.cpp | 45 +++--------------------- src/systems/probe.cpp | 79 +++++++++++++++++++++++++++++++++++++++++++ src/systems/probe.h | 13 +++++++ 4 files changed, 98 insertions(+), 41 deletions(-) create mode 100644 src/systems/probe.cpp create mode 100644 src/systems/probe.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d3fd6b1fb3..a2a122e697 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -404,6 +404,8 @@ set(MAIN_SOURCES src/systems/damage.cpp src/systems/selfdestruct.h src/systems/selfdestruct.cpp + src/systems/probe.h + src/systems/probe.cpp src/systems/pickup.h src/systems/pickup.cpp src/systems/basicmovement.h diff --git a/src/playerInfo.cpp b/src/playerInfo.cpp index 54ef190b6d..8330eee7c5 100644 --- a/src/playerInfo.cpp +++ b/src/playerInfo.cpp @@ -56,6 +56,7 @@ #include "systems/docking.h" #include "systems/missilesystem.h" #include "systems/selfdestruct.h" +#include "systems/probe.h" #include "systems/comms.h" #include "systems/scanning.h" @@ -947,48 +948,10 @@ void PlayerInfo::onReceiveClientCommand(int32_t client_id, sp::io::DataBuffer& p } break; case CMD_LAUNCH_PROBE: - if (auto spl = ship.getComponent()) { - auto t = ship.getComponent(); - if (t && spl->stock > 0) { - glm::vec2 target{}; - packet >> target; - - auto p = sp::ecs::Entity::create(); - p.addComponent(*t); - p.addComponent().callsign = p.toString().split(":", 1)[0] + "P"; - p.addComponent().lifetime = 60*10; - if (auto faction = ship.getComponent()) - p.addComponent() = *faction; - auto& mt = p.addComponent(); - mt.target = target; - mt.speed = 1000; - p.addComponent().owner = ship; - //TODO: setRadarSignatureInfo(0.0, 0.2, 0.0); - auto& trace = p.addComponent(); - trace.icon = "radar/probe.png"; - trace.min_size = 10.0; - trace.max_size = 10.0; - trace.color = {96, 192, 128, 255}; - trace.flags = RadarTrace::LongRange; - auto& hull = p.addComponent(); - hull.current = hull.max = 1; - p.addComponent(); - auto model = "SensorBuoy/SensorBuoyMKI.model"; - auto idx = irandom(1, 3); - if (idx == 2) model = "SensorBuoy/SensorBuoyMKII.model"; - if (idx == 3) model = "SensorBuoy/SensorBuoyMKIII.model"; - auto& mrc = p.addComponent(); - mrc.mesh.name = model; - mrc.texture.name = "SensorBuoy/SensorBuoyAlbedoAO.png"; - mrc.specular_texture.name = "SensorBuoy/SensorBuoyPBRSpecular.png"; - mrc.scale = 300; - auto& phy = p.addComponent(); - phy.setCircle(sp::Physics::Type::Sensor, 15); - if (spl->on_launch) - LuaConsole::checkResult(spl->on_launch.call(ship, p)); - spl->stock--; - } + glm::vec2 target{}; + packet >> target; + ProbeSystem::launch(ship, target); } break; case CMD_SET_ALERT_LEVEL:{ diff --git a/src/systems/probe.cpp b/src/systems/probe.cpp new file mode 100644 index 0000000000..0103b8eab9 --- /dev/null +++ b/src/systems/probe.cpp @@ -0,0 +1,79 @@ +#include "systems/probe.h" +#include "random.h" + +#include "components/probe.h" +#include "components/radar.h" +#include "components/moveto.h" +#include "components/lifetime.h" +#include "components/rendering.h" +#include "components/name.h" +#include "components/faction.h" +#include "components/hull.h" +#include "components/collision.h" + +#include "menus/luaConsole.h" + +sp::ecs::Entity ProbeSystem::launch(sp::ecs::Entity ship, glm::vec2 target) +{ + // Return an empty entity early if the ship lacks a probe launcher, probes, + // or a transform. + auto probe_launcher = ship.getComponent(); + if (!probe_launcher) return {}; + auto ship_transform = ship.getComponent(); + if (!ship_transform || probe_launcher->stock <= 0) return {}; + + // Create a probe entity. + 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. + + // Apply the launching ship's faction, if any. + if (auto faction = ship.getComponent()) + probe.addComponent() = *faction; + + // Launch the probe to the target coordintes at 1U/sec. + auto& move_to = probe.addComponent(); + move_to.target = target; + move_to.speed = 1000.0f; + + // Connect the radar link capacity to the launching entity. + probe.addComponent().owner = ship; + // Share short-range radar with allies. + probe.addComponent(); + + // Decorate the probe on radar. + auto& trace = probe.addComponent(); + trace.icon = "radar/probe.png"; + trace.min_size = 10.0f; + trace.max_size = 10.0f; + trace.color = {96, 192, 128, 255}; + trace.flags = RadarTrace::LongRange; + + // TODO: setRadarSignatureInfo(0.0, 0.2, 0.0); + + // Assign a random mesh for 3D views. + auto model = "SensorBuoy/SensorBuoyMKI.model"; + auto idx = irandom(1, 3); + if (idx == 2) model = "SensorBuoy/SensorBuoyMKII.model"; + if (idx == 3) model = "SensorBuoy/SensorBuoyMKIII.model"; + auto& mesh_render = probe.addComponent(); + mesh_render.mesh.name = model; + mesh_render.texture.name = "SensorBuoy/SensorBuoyAlbedoAO.png"; + mesh_render.specular_texture.name = "SensorBuoy/SensorBuoyPBRSpecular.png"; + mesh_render.scale = 300.0f; + + // Assign a physics collider. + auto& physics = probe.addComponent(); + physics.setCircle(sp::Physics::Type::Sensor, 15.0f); + + // Fire the on_launch callback if present. + if (probe_launcher->on_launch) + LuaConsole::checkResult(probe_launcher->on_launch.call(ship, probe)); + + // Decrement the launcher's probe stocks. + probe_launcher->stock--; + + // Return the probe entity. + return probe; +} diff --git a/src/systems/probe.h b/src/systems/probe.h new file mode 100644 index 0000000000..78546d46b5 --- /dev/null +++ b/src/systems/probe.h @@ -0,0 +1,13 @@ +#pragma once + +#include "ecs/entity.h" +#include + +class ProbeSystem +{ +public: + // Spawn a probe from an entity with a ScanProbeLauncher, connect the + // probe's AllowRadarLink to the launching entity, and launch it to the + // target coordinates with MoveTo. + static sp::ecs::Entity launch(sp::ecs::Entity ship, glm::vec2 target); +}; From 21affc2e778c87d29d65d07ea45d45095eb28665 Mon Sep 17 00:00:00 2001 From: Oznogon Date: Fri, 17 Apr 2026 08:21:41 -0700 Subject: [PATCH 2/4] Implement Lua command...() function TODOs Implement component changes for Lua globals flagged as TODOs. - commandCombatManeuverBoost() - commandLaunchProbe() - commandSetScienceLink() - commandClearScienceLink() - commandSetAlertLevel() Also: - Add commandCombatManueuverStrafe() --- src/script.cpp | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/src/script.cpp b/src/script.cpp index fdd44b87ef..19cd56fed5 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -32,6 +32,8 @@ #include "components/zone.h" #include "components/shiplog.h" #include "components/selfdestruct.h" +#include "components/radar.h" +#include "systems/probe.h" #include "systems/jumpsystem.h" #include "systems/missilesystem.h" #include "systems/docking.h" @@ -1109,23 +1111,49 @@ static void luaCommandConfirmDestructCode(sp::ecs::Entity ship, int index, int c } static void luaCommandCombatManeuverBoost(sp::ecs::Entity ship, float amount) { if (my_player_info && my_player_info->ship == ship) { my_player_info->commandCombatManeuverBoost(amount); return; } - //TODO + if (auto combat = ship.getComponent()) + combat->boost.request = amount; +} +static void luaCommandCombatManeuverStrafe(sp::ecs::Entity ship, float amount) { + if (my_player_info && my_player_info->ship == ship) { my_player_info->commandCombatManeuverBoost(amount); return; } + if (auto combat = ship.getComponent()) + combat->strafe.request = amount; } static void luaCommandLaunchProbe(sp::ecs::Entity ship, float x, float y) { if (my_player_info && my_player_info->ship == ship) { my_player_info->commandLaunchProbe({x, y}); return; } - //TODO + ProbeSystem::launch(ship, {x, y}); } static void luaCommandSetScienceLink(sp::ecs::Entity ship, sp::ecs::Entity probe) { if (my_player_info && my_player_info->ship == ship) { my_player_info->commandSetScienceLink(probe); return; } - //TODO + if (auto radar_link = ship.getComponent()) + { + auto existing_link = radar_link->linked_entity; + // Run on_link callback if present. + if (radar_link->on_link && probe) + LuaConsole::checkResult(radar_link->on_link.call(ship, probe)); + // Update radar link. + radar_link->linked_entity = probe; + // Run on_unlink callback if this caused an existing link to be broken. + if (radar_link->on_unlink && existing_link) + LuaConsole::checkResult(radar_link->on_unlink.call(ship, existing_link)); + } } static void luaCommandClearScienceLink(sp::ecs::Entity ship) { if (my_player_info && my_player_info->ship == ship) { my_player_info->commandClearScienceLink(); return; } - //TODO + if (auto radar_link = ship.getComponent()) + { + auto existing_link = radar_link->linked_entity; + // Clear radar link. + radar_link->linked_entity = {}; + // Run on_unlink callback if this caused an existing link to be broken. + if (radar_link->on_unlink && existing_link) + LuaConsole::checkResult(radar_link->on_unlink.call(ship, existing_link)); + } } static void luaCommandSetAlertLevel(sp::ecs::Entity ship, AlertLevel level) { if (my_player_info && my_player_info->ship == ship) { my_player_info->commandSetAlertLevel(level); return; } - //TODO + if (auto player_control = ship.getComponent()) + player_control->alert_level = level; } static void luaStartThread(sp::script::Callback callback) @@ -1325,6 +1353,7 @@ bool setupScriptEnvironment(sp::script::Environment& env) env.setGlobal("commandCancelSelfDestruct", &luaCommandCancelSelfDestruct); env.setGlobal("commandConfirmDestructCode", &luaCommandConfirmDestructCode); env.setGlobal("commandCombatManeuverBoost", &luaCommandCombatManeuverBoost); + env.setGlobal("commandCombatManeuverStrafe", &luaCommandCombatManeuverStrafe); env.setGlobal("commandLaunchProbe", &luaCommandLaunchProbe); env.setGlobal("commandSetScienceLink", &luaCommandSetScienceLink); env.setGlobal("commandClearScienceLink", &luaCommandClearScienceLink); From 661582b053bf2e4c6434d8d7dfa596d553596836 Mon Sep 17 00:00:00 2001 From: Oznogon Date: Fri, 17 Apr 2026 08:25:51 -0700 Subject: [PATCH 3/4] Document commandCombatManeuverStrafe() --- src/script.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/script.cpp b/src/script.cpp index 19cd56fed5..00825c67ab 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1353,6 +1353,12 @@ bool setupScriptEnvironment(sp::script::Environment& env) env.setGlobal("commandCancelSelfDestruct", &luaCommandCancelSelfDestruct); env.setGlobal("commandConfirmDestructCode", &luaCommandConfirmDestructCode); env.setGlobal("commandCombatManeuverBoost", &luaCommandCombatManeuverBoost); + /// void commandCombatManeuverStrafe(entity ship, number amount) + /// Triggers a combat maneuver strafe for the given ship. + /// amount is a value from 0.0 to 1.0. + /// This is equivalent to pushing the Helms screen's combat maneuver control left (-1.0) or right (1.0). + /// Example: + /// commandCombatManeuverStrafe(getPlayerShip(-1), 1.0) -- full combat boost right env.setGlobal("commandCombatManeuverStrafe", &luaCommandCombatManeuverStrafe); env.setGlobal("commandLaunchProbe", &luaCommandLaunchProbe); env.setGlobal("commandSetScienceLink", &luaCommandSetScienceLink); From 4b126bcc5c697b220a5ee0a5e0f6b2f86103c5f0 Mon Sep 17 00:00:00 2001 From: Oznogon Date: Fri, 17 Apr 2026 08:35:00 -0700 Subject: [PATCH 4/4] Fix strafe command --- src/script.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/script.cpp b/src/script.cpp index 00825c67ab..83b4956889 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1115,7 +1115,7 @@ static void luaCommandCombatManeuverBoost(sp::ecs::Entity ship, float amount) { combat->boost.request = amount; } static void luaCommandCombatManeuverStrafe(sp::ecs::Entity ship, float amount) { - if (my_player_info && my_player_info->ship == ship) { my_player_info->commandCombatManeuverBoost(amount); return; } + if (my_player_info && my_player_info->ship == ship) { my_player_info->commandCombatManeuverStrafe(amount); return; } if (auto combat = ship.getComponent()) combat->strafe.request = amount; }