diff --git a/CMakeLists.txt b/CMakeLists.txt index ddb7430e31..22ab05d215 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/script.cpp b/src/script.cpp index 13f587c1ac..4400af443a 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; update the script docs when fully implemented + 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->commandCombatManeuverStrafe(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; update the script docs when fully implemented + 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; update the script docs when fully implemented + 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; update the script docs when fully implemented + 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; update the script docs when fully implemented + if (auto player_control = ship.getComponent()) + player_control->alert_level = level; } static void luaStartThread(sp::script::Callback callback) @@ -1576,35 +1604,37 @@ bool setupScriptEnvironment(sp::script::Environment& env) /// void commandCombatManeuverBoost(entity ship, number amount) /// Triggers a combat maneuver boost for the given ship. /// amount is a value from 0.0 to 1.0. - /// This command is implemented only for the local player ship and has no effect on other ships. /// This is equivalent to pushing the Helms screen's combat maneuver control forward. /// Example: /// commandCombatManeuverBoost(getPlayerShip(-1), 1.0) -- full combat boost forward 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); /// void commandLaunchProbe(entity ship, number x, number y) /// Launches a scan probe from the given ship toward the given coordinates. - /// This command is only implemented for the local player ship and has no effect on other ships. /// This is equivalent to clicking the Relay screen's launch probe button and then clicking a location. /// Example: /// commandLaunchProbe(getPlayerShip(-1), 30000, 10000) env.setGlobal("commandLaunchProbe", &luaCommandLaunchProbe); /// void commandSetScienceLink(entity ship, entity probe) /// Links the science station of the given ship to the given scan probe for extended radar range. - /// This command is only implemented for the local player ship and has no effect on other ships. /// This is equivalent to selecting a probe on the Relay screen and then clicking the link to science button. /// Example: /// commandSetScienceLink(getPlayerShip(-1), launched_probe) -- link the probe assigned to launched_probe env.setGlobal("commandSetScienceLink", &luaCommandSetScienceLink); /// void commandClearScienceLink(entity ship) /// Clears the science station's link to a scan probe for the given ship. - /// This command is only implemented for the local player ship and has no effect on other ships. /// This is equivalent to selecting the linked probe on the Relay screen and then clicking the link to science button. /// Example: /// commandClearScienceLink(getPlayerShip(-1)) -- clear any science link on this ship env.setGlobal("commandClearScienceLink", &luaCommandClearScienceLink); /// void commandSetAlertLevel(entity ship, string level) /// Sets the alert level for the given ship. See EAlertLevel for valid values. - /// This command is only implemented for the local player ship and has no effect on other ships. /// This is equivalent to clicking the Relay screen's alert level button and then selecting a level. /// Example: /// commandSetAlertLevel(getPlayerShip(-1), "RED ALERT") -- set red alert 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); +};