From 01e90d86a6cfd5546bad14903d53092747e88d7c Mon Sep 17 00:00:00 2001 From: Daid Date: Wed, 26 Oct 2022 17:05:57 +0200 Subject: [PATCH 001/320] ECS experiment, currently crashes... --- .../rawScannerDataRadarOverlay.cpp | 15 ++++++--------- src/screens/gm/objectCreationView.cpp | 2 +- src/spaceObjects/spaceObject.cpp | 13 +++++++++---- src/spaceObjects/spaceObject.h | 15 ++++++++------- src/spaceObjects/spaceship.cpp | 7 ++++--- 5 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/screenComponents/rawScannerDataRadarOverlay.cpp b/src/screenComponents/rawScannerDataRadarOverlay.cpp index 277f1e03b2..bc77bc642f 100644 --- a/src/screenComponents/rawScannerDataRadarOverlay.cpp +++ b/src/screenComponents/rawScannerDataRadarOverlay.cpp @@ -3,6 +3,7 @@ #include "playerInfo.h" #include "random.h" #include "spaceObjects/playerSpaceship.h" +#include "ecs/query.h" RawScannerDataRadarOverlay::RawScannerDataRadarOverlay(GuiRadarView* owner, string id, float distance) @@ -27,10 +28,10 @@ void RawScannerDataRadarOverlay::onDraw(sp::RenderTarget& renderer) RawRadarSignatureInfo signatures[point_count]; // For each SpaceObject ... - foreach(SpaceObject, obj, space_object_list) + for(auto [entity, signature, obj] : sp::ecs::Query()) { // Don't measure our own ship. - if (obj == my_spaceship) + if (obj == *my_spaceship) continue; // Initialize angle, distance, and scale variables. @@ -65,16 +66,12 @@ void RawScannerDataRadarOverlay::onDraw(sp::RenderTarget& renderer) // Get the object's radar signature. // If the object is a SpaceShip, adjust the signature dynamically based // on its current state and activity. - RawRadarSignatureInfo info; - P ship = obj; - + RawRadarSignatureInfo info = signature; + P ship = P(obj); if (ship) { // Use dynamic signatures for ships. - info = ship->getDynamicRadarSignatureInfo(); - } else { - // Otherwise, use the baseline only. - info = obj->getRadarSignatureInfo(); + info += ship->getDynamicRadarSignatureInfo(); } // For each interval determined by the level of raw data resolution, diff --git a/src/screens/gm/objectCreationView.cpp b/src/screens/gm/objectCreationView.cpp index e16d1eb04c..fa1c99b6f5 100644 --- a/src/screens/gm/objectCreationView.cpp +++ b/src/screens/gm/objectCreationView.cpp @@ -123,7 +123,7 @@ GuiObjectCreationView::GuiObjectCreationView(GuiContainer* owner) setCreateScript("PlayerSpaceship():setFactionId(" + string(faction_selector->getSelectionIndex()) + ")",":setTemplate(\"" + value + "\")"); }); player_ship_listbox->setTextSize(20)->setButtonHeight(30)->setPosition(-20, 20, sp::Alignment::TopRight)->setSize(300, 460); - for (const auto template_name : player_template_names) + for (const auto& template_name : player_template_names) { auto shipTemplate=ShipTemplate::getTemplate(template_name); if (shipTemplate) diff --git a/src/spaceObjects/spaceObject.cpp b/src/spaceObjects/spaceObject.cpp index 4dc8065cca..9b656d755d 100644 --- a/src/spaceObjects/spaceObject.cpp +++ b/src/spaceObjects/spaceObject.cpp @@ -289,6 +289,10 @@ PVector space_object_list; SpaceObject::SpaceObject(float collision_range, string multiplayer_name, float multiplayer_significant_range) : Collisionable(collision_range), MultiplayerObject(multiplayer_name) { + entity = sp::ecs::Entity::create(); + //Add a back reference to the SpaceObject from the ECS, we need this until we fully phased out the OOP style code (if ever...) + entity.addComponent(this); + object_radius = collision_range; space_object_list.push_back(this); faction_id = 0; @@ -303,17 +307,18 @@ SpaceObject::SpaceObject(float collision_range, string multiplayer_name, float m registerMemberReplication(&object_description.friend_of_foe_identified); registerMemberReplication(&object_description.simple_scan); registerMemberReplication(&object_description.full_scan); - registerMemberReplication(&radar_signature.gravity); - registerMemberReplication(&radar_signature.electrical); - registerMemberReplication(&radar_signature.biological); +#warning "TODO: Replication of entity and radar signature" + //registerMemberReplication(&radar_signature.gravity); + //registerMemberReplication(&radar_signature.electrical); + //registerMemberReplication(&radar_signature.biological); registerMemberReplication(&scanning_complexity_value); registerMemberReplication(&scanning_depth_value); registerCollisionableReplication(multiplayer_significant_range); } -//due to a suspected compiler bug this deconstructor needs to be explicitly defined SpaceObject::~SpaceObject() { + entity.destroy(); } void SpaceObject::draw3D() diff --git a/src/spaceObjects/spaceObject.h b/src/spaceObjects/spaceObject.h index 2768ab3fb4..6b0dd6a6a3 100644 --- a/src/spaceObjects/spaceObject.h +++ b/src/spaceObjects/spaceObject.h @@ -9,6 +9,7 @@ #include "factionInfo.h" #include "shipTemplate.h" #include "graphics/renderTarget.h" +#include "ecs/entity.h" #include @@ -110,7 +111,6 @@ class SpaceObject : public Collisionable, public MultiplayerObject string simple_scan; string full_scan; } object_description; - RawRadarSignatureInfo radar_signature; /*! * Scan state per faction. Implementation wise, this vector is resized when @@ -121,6 +121,7 @@ class SpaceObject : public Collisionable, public MultiplayerObject */ std::vector scanned_by_faction; public: + sp::ecs::Entity entity; string comms_script_name; ScriptSimpleCallback comms_script_callback; @@ -136,12 +137,12 @@ class SpaceObject : public Collisionable, public MultiplayerObject bool hasWeight() { return has_weight; } - // Return the object's raw radar signature. The default signature is 0,0,0. - virtual RawRadarSignatureInfo getRadarSignatureInfo() { return radar_signature; } - void setRadarSignatureInfo(float grav, float elec, float bio) { radar_signature = RawRadarSignatureInfo(grav, elec, bio); } - float getRadarSignatureGravity() { return radar_signature.gravity; } - float getRadarSignatureElectrical() { return radar_signature.electrical; } - float getRadarSignatureBiological() { return radar_signature.biological; } + void setRadarSignatureInfo(float grav, float elec, float bio) { + entity.addComponent(grav, elec, bio); + } + float getRadarSignatureGravity() { auto radar_signature = entity.getComponent(); if (!radar_signature) return 0.0; return radar_signature->gravity; } + float getRadarSignatureElectrical() { auto radar_signature = entity.getComponent(); if (!radar_signature) return 0.0; return radar_signature->electrical; } + float getRadarSignatureBiological() { auto radar_signature = entity.getComponent(); if (!radar_signature) return 0.0; return radar_signature->biological; } virtual ERadarLayer getRadarLayer() const { return ERadarLayer::Default; } string getDescription(EScannedState state) diff --git a/src/spaceObjects/spaceship.cpp b/src/spaceObjects/spaceship.cpp index e1d3dd9c72..5c1967e83c 100644 --- a/src/spaceObjects/spaceship.cpp +++ b/src/spaceObjects/spaceship.cpp @@ -448,9 +448,10 @@ RawRadarSignatureInfo SpaceShip::getDynamicRadarSignatureInfo() } // Update the signature by adding the delta to its baseline. - RawRadarSignatureInfo info = getRadarSignatureInfo(); - info += signature_delta; - return info; + auto rsi = entity.getComponent(); + if (rsi) + signature_delta += *rsi; + return signature_delta; } void SpaceShip::drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) From dc202c3925dde9149a139a0b68782048629f499c Mon Sep 17 00:00:00 2001 From: Daid Date: Thu, 27 Oct 2022 09:42:01 +0200 Subject: [PATCH 002/320] Turn the dynamic ship radar signature into an ECS component. --- src/screenComponents/rawScannerDataRadarOverlay.cpp | 10 +++++----- src/spaceObjects/spaceObject.h | 7 +++++++ src/spaceObjects/spaceship.cpp | 11 +++++------ src/spaceObjects/spaceship.h | 8 ++++---- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/screenComponents/rawScannerDataRadarOverlay.cpp b/src/screenComponents/rawScannerDataRadarOverlay.cpp index bc77bc642f..dbf229324c 100644 --- a/src/screenComponents/rawScannerDataRadarOverlay.cpp +++ b/src/screenComponents/rawScannerDataRadarOverlay.cpp @@ -28,7 +28,7 @@ void RawScannerDataRadarOverlay::onDraw(sp::RenderTarget& renderer) RawRadarSignatureInfo signatures[point_count]; // For each SpaceObject ... - for(auto [entity, signature, obj] : sp::ecs::Query()) + for(auto [entity, signature, dynamic_signature, obj] : sp::ecs::Query, SpaceObject*>()) { // Don't measure our own ship. if (obj == *my_spaceship) @@ -67,11 +67,11 @@ void RawScannerDataRadarOverlay::onDraw(sp::RenderTarget& renderer) // If the object is a SpaceShip, adjust the signature dynamically based // on its current state and activity. RawRadarSignatureInfo info = signature; - P ship = P(obj); - if (ship) + if (dynamic_signature) { - // Use dynamic signatures for ships. - info += ship->getDynamicRadarSignatureInfo(); + info.gravity += dynamic_signature->gravity; + info.electrical += dynamic_signature->electrical; + info.biological += dynamic_signature->biological; } // For each interval determined by the level of raw data resolution, diff --git a/src/spaceObjects/spaceObject.h b/src/spaceObjects/spaceObject.h index 6b0dd6a6a3..f6b9d5b91a 100644 --- a/src/spaceObjects/spaceObject.h +++ b/src/spaceObjects/spaceObject.h @@ -77,6 +77,13 @@ class RawRadarSignatureInfo return RawRadarSignatureInfo(gravity * f, electrical * f, biological * f); } }; +class DynamicRadarSignatureInfo +{ +public: + float gravity; + float electrical; + float biological; +}; enum EScannedState { diff --git a/src/spaceObjects/spaceship.cpp b/src/spaceObjects/spaceship.cpp index 5c1967e83c..f020614350 100644 --- a/src/spaceObjects/spaceship.cpp +++ b/src/spaceObjects/spaceship.cpp @@ -383,11 +383,11 @@ void SpaceShip::draw3DTransparent() } } -RawRadarSignatureInfo SpaceShip::getDynamicRadarSignatureInfo() +void SpaceShip::updateDynamicRadarSignature() { // Adjust radar_signature dynamically based on current state and activity. // radar_signature becomes the ship's baseline radar signature. - RawRadarSignatureInfo signature_delta; + DynamicRadarSignatureInfo signature_delta; // For each ship system ... for(int n = 0; n < SYS_COUNT; n++) @@ -448,10 +448,7 @@ RawRadarSignatureInfo SpaceShip::getDynamicRadarSignatureInfo() } // Update the signature by adding the delta to its baseline. - auto rsi = entity.getComponent(); - if (rsi) - signature_delta += *rsi; - return signature_delta; + entity.addComponent(signature_delta); } void SpaceShip::drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) @@ -926,6 +923,8 @@ void SpaceShip::update(float delta) model_info.warp_scale = (10.0f - jump_delay) / 10.0f; else model_info.warp_scale = 0.f; + + updateDynamicRadarSignature(); } float SpaceShip::getShieldRechargeRate(int shield_index) diff --git a/src/spaceObjects/spaceship.h b/src/spaceObjects/spaceship.h index d517aca659..ea1455963a 100644 --- a/src/spaceObjects/spaceship.h +++ b/src/spaceObjects/spaceship.h @@ -221,10 +221,10 @@ class SpaceShip : public ShipTemplateBasedObject * Get this ship's radar signature dynamically modified by the state of its * systems and current activity. */ - virtual RawRadarSignatureInfo getDynamicRadarSignatureInfo(); - float getDynamicRadarSignatureGravity() { return getDynamicRadarSignatureInfo().gravity; } - float getDynamicRadarSignatureElectrical() { return getDynamicRadarSignatureInfo().electrical; } - float getDynamicRadarSignatureBiological() { return getDynamicRadarSignatureInfo().biological; } + void updateDynamicRadarSignature(); + float getDynamicRadarSignatureGravity() { auto radar_signature = entity.getComponent(); if (!radar_signature) return getRadarSignatureGravity(); return radar_signature->gravity + getRadarSignatureGravity(); } + float getDynamicRadarSignatureElectrical() { auto radar_signature = entity.getComponent(); if (!radar_signature) return getRadarSignatureElectrical(); return radar_signature->electrical + getRadarSignatureElectrical(); } + float getDynamicRadarSignatureBiological() { auto radar_signature = entity.getComponent(); if (!radar_signature) return getRadarSignatureBiological(); return radar_signature->biological + getRadarSignatureBiological(); } /*! * Draw this ship on the radar. From 24be52f26e27a4812a59a9c9a3b2071d6371de73 Mon Sep 17 00:00:00 2001 From: Daid Date: Thu, 27 Oct 2022 16:46:44 +0200 Subject: [PATCH 003/320] Add untested component replication code, quick&dirty --- src/main.cpp | 1 + src/spaceObjects/spaceObject.cpp | 13 ++++++------- src/spaceObjects/spaceObject.h | 5 ++++- src/spaceObjects/spaceship.cpp | 3 ++- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 56d489262d..35d8b4d823 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -118,6 +118,7 @@ int main(int argc, char** argv) free(exe_dir); } #endif + MultiplayerECSComponentReplication rrsir; #ifdef DEBUG Logging::setLogLevel(LOGLEVEL_DEBUG); diff --git a/src/spaceObjects/spaceObject.cpp b/src/spaceObjects/spaceObject.cpp index 9b656d755d..dbdaf55f72 100644 --- a/src/spaceObjects/spaceObject.cpp +++ b/src/spaceObjects/spaceObject.cpp @@ -289,9 +289,11 @@ PVector space_object_list; SpaceObject::SpaceObject(float collision_range, string multiplayer_name, float multiplayer_significant_range) : Collisionable(collision_range), MultiplayerObject(multiplayer_name) { - entity = sp::ecs::Entity::create(); - //Add a back reference to the SpaceObject from the ECS, we need this until we fully phased out the OOP style code (if ever...) - entity.addComponent(this); + if (isServer()) { + entity = sp::ecs::Entity::create(); + //Add a back reference to the SpaceObject from the ECS, we need this until we fully phased out the OOP style code (if ever...) + entity.addComponent(this); + } object_radius = collision_range; space_object_list.push_back(this); @@ -307,10 +309,7 @@ SpaceObject::SpaceObject(float collision_range, string multiplayer_name, float m registerMemberReplication(&object_description.friend_of_foe_identified); registerMemberReplication(&object_description.simple_scan); registerMemberReplication(&object_description.full_scan); -#warning "TODO: Replication of entity and radar signature" - //registerMemberReplication(&radar_signature.gravity); - //registerMemberReplication(&radar_signature.electrical); - //registerMemberReplication(&radar_signature.biological); + registerMemberReplication(&entity); registerMemberReplication(&scanning_complexity_value); registerMemberReplication(&scanning_depth_value); registerCollisionableReplication(multiplayer_significant_range); diff --git a/src/spaceObjects/spaceObject.h b/src/spaceObjects/spaceObject.h index f6b9d5b91a..075a79ca0c 100644 --- a/src/spaceObjects/spaceObject.h +++ b/src/spaceObjects/spaceObject.h @@ -77,6 +77,9 @@ class RawRadarSignatureInfo return RawRadarSignatureInfo(gravity * f, electrical * f, biological * f); } }; +static inline sp::io::DataBuffer& operator << (sp::io::DataBuffer& packet, const RawRadarSignatureInfo& rrs) { return packet << rrs.gravity << rrs.electrical << rrs.biological; } +static inline sp::io::DataBuffer& operator >> (sp::io::DataBuffer& packet, RawRadarSignatureInfo& rrs) { packet >> rrs.gravity >> rrs.electrical >> rrs.biological; return packet; } + class DynamicRadarSignatureInfo { public: @@ -128,7 +131,7 @@ class SpaceObject : public Collisionable, public MultiplayerObject */ std::vector scanned_by_faction; public: - sp::ecs::Entity entity; + sp::ecs::Entity entity; //NOTE: On clients be careful, the Entity+components might be destroyed before the SpaceObject! Always check if this exists before using it. string comms_script_name; ScriptSimpleCallback comms_script_callback; diff --git a/src/spaceObjects/spaceship.cpp b/src/spaceObjects/spaceship.cpp index f020614350..42d6f985a0 100644 --- a/src/spaceObjects/spaceship.cpp +++ b/src/spaceObjects/spaceship.cpp @@ -448,7 +448,8 @@ void SpaceShip::updateDynamicRadarSignature() } // Update the signature by adding the delta to its baseline. - entity.addComponent(signature_delta); + if (entity) + entity.addComponent(signature_delta); } void SpaceShip::drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) From 1e757e94ce22fe6a0f239b6066f2c19fc7c72218 Mon Sep 17 00:00:00 2001 From: Daid Date: Thu, 27 Oct 2022 23:11:54 +0200 Subject: [PATCH 004/320] WIP --- src/gameGlobalInfo.cpp | 8 ++++++++ src/spaceObjects/spaceObject.cpp | 2 -- src/spaceObjects/spaceObject.h | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/gameGlobalInfo.cpp b/src/gameGlobalInfo.cpp index 13a659c31a..c55f2e1d7f 100644 --- a/src/gameGlobalInfo.cpp +++ b/src/gameGlobalInfo.cpp @@ -105,6 +105,14 @@ int GameGlobalInfo::insertPlayerShip(P ship) void GameGlobalInfo::update(float delta) { + foreach(SpaceObject, obj, space_object_list) { + if (obj->entity) { + //Add a back reference to the SpaceObject from the ECS, we need this until we fully phased out the OOP style code (if ever...) + // We do this here so this is done for client and server. + obj->entity.addComponent(*obj); + } + } + if (global_message_timeout > 0.0f) { global_message_timeout -= delta; diff --git a/src/spaceObjects/spaceObject.cpp b/src/spaceObjects/spaceObject.cpp index dbdaf55f72..3043ab69f1 100644 --- a/src/spaceObjects/spaceObject.cpp +++ b/src/spaceObjects/spaceObject.cpp @@ -291,8 +291,6 @@ SpaceObject::SpaceObject(float collision_range, string multiplayer_name, float m { if (isServer()) { entity = sp::ecs::Entity::create(); - //Add a back reference to the SpaceObject from the ECS, we need this until we fully phased out the OOP style code (if ever...) - entity.addComponent(this); } object_radius = collision_range; diff --git a/src/spaceObjects/spaceObject.h b/src/spaceObjects/spaceObject.h index 075a79ca0c..a7049a5496 100644 --- a/src/spaceObjects/spaceObject.h +++ b/src/spaceObjects/spaceObject.h @@ -148,7 +148,7 @@ class SpaceObject : public Collisionable, public MultiplayerObject bool hasWeight() { return has_weight; } void setRadarSignatureInfo(float grav, float elec, float bio) { - entity.addComponent(grav, elec, bio); + if (entity) entity.addComponent(grav, elec, bio); } float getRadarSignatureGravity() { auto radar_signature = entity.getComponent(); if (!radar_signature) return 0.0; return radar_signature->gravity; } float getRadarSignatureElectrical() { auto radar_signature = entity.getComponent(); if (!radar_signature) return 0.0; return radar_signature->electrical; } From 8a023e36bc1aaf5a95228acf642852a64cb7f2d2 Mon Sep 17 00:00:00 2001 From: Daid Date: Fri, 28 Oct 2022 16:57:08 +0200 Subject: [PATCH 005/320] Make the multiple ECS replication thing global. --- src/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 35d8b4d823..9a556d39cc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -75,6 +75,8 @@ GUI_REGISTER_LAYOUT("verticalbottom", GuiLayoutVerticalBottom); GUI_REGISTER_LAYOUT("horizontal", GuiLayoutHorizontal); GUI_REGISTER_LAYOUT("horizontalright", GuiLayoutHorizontalRight); +MultiplayerECSComponentReplication rrsir; + int main(int argc, char** argv) { #ifdef __APPLE__ @@ -118,7 +120,6 @@ int main(int argc, char** argv) free(exe_dir); } #endif - MultiplayerECSComponentReplication rrsir; #ifdef DEBUG Logging::setLogLevel(LOGLEVEL_DEBUG); From 486171e89315e4063e81340a45968a386cfdd9ca Mon Sep 17 00:00:00 2001 From: Daid Date: Sat, 29 Oct 2022 18:37:34 +0200 Subject: [PATCH 006/320] Start with converting radar trace icons into an ECS component. --- CMakeLists.txt | 1 + src/components/radar.h | 69 ++++++++++++++++++++++++++++++ src/main.cpp | 4 +- src/screenComponents/radarView.cpp | 13 ++++++ src/spaceObjects/artifact.cpp | 53 +++++++++++------------ src/spaceObjects/artifact.h | 7 +-- src/spaceObjects/spaceObject.h | 44 +------------------ 7 files changed, 112 insertions(+), 79 deletions(-) create mode 100644 src/components/radar.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f3b0b206d0..9c9be0b90b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -353,6 +353,7 @@ set(MAIN_SOURCES src/spaceObjects/zone.cpp src/spaceObjects/spaceshipParts/beamWeapon.cpp src/spaceObjects/spaceshipParts/weaponTube.cpp + src/components/radar.h src/ai/fighterAI.cpp src/ai/ai.cpp src/ai/aiFactory.cpp diff --git a/src/components/radar.h b/src/components/radar.h new file mode 100644 index 0000000000..b0ed7b4665 --- /dev/null +++ b/src/components/radar.h @@ -0,0 +1,69 @@ +#pragma once + +#include "io/dataBuffer.h" + +class RadarTrace +{ +public: + string icon; + float min_size = 8.0; //Size in screen "pixels" + float max_size = 256.0; //Size in screen "pixels" + float radius; // Size in world "units" + glm::u8vec4 color{255,255,255,255}; + bool rotate = true; + + //TODO: color by ffi/faction + + bool operator!=(const RadarTrace& o) + { + return icon != o.icon || min_size != o.min_size || max_size != o.max_size || radius != o.radius || color != o.color || rotate != o.rotate; + } +}; +static inline sp::io::DataBuffer& operator << (sp::io::DataBuffer& packet, const RadarTrace& rt) { return packet << rt.icon << rt.min_size << rt.max_size << rt.radius << rt.color << rt.rotate; } +static inline sp::io::DataBuffer& operator >> (sp::io::DataBuffer& packet, RadarTrace& rt) { return packet >> rt.icon >> rt.min_size >> rt.max_size >> rt.radius >> rt.color >> rt.rotate; } + + +// Radar signature data, used by rawScannerDataOverlay. +class RawRadarSignatureInfo +{ +public: + float gravity; + float electrical; + float biological; + + RawRadarSignatureInfo() + : gravity(0), electrical(0), biological(0) {} + + RawRadarSignatureInfo(float gravity, float electrical, float biological) + : gravity(gravity), electrical(electrical), biological(biological) {} + + RawRadarSignatureInfo& operator+=(const RawRadarSignatureInfo& o) + { + gravity += o.gravity; + electrical += o.electrical; + biological += o.biological; + return *this; + } + + bool operator!=(const RawRadarSignatureInfo& o) + { + return gravity != o.gravity || electrical != o.electrical || biological != o.biological; + } + + RawRadarSignatureInfo operator*(const float f) const + { + return RawRadarSignatureInfo(gravity * f, electrical * f, biological * f); + } +}; +static inline sp::io::DataBuffer& operator << (sp::io::DataBuffer& packet, const RawRadarSignatureInfo& rrs) { return packet << rrs.gravity << rrs.electrical << rrs.biological; } +static inline sp::io::DataBuffer& operator >> (sp::io::DataBuffer& packet, RawRadarSignatureInfo& rrs) { packet >> rrs.gravity >> rrs.electrical >> rrs.biological; return packet; } + +// Dynamic radar signature is added to entities that +// generate additional radar signature info by live systems (impulse engine, etc...) +class DynamicRadarSignatureInfo +{ +public: + float gravity; + float electrical; + float biological; +}; diff --git a/src/main.cpp b/src/main.cpp index 9a556d39cc..d0d111f486 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,6 +35,7 @@ #include "networkRecorder.h" #include "tutorialGame.h" #include "windowManager.h" +#include "ecs/multiplayer.h" #include "graphics/opengl.h" @@ -75,7 +76,8 @@ GUI_REGISTER_LAYOUT("verticalbottom", GuiLayoutVerticalBottom); GUI_REGISTER_LAYOUT("horizontal", GuiLayoutHorizontal); GUI_REGISTER_LAYOUT("horizontalright", GuiLayoutHorizontalRight); -MultiplayerECSComponentReplication rrsir; +sp::ecs::ComponentReplication cr_RawRadarSignatureInfo; +sp::ecs::ComponentReplication cr_RadarTrace; int main(int argc, char** argv) { diff --git a/src/screenComponents/radarView.cpp b/src/screenComponents/radarView.cpp index 9565b611be..4825377002 100644 --- a/src/screenComponents/radarView.cpp +++ b/src/screenComponents/radarView.cpp @@ -1,5 +1,6 @@ #include +#include "ecs/query.h" #include "main.h" #include "gameGlobalInfo.h" #include "spaceObjects/nebula.h" @@ -683,6 +684,18 @@ void GuiRadarView::drawObjects(sp::RenderTarget& renderer) { draw_object(obj); } + + for(auto [entity, trace, obj] : sp::ecs::Query()) { + auto object_position_on_screen = worldToScreen(obj->getPosition()); + + auto size = trace.radius * scale * 2.0f; + size = std::clamp(size, trace.min_size, trace.max_size); + + if (trace.rotate) + renderer.drawRotatedSprite(trace.icon, object_position_on_screen, size, obj->getRotation() - view_rotation, trace.color); + else + renderer.drawSprite(trace.icon, object_position_on_screen, size, trace.color); + } if (my_spaceship) { diff --git a/src/spaceObjects/artifact.cpp b/src/spaceObjects/artifact.cpp index 745dc96740..fadf920a67 100644 --- a/src/spaceObjects/artifact.cpp +++ b/src/spaceObjects/artifact.cpp @@ -61,19 +61,19 @@ Artifact::Artifact() current_model_data_name("artifact" + string(irandom(1, 8))), model_data_name(current_model_data_name), artifact_spin(0.0f), - allow_pickup(false), - radar_trace_icon("radar/blip.png"), - radar_trace_scale(0), - radar_trace_color(glm::u8vec4(255, 255, 255, 255)) + allow_pickup(false) { setRotation(random(0, 360)); model_info.setData(current_model_data_name); registerMemberReplication(&model_data_name); registerMemberReplication(&artifact_spin); - registerMemberReplication(&radar_trace_icon); - registerMemberReplication(&radar_trace_scale); - registerMemberReplication(&radar_trace_color); + + if (entity) { + auto& trace = entity.addComponent(); + trace.radius = getRadius(); + trace.icon = "radar/blip.png"; + } } void Artifact::update(float delta) @@ -85,26 +85,6 @@ void Artifact::update(float delta) } } -void Artifact::drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) -{ - // radar trace scaling, via script or automatically - float size; - if (radar_trace_scale > 0) - { - if (long_range) - size = radar_trace_scale * 0.7f; - else - size = radar_trace_scale; - } - else - { - size = getRadius() * scale / 16; - if (size < 0.2f) - size = 0.2f; - } - renderer.drawRotatedSprite(radar_trace_icon, position, size * 32.0f, getRotation() - rotation, radar_trace_color); -} - void Artifact::collide(Collisionable* target, float force) { // Handle collisions on the server only. @@ -172,12 +152,27 @@ void Artifact::setSpin(float spin) void Artifact::setRadarTraceIcon(string icon) { - radar_trace_icon = "radar/" + icon; + auto trace = entity.getComponent(); + if (trace) { + trace->icon = "radar/" + icon; + } } void Artifact::setRadarTraceScale(float scale) { - radar_trace_scale = scale; + auto trace = entity.getComponent(); + if (trace) { + trace->min_size = scale * 32.0f; + trace->max_size = scale * 32.0f; + } +} + +void Artifact::setRadarTraceColor(int r, int g, int b) +{ + auto trace = entity.getComponent(); + if (trace) { + trace->color = glm::u8vec4(r, g, b, 255); + } } void Artifact::onPickUp(ScriptSimpleCallback callback) diff --git a/src/spaceObjects/artifact.h b/src/spaceObjects/artifact.h index f508cf77fd..f623dc0721 100644 --- a/src/spaceObjects/artifact.h +++ b/src/spaceObjects/artifact.h @@ -14,16 +14,11 @@ class Artifact : public SpaceObject, public Updatable ScriptSimpleCallback on_collision_callback; ScriptSimpleCallback on_player_collision_callback; - string radar_trace_icon; - float radar_trace_scale; - glm::u8vec4 radar_trace_color; public: Artifact(); virtual void update(float delta) override; - virtual void drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) override; - virtual void collide(Collisionable* target, float force) override; void setModel(string name); @@ -33,7 +28,7 @@ class Artifact : public SpaceObject, public Updatable void setRadarTraceIcon(string icon); void setRadarTraceScale(float scale); - void setRadarTraceColor(int r, int g, int b) { radar_trace_color = glm::u8vec4(r, g, b, 255); } + void setRadarTraceColor(int r, int g, int b); void onPickUp(ScriptSimpleCallback callback); // Consistent naming workaround diff --git a/src/spaceObjects/spaceObject.h b/src/spaceObjects/spaceObject.h index a7049a5496..dfbb38d7a8 100644 --- a/src/spaceObjects/spaceObject.h +++ b/src/spaceObjects/spaceObject.h @@ -10,6 +10,7 @@ #include "shipTemplate.h" #include "graphics/renderTarget.h" #include "ecs/entity.h" +#include "components/radar.h" #include @@ -45,49 +46,6 @@ class DamageInfo {} }; -// Radar signature data, used by rawScannerDataOverlay. -class RawRadarSignatureInfo -{ -public: - float gravity; - float electrical; - float biological; - - RawRadarSignatureInfo() - : gravity(0), electrical(0), biological(0) {} - - RawRadarSignatureInfo(float gravity, float electrical, float biological) - : gravity(gravity), electrical(electrical), biological(biological) {} - - RawRadarSignatureInfo& operator+=(const RawRadarSignatureInfo& o) - { - gravity += o.gravity; - electrical += o.electrical; - biological += o.biological; - return *this; - } - - bool operator!=(const RawRadarSignatureInfo& o) - { - return gravity != o.gravity || electrical != o.electrical || biological != o.biological; - } - - RawRadarSignatureInfo operator*(const float f) const - { - return RawRadarSignatureInfo(gravity * f, electrical * f, biological * f); - } -}; -static inline sp::io::DataBuffer& operator << (sp::io::DataBuffer& packet, const RawRadarSignatureInfo& rrs) { return packet << rrs.gravity << rrs.electrical << rrs.biological; } -static inline sp::io::DataBuffer& operator >> (sp::io::DataBuffer& packet, RawRadarSignatureInfo& rrs) { packet >> rrs.gravity >> rrs.electrical >> rrs.biological; return packet; } - -class DynamicRadarSignatureInfo -{ -public: - float gravity; - float electrical; - float biological; -}; - enum EScannedState { SS_NotScanned, From 18dfa9e33d2954de875174e4c5343039a164ed7b Mon Sep 17 00:00:00 2001 From: Daid Date: Thu, 3 Nov 2022 15:57:50 +0100 Subject: [PATCH 007/320] Start converting collision/physics handling into ECS --- src/ai/ai.cpp | 29 +++-- src/ai/evasionAI.cpp | 9 +- src/gameGlobalInfo.cpp | 18 +-- src/modelData.cpp | 7 +- src/screenComponents/dockingButton.cpp | 9 +- src/screenComponents/radarView.cpp | 8 +- src/screenComponents/targetsContainer.cpp | 9 +- src/screens/gm/gameMasterScreen.cpp | 22 ++-- src/spaceObjects/artifact.cpp | 4 +- src/spaceObjects/artifact.h | 2 +- src/spaceObjects/asteroid.cpp | 4 +- src/spaceObjects/asteroid.h | 2 +- src/spaceObjects/beamEffect.cpp | 4 +- src/spaceObjects/blackHole.cpp | 4 +- src/spaceObjects/blackHole.h | 2 +- src/spaceObjects/electricExplosionEffect.cpp | 3 +- src/spaceObjects/explosionEffect.cpp | 3 +- src/spaceObjects/mine.cpp | 14 ++- src/spaceObjects/mine.h | 2 +- src/spaceObjects/missiles/hvli.cpp | 4 +- src/spaceObjects/missiles/missileWeapon.cpp | 24 ++-- src/spaceObjects/missiles/missileWeapon.h | 2 +- src/spaceObjects/nebula.cpp | 5 +- src/spaceObjects/planet.cpp | 7 +- src/spaceObjects/planet.h | 2 +- src/spaceObjects/shipTemplateBasedObject.cpp | 3 +- src/spaceObjects/spaceObject.cpp | 117 +++++++++++++++---- src/spaceObjects/spaceObject.h | 16 ++- src/spaceObjects/spaceship.cpp | 42 ++++--- src/spaceObjects/spaceship.h | 2 +- src/spaceObjects/supplyDrop.cpp | 4 +- src/spaceObjects/supplyDrop.h | 2 +- src/spaceObjects/wormHole.cpp | 6 +- src/spaceObjects/wormHole.h | 2 +- src/spaceObjects/zone.cpp | 3 +- src/threatLevelEstimate.cpp | 11 +- 36 files changed, 269 insertions(+), 138 deletions(-) diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp index 37a9fbefea..2b388248ac 100644 --- a/src/ai/ai.cpp +++ b/src/ai/ai.cpp @@ -4,6 +4,7 @@ #include "ai/ai.h" #include "ai/aiFactory.h" #include "random.h" +#include "systems/collision.h" REGISTER_SHIP_AI(ShipAI, "default"); @@ -656,12 +657,13 @@ void ShipAI::flyFormation(P target, glm::vec2 offset) P ShipAI::findBestTarget(glm::vec2 position, float radius) { float target_score = 0.0; - PVector objectList = CollisionManager::queryArea(position - glm::vec2(radius, radius), position + glm::vec2(radius, radius)); P target; auto owner_position = owner->getPosition(); - foreach(Collisionable, obj, objectList) + for(auto entity : sp::CollisionSystem::queryArea(position - glm::vec2(radius, radius), position + glm::vec2(radius, radius))) { - P space_object = obj; + auto ptr = entity.getComponent(); + if (!ptr || !*ptr) continue; + P space_object = *ptr; if (!space_object || !space_object->canBeTargetedBy(owner) || !owner->isEnemy(space_object) || space_object == target) continue; if (space_object->canHideInNebula() && Nebula::blockedByNebula(owner_position, space_object->getPosition(), owner->getShortRangeRadarRange())) @@ -752,10 +754,11 @@ float ShipAI::calculateFiringSolution(P target, int tube_index) const float search_angle = 5.0; // Verify if missle can be fired safely - PVector objectList = CollisionManager::queryArea(owner->getPosition() - glm::vec2(search_distance, search_distance), owner->getPosition() + glm::vec2(search_distance, search_distance)); - foreach(Collisionable, c, objectList) + for(auto entity : sp::CollisionSystem::queryArea(owner->getPosition() - glm::vec2(search_distance, search_distance), owner->getPosition() + glm::vec2(search_distance, search_distance))) { - P obj = c; + auto ptr = entity.getComponent(); + if (!ptr || !*ptr) continue; + P obj = *ptr; if (obj && !obj->isEnemy(owner) && (P(obj) || P(obj))) { // Ship in research triangle @@ -798,10 +801,11 @@ float ShipAI::calculateFiringSolution(P target, int tube_index) float safety_radius = 1100; if (glm::length2(target_position - owner->getPosition()) < safety_radius*safety_radius) return std::numeric_limits::infinity(); - PVector object_list = CollisionManager::queryArea(target->getPosition() - glm::vec2(safety_radius, safety_radius), target->getPosition() + glm::vec2(safety_radius, safety_radius)); - foreach(Collisionable, c, object_list) + for(auto entity : sp::CollisionSystem::queryArea(target->getPosition() - glm::vec2(safety_radius, safety_radius), target->getPosition() + glm::vec2(safety_radius, safety_radius))) { - P obj = c; + auto ptr = entity.getComponent(); + if (!ptr || !*ptr) continue; + P obj = *ptr; if (obj && !obj->isEnemy(owner) && (P(obj) || P(obj))) { if (glm::length(obj->getPosition() - owner->getPosition()) < safety_radius - obj->getRadius()) @@ -821,12 +825,13 @@ P ShipAI::findBestMissileRestockTarget(glm::vec2 position, float ra // Check each object within the given radius. If it's friendly, we can dock // to it, and it can restock our missiles, then select it. float target_score = 0.0; - PVector objectList = CollisionManager::queryArea(position - glm::vec2(radius, radius), position + glm::vec2(radius, radius)); P target; auto owner_position = owner->getPosition(); - foreach(Collisionable, obj, objectList) + for(auto entity : sp::CollisionSystem::queryArea(position - glm::vec2(radius, radius), position + glm::vec2(radius, radius))) { - P space_object = obj; + auto ptr = entity.getComponent(); + if (!ptr || !*ptr) continue; + P space_object = *ptr; if (!space_object || !owner->isFriendly(space_object) || space_object == target) continue; if (space_object->canBeDockedBy(owner) == DockStyle::None || !space_object->canRestockMissiles()) diff --git a/src/ai/evasionAI.cpp b/src/ai/evasionAI.cpp index f15f4db1d7..4868e7ecb4 100644 --- a/src/ai/evasionAI.cpp +++ b/src/ai/evasionAI.cpp @@ -3,6 +3,7 @@ #include "ai/evasionAI.h" #include "ai/aiFactory.h" #include "random.h" +#include "systems/collision.h" REGISTER_SHIP_AI(EvasionAI, "evasion"); @@ -77,14 +78,14 @@ bool EvasionAI::evadeIfNecessary() auto position = owner->getPosition(); float scan_radius = 9000.0; - PVector objectList = CollisionManager::queryArea(position - glm::vec2(scan_radius, scan_radius), position + glm::vec2(scan_radius, scan_radius)); - // NOT AN OBJECT ON THE PLANE, but it represents an escape vector. // It tracks which direction is the best to run to (angle) and the strength of the desire to go there (distance from origin) glm::vec2 evasion_vector = glm::vec2(0, 0); - foreach(Collisionable, obj, objectList) + for(auto entity : sp::CollisionSystem::queryArea(position - glm::vec2(scan_radius, scan_radius), position + glm::vec2(scan_radius, scan_radius))) { - P ship = obj; + auto ptr = entity.getComponent(); + if (!ptr || !*ptr) continue; + P ship = P(*ptr); if (!ship || !owner->isEnemy(ship)) continue; if (ship->canHideInNebula() && Nebula::blockedByNebula(position, ship->getPosition(), owner->getShortRangeRadarRange())) diff --git a/src/gameGlobalInfo.cpp b/src/gameGlobalInfo.cpp index c55f2e1d7f..a97974ccb9 100644 --- a/src/gameGlobalInfo.cpp +++ b/src/gameGlobalInfo.cpp @@ -6,6 +6,8 @@ #include "soundManager.h" #include "random.h" #include "config.h" +#include "components/collision.h" +#include "systems/collision.h" #include P gameGlobalInfo; @@ -415,14 +417,16 @@ static int getObjectsInRadius(lua_State* L) glm::vec2 position(x, y); PVector objects; - PVector objectList = CollisionManager::queryArea(position - glm::vec2(r, r), position + glm::vec2(r, r)); - foreach(Collisionable, obj, objectList) - { - P sobj = obj; - if (sobj && glm::length2(sobj->getPosition() - position) < r*r) - objects.push_back(sobj); + for(auto entity : sp::CollisionSystem::queryArea(position - glm::vec2(r, r), position + glm::vec2(r, r))) { + auto entity_position = entity.getComponent(); + if (entity_position) { + if (glm::length2(entity_position->getPosition() - position) < r*r) { + auto obj = entity.getComponent(); + if (obj) + objects.push_back(*obj); + } + } } - return convert >::returnType(L, objects); } /// PVector getObjectsInRadius(float x, float y, float radius) diff --git a/src/modelData.cpp b/src/modelData.cpp index 7231ed1270..89980e2359 100644 --- a/src/modelData.cpp +++ b/src/modelData.cpp @@ -6,6 +6,7 @@ #include "spaceObjects/spaceObject.h" #include "modelData.h" +#include "components/collision.h" #include "scriptInterface.h" #include "glObjects.h" @@ -123,8 +124,10 @@ void ModelData::setSpecular(string specular_texture_name) void ModelData::setCollisionData(P object) { object->setRadius(radius); - if (collision_box.x > 0 && collision_box.y > 0) - object->setCollisionBox(collision_box); + if (collision_box.x > 0 && collision_box.y > 0) { + auto physics = object->entity.getOrAddComponent(); + physics.setRectangle(physics.getType(), collision_box); + } } glm::vec3 ModelData::getBeamPosition(int index) diff --git a/src/screenComponents/dockingButton.cpp b/src/screenComponents/dockingButton.cpp index a86c227a4c..ac7c8536b0 100644 --- a/src/screenComponents/dockingButton.cpp +++ b/src/screenComponents/dockingButton.cpp @@ -2,6 +2,8 @@ #include "playerInfo.h" #include "spaceObjects/playerSpaceship.h" #include "dockingButton.h" +#include "systems/collision.h" + GuiDockingButton::GuiDockingButton(GuiContainer* owner, string id) : GuiButton(owner, id, "", [this]() { click(); }) @@ -87,11 +89,12 @@ void GuiDockingButton::onDraw(sp::RenderTarget& renderer) P GuiDockingButton::findDockingTarget() { - PVector obj_list = CollisionManager::queryArea(my_spaceship->getPosition() - glm::vec2(1000, 1000), my_spaceship->getPosition() + glm::vec2(1000, 1000)); P dock_object; - foreach(Collisionable, obj, obj_list) + for(auto entity : sp::CollisionSystem::queryArea(my_spaceship->getPosition() - glm::vec2(1000, 1000), my_spaceship->getPosition() + glm::vec2(1000, 1000))) { - dock_object = obj; + auto ptr = entity.getComponent(); + if (!ptr || !*ptr) continue; + dock_object = *ptr; if (dock_object && dock_object != my_spaceship && dock_object->canBeDockedBy(my_spaceship) != DockStyle::None && glm::length(dock_object->getPosition() - my_spaceship->getPosition()) < 1000.0f + dock_object->getRadius()) break; dock_object = NULL; diff --git a/src/screenComponents/radarView.cpp b/src/screenComponents/radarView.cpp index 4825377002..0aaf0bd287 100644 --- a/src/screenComponents/radarView.cpp +++ b/src/screenComponents/radarView.cpp @@ -1,6 +1,7 @@ #include #include "ecs/query.h" +#include "systems/collision.h" #include "main.h" #include "gameGlobalInfo.h" #include "spaceObjects/nebula.h" @@ -623,13 +624,14 @@ void GuiRadarView::drawObjects(sp::RenderTarget& renderer) // Query for objects within short-range radar/5U of this object. auto position = obj->getPosition(); - PVector obj_list = CollisionManager::queryArea(position - glm::vec2(r, r), position + glm::vec2(r, r)); // For each of those objects, check if it is at least partially // inside the revealed radius. If so, reveal the object on the map. - foreach(Collisionable, c_obj, obj_list) + for(auto entity : sp::CollisionSystem::queryArea(position - glm::vec2(r, r), position + glm::vec2(r, r))) { - P obj2 = c_obj; + auto ptr = entity.getComponent(); + if (!ptr || !*ptr) continue; + P obj2 = *ptr; auto r2 = r + obj2->getRadius(); if (obj2 && glm::length2(obj->getPosition() - obj2->getPosition()) < r2*r2) diff --git a/src/screenComponents/targetsContainer.cpp b/src/screenComponents/targetsContainer.cpp index e1fce48eb0..27da6ec06f 100644 --- a/src/screenComponents/targetsContainer.cpp +++ b/src/screenComponents/targetsContainer.cpp @@ -1,6 +1,8 @@ #include "targetsContainer.h" #include "playerInfo.h" #include "spaceObjects/playerSpaceship.h" +#include "systems/collision.h" + TargetsContainer::TargetsContainer() { @@ -49,10 +51,11 @@ void TargetsContainer::set(PVector objs) void TargetsContainer::setToClosestTo(glm::vec2 position, float max_range, ESelectionType selection_type) { P target; - PVector list = CollisionManager::queryArea(position - glm::vec2(max_range, max_range), position + glm::vec2(max_range, max_range)); - foreach(Collisionable, obj, list) + for(auto entity : sp::CollisionSystem::queryArea(position - glm::vec2(max_range, max_range), position + glm::vec2(max_range, max_range))) { - P spaceObject = obj; + auto ptr = entity.getComponent(); + if (!ptr || !*ptr) continue; + P spaceObject = *ptr; if (spaceObject && spaceObject != my_spaceship) { switch(selection_type) diff --git a/src/screens/gm/gameMasterScreen.cpp b/src/screens/gm/gameMasterScreen.cpp index 181cbb05d9..87707d0690 100644 --- a/src/screens/gm/gameMasterScreen.cpp +++ b/src/screens/gm/gameMasterScreen.cpp @@ -11,6 +11,7 @@ #include "spaceObjects/spaceStation.h" #include "spaceObjects/wormHole.h" #include "spaceObjects/zone.h" +#include "systems/collision.h" #include "screenComponents/radarView.h" @@ -486,10 +487,11 @@ void GameMasterScreen::onMouseUp(glm::vec2 position) //Right click bool shift_down = SDL_GetModState() & KMOD_SHIFT; P target; - PVector list = CollisionManager::queryArea(position, position); - foreach(Collisionable, collisionable, list) + for(auto entity : sp::CollisionSystem::queryArea(position, position)) { - P space_object = collisionable; + auto ptr = entity.getComponent(); + if (!ptr || !*ptr) continue; + P space_object = *ptr; if (space_object) { if (!target || glm::length(position - space_object->getPosition()) < glm::length(position - target->getPosition())) @@ -550,17 +552,19 @@ void GameMasterScreen::onMouseUp(glm::vec2 position) bool shift_down = SDL_GetModState() & KMOD_SHIFT; bool ctrl_down = SDL_GetModState() & KMOD_CTRL; bool alt_down = SDL_GetModState() & KMOD_ALT; - PVector objects = CollisionManager::queryArea(drag_start_position, position); PVector space_objects; - foreach(Collisionable, c, objects) + for(auto entity : sp::CollisionSystem::queryArea(drag_start_position, position)) { - if (P(c)) + auto ptr = entity.getComponent(); + if (!ptr || !*ptr) continue; + P obj = *ptr; + if (P(obj)) continue; - if (ctrl_down && !P(c)) + if (ctrl_down && !P(obj)) continue; - if (alt_down && (!P(c) || (int)(P(c))->getFactionId() != faction_selector->getSelectionIndex())) + if (alt_down && (!P(obj) || (int)(P(obj))->getFactionId() != faction_selector->getSelectionIndex())) continue; - space_objects.push_back(c); + space_objects.push_back(obj); } if (shift_down) { diff --git a/src/spaceObjects/artifact.cpp b/src/spaceObjects/artifact.cpp index fadf920a67..76c179d8d6 100644 --- a/src/spaceObjects/artifact.cpp +++ b/src/spaceObjects/artifact.cpp @@ -85,7 +85,7 @@ void Artifact::update(float delta) } } -void Artifact::collide(Collisionable* target, float force) +void Artifact::collide(SpaceObject* target, float force) { // Handle collisions on the server only. if (!isServer()) @@ -94,7 +94,7 @@ void Artifact::collide(Collisionable* target, float force) } // Fire collision callbacks. - P hit_object = P(target); + P hit_object = target; P player = hit_object; // Player-specific callback handling. diff --git a/src/spaceObjects/artifact.h b/src/spaceObjects/artifact.h index f623dc0721..e33e29d16f 100644 --- a/src/spaceObjects/artifact.h +++ b/src/spaceObjects/artifact.h @@ -19,7 +19,7 @@ class Artifact : public SpaceObject, public Updatable virtual void update(float delta) override; - virtual void collide(Collisionable* target, float force) override; + virtual void collide(SpaceObject* target, float force) override; void setModel(string name); void setSpin(float spin=0.0); diff --git a/src/spaceObjects/asteroid.cpp b/src/spaceObjects/asteroid.cpp index a71a661763..61b901f356 100644 --- a/src/spaceObjects/asteroid.cpp +++ b/src/spaceObjects/asteroid.cpp @@ -81,11 +81,11 @@ void Asteroid::drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float renderer.drawSprite("radar/blip.png", position, size * 32.0f, glm::u8vec4(255, 200, 100, 255)); } -void Asteroid::collide(Collisionable* target, float force) +void Asteroid::collide(SpaceObject* target, float force) { if (!isServer()) return; - P hit_object = P(target); + P hit_object = target; if (!hit_object || !hit_object->canBeTargetedBy(nullptr)) return; diff --git a/src/spaceObjects/asteroid.h b/src/spaceObjects/asteroid.h index 8ca3da4f42..9c65784cc9 100644 --- a/src/spaceObjects/asteroid.h +++ b/src/spaceObjects/asteroid.h @@ -17,7 +17,7 @@ class Asteroid : public SpaceObject virtual void drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) override; - virtual void collide(Collisionable* target, float force) override; + virtual void collide(SpaceObject* target, float force) override; void setSize(float size); float getSize(); diff --git a/src/spaceObjects/beamEffect.cpp b/src/spaceObjects/beamEffect.cpp index 9d3c1ef19e..c3dcaf5cd2 100644 --- a/src/spaceObjects/beamEffect.cpp +++ b/src/spaceObjects/beamEffect.cpp @@ -9,6 +9,7 @@ #include "soundManager.h" #include "multiplayer_server.h" #include "multiplayer_client.h" +#include "components/collision.h" #include "shaderRegistry.h" @@ -39,7 +40,8 @@ BeamEffect::BeamEffect() { has_weight = false; setRadarSignatureInfo(0.0, 0.3, 0.0); - setCollisionRadius(1.0); + + entity.removeComponent(); //TODO: Never add this in the first place. lifetime = 1.0; sourceId = -1; target_id = -1; diff --git a/src/spaceObjects/blackHole.cpp b/src/spaceObjects/blackHole.cpp index 455207fb91..cdff62921f 100644 --- a/src/spaceObjects/blackHole.cpp +++ b/src/spaceObjects/blackHole.cpp @@ -71,12 +71,12 @@ void BlackHole::drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, floa renderer.drawSprite("radar/blackHole.png", position, size, glm::u8vec4(0, 0, 0, 255)); } -void BlackHole::collide(Collisionable* target, float collision_force) +void BlackHole::collide(SpaceObject* target, float collision_force) { if (update_delta == 0.0f) return; - P obj = P(target); + P obj = target; if (!obj) return; if (!obj->hasWeight()) { return; } // the object is not affected by gravitation diff --git a/src/spaceObjects/blackHole.h b/src/spaceObjects/blackHole.h index 601c44c1cb..9019fccef7 100644 --- a/src/spaceObjects/blackHole.h +++ b/src/spaceObjects/blackHole.h @@ -18,7 +18,7 @@ class BlackHole : public SpaceObject, public Updatable virtual bool canHideInNebula() override { return false; } virtual ERadarLayer getRadarLayer() const override { return ERadarLayer::BackgroundObjects; } - virtual void collide(Collisionable* target, float force) override; + virtual void collide(SpaceObject* target, float force) override; virtual string getExportLine() override { return "BlackHole():setPosition(" + string(getPosition().x, 0) + ", " + string(getPosition().y, 0) + ")"; } }; diff --git a/src/spaceObjects/electricExplosionEffect.cpp b/src/spaceObjects/electricExplosionEffect.cpp index 225990af21..afd01cd417 100644 --- a/src/spaceObjects/electricExplosionEffect.cpp +++ b/src/spaceObjects/electricExplosionEffect.cpp @@ -8,6 +8,7 @@ #include "tween.h" #include "soundManager.h" #include "textureManager.h" +#include "components/collision.h" /// ElectricExplosionEffect is a visible electrical explosion, as seen from EMP missiles /// Example: ElectricExplosionEffect():setPosition(500,5000):setSize(20) @@ -25,7 +26,7 @@ ElectricExplosionEffect::ElectricExplosionEffect() on_radar = false; size = 1.f; - setCollisionRadius(1.0); + entity.removeComponent(); //TODO: Never add this in the first place. lifetime = maxLifetime; for(int n=0; n(); //TODO: Never add this in the first place. lifetime = maxLifetime; for(int n=0; n(); + physics.setCircle(sp::Physics::Type::Sensor, trigger_range); triggered = false; triggerTimeout = triggerDelay; ejectTimeout = 0.0; @@ -68,12 +70,14 @@ void Mine::update(float delta) particleTimeout = 0.4; } + auto physics = entity.getComponent(); + if (ejectTimeout > 0.0f) { ejectTimeout -= delta; - setVelocity(vec2FromAngle(getRotation()) * data.speed); + if (physics) physics->setVelocity(vec2FromAngle(getRotation()) * data.speed); }else{ - setVelocity(glm::vec2(0, 0)); + if (physics) physics->setVelocity(glm::vec2(0, 0)); } if (!triggered) return; @@ -84,11 +88,11 @@ void Mine::update(float delta) } } -void Mine::collide(Collisionable* target, float force) +void Mine::collide(SpaceObject* target, float force) { if (!game_server || triggered || ejectTimeout > 0.0f) return; - P hitObject = P(target); + P hitObject = target; if (!hitObject || !hitObject->canBeTargetedBy(nullptr)) return; diff --git a/src/spaceObjects/mine.h b/src/spaceObjects/mine.h index 1c89b9a638..9680717d3d 100644 --- a/src/spaceObjects/mine.h +++ b/src/spaceObjects/mine.h @@ -29,7 +29,7 @@ class Mine : public SpaceObject, public Updatable virtual void drawOnGMRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) override; virtual void update(float delta) override; - virtual void collide(Collisionable* target, float force) override; + virtual void collide(SpaceObject* target, float force) override; void eject(); void explode(); void onDestruction(ScriptSimpleCallback callback); diff --git a/src/spaceObjects/missiles/hvli.cpp b/src/spaceObjects/missiles/hvli.cpp index 0650c206fe..ebc60a9015 100644 --- a/src/spaceObjects/missiles/hvli.cpp +++ b/src/spaceObjects/missiles/hvli.cpp @@ -1,6 +1,7 @@ #include "hvli.h" #include "particleEffect.h" #include "spaceObjects/explosionEffect.h" +#include "components/collision.h" /// HVLI missile REGISTER_SCRIPT_SUBCLASS(HVLI, MissileWeapon) @@ -13,7 +14,8 @@ HVLI::HVLI() : MissileWeapon("HVLI", MissileWeaponData::getDataFor(MW_HVLI)) { setRadarSignatureInfo(0.1, 0.0, 0.0); - setCollisionBox({10, 30}); // Make it a bit harder to the HVLI to phase trough smaller enemies + auto physics = entity.getOrAddComponent(); + physics.setRectangle(sp::Physics::Type::Sensor, {10, 30}); // Make it a bit harder to the HVLI to phase trough smaller enemies } void HVLI::hitObject(P object) diff --git a/src/spaceObjects/missiles/missileWeapon.cpp b/src/spaceObjects/missiles/missileWeapon.cpp index 27c71259d3..cd6e40e2bf 100644 --- a/src/spaceObjects/missiles/missileWeapon.cpp +++ b/src/spaceObjects/missiles/missileWeapon.cpp @@ -5,6 +5,7 @@ #include "multiplayer_server.h" #include "multiplayer_client.h" #include "soundManager.h" +#include "components/collision.h" #include "i18n.h" @@ -74,7 +75,9 @@ void MissileWeapon::update(float delta) lifeEnded(); destroy(); } - setVelocity(vec2FromAngle(getRotation()) * data.speed * size_speed_modifier); + auto physics = entity.getComponent(); + if (physics) + physics->setVelocity(vec2FromAngle(getRotation()) * data.speed * size_speed_modifier); if (delta > 0) { @@ -82,13 +85,13 @@ void MissileWeapon::update(float delta) } } -void MissileWeapon::collide(Collisionable* target, float force) +void MissileWeapon::collide(SpaceObject* target, float force) { if (!game_server) { return; } - P object = P(target); + P object = target; if (!object || object == owner || !object->canBeTargetedBy(owner)) { return; @@ -128,12 +131,15 @@ void MissileWeapon::updateMovement() float angle_diff = angleDifference(getRotation(), target_angle); - if (angle_diff > 1.0f) - setAngularVelocity(data.turnrate * size_speed_modifier); - else if (angle_diff < -1.0f) - setAngularVelocity(data.turnrate * -1.0f * size_speed_modifier); - else - setAngularVelocity(angle_diff * data.turnrate * size_speed_modifier); + auto physics = entity.getComponent(); + if (physics) { + if (angle_diff > 1.0f) + physics->setAngularVelocity(data.turnrate * size_speed_modifier); + else if (angle_diff < -1.0f) + physics->setAngularVelocity(data.turnrate * -1.0f * size_speed_modifier); + else + physics->setAngularVelocity(angle_diff * data.turnrate * size_speed_modifier); + } } } diff --git a/src/spaceObjects/missiles/missileWeapon.h b/src/spaceObjects/missiles/missileWeapon.h index 3ab5d18fdb..f57fbb2273 100644 --- a/src/spaceObjects/missiles/missileWeapon.h +++ b/src/spaceObjects/missiles/missileWeapon.h @@ -26,7 +26,7 @@ class MissileWeapon : public SpaceObject, public Updatable virtual void drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) override; virtual void update(float delta) override; - virtual void collide(Collisionable* target, float force) override; + virtual void collide(SpaceObject* target, float force) override; virtual void takeDamage(float damage_amount, DamageInfo info) override { // Energy and EMP damage can destroy a missile. if (info.type != DT_Kinetic) destroy(); diff --git a/src/spaceObjects/nebula.cpp b/src/spaceObjects/nebula.cpp index ddb46e3bc3..c93c7f73b1 100644 --- a/src/spaceObjects/nebula.cpp +++ b/src/spaceObjects/nebula.cpp @@ -5,6 +5,7 @@ #include "playerInfo.h" #include "random.h" #include "textureManager.h" +#include "components/collision.h" #include "scriptInterface.h" @@ -32,9 +33,7 @@ REGISTER_MULTIPLAYER_CLASS(Nebula, "Nebula") Nebula::Nebula() : SpaceObject(5000, "Nebula") { - // Nebulae need a large radius to render properly from a distance, but - // collision isn't important, so set the collision radius to a tiny range. - setCollisionRadius(1); + entity.removeComponent(); //TODO: Never add this in the first place. setRotation(random(0, 360)); radar_visual = irandom(1, 3); setRadarSignatureInfo(0.0, 0.8, -1.0); diff --git a/src/spaceObjects/planet.cpp b/src/spaceObjects/planet.cpp index b4ba045df9..528ea30d61 100644 --- a/src/spaceObjects/planet.cpp +++ b/src/spaceObjects/planet.cpp @@ -9,6 +9,7 @@ #include "textureManager.h" #include "multiplayer_server.h" #include "multiplayer_client.h" +#include "components/collision.h" #include #include @@ -364,7 +365,7 @@ void Planet::drawOnGMRadar(sp::RenderTarget& renderer, glm::vec2 position, float renderer.drawCircleOutline(position, planet_size * scale, 3, glm::u8vec4(255, 255, 255, 128)); } -void Planet::collide(Collisionable* target, float collision_force) +void Planet::collide(SpaceObject* target, float collision_force) { if (collision_size > 0) { @@ -378,10 +379,10 @@ void Planet::updateCollisionSize() if (std::abs(distance_from_movement_plane) >= planet_size) { collision_size = -1.0; + entity.removeComponent(); }else{ collision_size = sqrt((planet_size * planet_size) - (distance_from_movement_plane * distance_from_movement_plane)) * 1.1f; - setCollisionRadius(collision_size); - setCollisionPhysics(true, true); + entity.getOrAddComponent().setCircle(sp::Physics::Type::Static, collision_size); } } diff --git a/src/spaceObjects/planet.h b/src/spaceObjects/planet.h index bdc84d535c..e55ccf937a 100644 --- a/src/spaceObjects/planet.h +++ b/src/spaceObjects/planet.h @@ -15,7 +15,7 @@ class Planet : public SpaceObject, public Updatable virtual void drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) override; virtual void drawOnGMRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) override; virtual void update(float delta) override; - virtual void collide(Collisionable* target, float force) override; + virtual void collide(SpaceObject* target, float force) override; virtual bool canHideInNebula() override { return false; } float getPlanetRadius(); diff --git a/src/spaceObjects/shipTemplateBasedObject.cpp b/src/spaceObjects/shipTemplateBasedObject.cpp index 4d0de6b87d..7b2eeefa5d 100644 --- a/src/spaceObjects/shipTemplateBasedObject.cpp +++ b/src/spaceObjects/shipTemplateBasedObject.cpp @@ -1,6 +1,7 @@ #include "shipTemplateBasedObject.h" #include "scriptInterface.h" +#include "components/collision.h" #include "tween.h" #include "i18n.h" @@ -108,7 +109,7 @@ REGISTER_SCRIPT_SUBCLASS_NO_CREATE(ShipTemplateBasedObject, SpaceObject) ShipTemplateBasedObject::ShipTemplateBasedObject(float collision_range, string multiplayer_name, float multiplayer_significant_range) : SpaceObject(collision_range, multiplayer_name, multiplayer_significant_range) { - setCollisionPhysics(true, true); + entity.getOrAddComponent().setCircle(sp::Physics::Type::Dynamic, collision_range); shield_count = 0; for(int n=0; n @@ -14,24 +16,24 @@ REGISTER_SCRIPT_CLASS_NO_CREATE(SpaceObject) /// Sets this object's position on the map, in meters from the origin. /// Requires two numeric values. /// Example: obj:setPosition(x, y) - REGISTER_SCRIPT_CLASS_FUNCTION(Collisionable, setPosition); + REGISTER_SCRIPT_CLASS_FUNCTION(SpaceObject, setPosition); /// Gets this object's position on the map. /// Returns x, y as meters from the origin. /// Example: local x, y = obj:getPosition() - REGISTER_SCRIPT_CLASS_FUNCTION(Collisionable, getPosition); + REGISTER_SCRIPT_CLASS_FUNCTION(SpaceObject, getPosition); /// Sets this object's absolute rotation, in degrees. /// Unlike setHeading, a value of 0 points to the right of the map. /// The value can also be unbounded; it can be negative, or greater than /// 360 degrees. /// Requires a numeric value. /// Example: obj:setRotation(270) - REGISTER_SCRIPT_CLASS_FUNCTION(Collisionable, setRotation); + REGISTER_SCRIPT_CLASS_FUNCTION(SpaceObject, setRotation); /// Gets this object's absolute rotation. /// setHeading and setRotation do not change the target heading of /// PlayerSpaceships; use PlayerSpaceship's commandTargetRotation. /// Returns a value in degrees. /// Example: local rotation = obj:getRotation() - REGISTER_SCRIPT_CLASS_FUNCTION(Collisionable, getRotation); + REGISTER_SCRIPT_CLASS_FUNCTION(SpaceObject, getRotation); /// Sets this object's heading, in degrees ranging from 0 to 360. /// Unlike setRotation, a value of 0 points to the top of the map. /// Values that are negative or greater than 360 are are converted to values @@ -48,11 +50,11 @@ REGISTER_SCRIPT_CLASS_NO_CREATE(SpaceObject) /// Gets this object's directional velocity within 2D space. /// Returns a pair of values x, y which are relative x, y coordinates from current position (2D velocity vector). /// Example: local vx, vy = obj:getVelocity() - REGISTER_SCRIPT_CLASS_FUNCTION(Collisionable, getVelocity); + REGISTER_SCRIPT_CLASS_FUNCTION(SpaceObject, getVelocity); /// Gets this object's rotational velocity within 2D space. /// Returns a value in degrees/second. /// Example: local angular_velocity = obj:getAngularVelocity() - REGISTER_SCRIPT_CLASS_FUNCTION(Collisionable, getAngularVelocity); + REGISTER_SCRIPT_CLASS_FUNCTION(SpaceObject, getAngularVelocity); /// Sets the faction to which this object belongs, by faction name. /// Factions are defined by the FactionInfo() function, and default /// factions are defined in scripts/factionInfo.lua. @@ -287,10 +289,13 @@ REGISTER_SCRIPT_CLASS_NO_CREATE(SpaceObject) PVector space_object_list; SpaceObject::SpaceObject(float collision_range, string multiplayer_name, float multiplayer_significant_range) -: Collisionable(collision_range), MultiplayerObject(multiplayer_name) +: MultiplayerObject(multiplayer_name) { if (isServer()) { entity = sp::ecs::Entity::create(); + //TODO: multiplayer_significant_range + entity.addComponent(); + entity.addComponent().setCircle(sp::Physics::Type::Sensor, collision_range); } object_radius = collision_range; @@ -310,7 +315,6 @@ SpaceObject::SpaceObject(float collision_range, string multiplayer_name, float m registerMemberReplication(&entity); registerMemberReplication(&scanning_complexity_value); registerMemberReplication(&scanning_depth_value); - registerCollisionableReplication(multiplayer_significant_range); } SpaceObject::~SpaceObject() @@ -318,6 +322,15 @@ SpaceObject::~SpaceObject() entity.destroy(); } +void SpaceObject::setRadius(float radius) +{ + object_radius = radius; + auto physics = entity.getComponent(); + if (!physics) + physics = &entity.addComponent(); + physics->setCircle(sp::Physics::Type::Dynamic, radius); +} + void SpaceObject::draw3D() { model_info.render(getPosition(), getRotation(), getModelMatrix()); @@ -487,28 +500,32 @@ bool SpaceObject::isFriendly(P obj) void SpaceObject::damageArea(glm::vec2 position, float blast_range, float min_damage, float max_damage, DamageInfo info, float min_range) { - PVector hitList = CollisionManager::queryArea(position - glm::vec2(blast_range, blast_range), position + glm::vec2(blast_range, blast_range)); - foreach(Collisionable, c, hitList) + for(auto entity : sp::CollisionSystem::queryArea(position - glm::vec2(blast_range, blast_range), position + glm::vec2(blast_range, blast_range))) { - P obj = c; - if (obj) + auto ptr = entity.getComponent(); + if (!ptr) continue; + auto pos = entity.getComponent(); + if (!pos) continue; + P obj = *ptr; + + float dist = glm::length(position - pos->getPosition()) - obj->getRadius() - min_range; + if (dist < 0) dist = 0; + if (dist < blast_range - min_range) { - float dist = glm::length(position - obj->getPosition()) - obj->getRadius() - min_range; - if (dist < 0) dist = 0; - if (dist < blast_range - min_range) - { - obj->takeDamage(max_damage - (max_damage - min_damage) * dist / (blast_range - min_range), info); - } + obj->takeDamage(max_damage - (max_damage - min_damage) * dist / (blast_range - min_range), info); } } } bool SpaceObject::areEnemiesInRange(float range) { - PVector hitList = CollisionManager::queryArea(getPosition() - glm::vec2(range, range), getPosition() + glm::vec2(range, range)); - foreach(Collisionable, c, hitList) + for(auto entity : sp::CollisionSystem::queryArea(getPosition() - glm::vec2(range, range), getPosition() + glm::vec2(range, range))) { - P obj = c; + auto ptr = entity.getComponent(); + if (!ptr) continue; + auto pos = entity.getComponent(); + if (!pos) continue; + P obj = *ptr; if (obj && isEnemy(obj)) { auto r = range + obj->getRadius(); @@ -522,10 +539,13 @@ bool SpaceObject::areEnemiesInRange(float range) PVector SpaceObject::getObjectsInRange(float range) { PVector ret; - PVector hitList = CollisionManager::queryArea(getPosition() - glm::vec2(range, range), getPosition() + glm::vec2(range, range)); - foreach(Collisionable, c, hitList) + for(auto entity : sp::CollisionSystem::queryArea(getPosition() - glm::vec2(range, range), getPosition() + glm::vec2(range, range))) { - P obj = c; + auto ptr = entity.getComponent(); + if (!ptr) continue; + auto pos = entity.getComponent(); + if (!pos) continue; + P obj = *ptr; auto r = range + obj->getRadius(); if (obj && glm::length2(getPosition() - obj->getPosition()) < r*r) { @@ -612,6 +632,55 @@ bool SpaceObject::sendCommsMessageNoLog(P target, string messag return target->hailByObject(this, message); } +glm::vec2 SpaceObject::getPosition() const +{ + if (!entity) return {}; + const auto position = entity.getComponent(); + if (!position) return {}; + return position->getPosition(); +} + +void SpaceObject::setPosition(glm::vec2 p) +{ + if (!entity) return; + auto position = entity.getComponent(); + if (!position) return; + position->setPosition(p); +} + +float SpaceObject::getRotation() const +{ + if (!entity) return {}; + auto position = entity.getComponent(); + if (!position) return {}; + return position->getRotation(); +} + +void SpaceObject::setRotation(float a) +{ + if (!entity) return; + auto position = entity.getComponent(); + if (!position) return; + position->setRotation(a); +} + +glm::vec2 SpaceObject::getVelocity() const +{ + if (!entity) return {}; + auto physics = entity.getComponent(); + if (!physics) return {}; + return physics->getVelocity(); +} + +float SpaceObject::getAngularVelocity() const +{ + if (!entity) return 0.0; + auto physics = entity.getComponent(); + if (!physics) return 0.0; + return physics->getAngularVelocity(); +} + + glm::mat4 SpaceObject::getModelMatrix() const { auto position = getPosition(); diff --git a/src/spaceObjects/spaceObject.h b/src/spaceObjects/spaceObject.h index dfbb38d7a8..2fb19ad453 100644 --- a/src/spaceObjects/spaceObject.h +++ b/src/spaceObjects/spaceObject.h @@ -1,7 +1,6 @@ #ifndef SPACE_OBJECT_H #define SPACE_OBJECT_H -#include "collisionable.h" #include "multiplayer.h" #include "scriptInterface.h" #include "featureDefs.h" @@ -68,7 +67,7 @@ class SpaceObject; class PlayerSpaceship; extern PVector space_object_list; -class SpaceObject : public Collisionable, public MultiplayerObject +class SpaceObject : public MultiplayerObject { float object_radius; uint8_t faction_id; @@ -101,7 +100,7 @@ class SpaceObject : public Collisionable, public MultiplayerObject virtual ~SpaceObject(); float getRadius() const { return object_radius; } - void setRadius(float radius) { object_radius = radius; setCollisionRadius(radius); } + void setRadius(float radius); bool hasWeight() { return has_weight; } @@ -219,10 +218,19 @@ class SpaceObject : public Collisionable, public MultiplayerObject bool sendCommsMessage(P target, string message); bool sendCommsMessageNoLog(P target, string message); + //TODO + virtual void collide(SpaceObject* other, float force) {} + + glm::vec2 getPosition() const; + void setPosition(glm::vec2 p); + float getRotation() const; + void setRotation(float a); + glm::vec2 getVelocity() const; + float getAngularVelocity() const; + ScriptSimpleCallback on_destroyed; glm::mat4 getModelTransform() const { return getModelMatrix(); } - protected: virtual glm::mat4 getModelMatrix() const; ModelInfo model_info; diff --git a/src/spaceObjects/spaceship.cpp b/src/spaceObjects/spaceship.cpp index 42d6f985a0..b38ca792dc 100644 --- a/src/spaceObjects/spaceship.cpp +++ b/src/spaceObjects/spaceship.cpp @@ -16,6 +16,7 @@ #include "textureManager.h" #include "multiplayer_client.h" #include "gameGlobalInfo.h" +#include "components/collision.h" #include "scriptInterface.h" @@ -178,8 +179,6 @@ std::array SpaceShip::default_system_power_factors{ SpaceShip::SpaceShip(string multiplayerClassName, float multiplayer_significant_range) : ShipTemplateBasedObject(50, multiplayerClassName, multiplayer_significant_range) { - setCollisionPhysics(true, false); - target_rotation = getRotation(); impulse_request = 0; current_impulse = 0; @@ -663,12 +662,16 @@ void SpaceShip::update(float delta) { ShipTemplateBasedObject::update(delta); - if (hasCollisionShape() != (docked_style != DockStyle::Internal)) + auto physics = entity.getComponent(); + + if (bool(physics) != (docked_style != DockStyle::Internal)) { - if (docked_style == DockStyle::Internal) - setCollisionRadius(0); - else if (ship_template) + if (docked_style == DockStyle::Internal) { + entity.removeComponent(); + physics = nullptr; + } else if (ship_template) { ship_template->setCollisionData(this); + } } if (game_server) @@ -718,12 +721,14 @@ void SpaceShip::update(float delta) rotationDiff = turnSpeed; } - if (rotationDiff > 1.0f) - setAngularVelocity(turn_speed * getSystemEffectiveness(SYS_Maneuver)); - else if (rotationDiff < -1.0f) - setAngularVelocity(-turn_speed * getSystemEffectiveness(SYS_Maneuver)); - else - setAngularVelocity(rotationDiff * turn_speed * getSystemEffectiveness(SYS_Maneuver)); + if (physics) { + if (rotationDiff > 1.0f) + physics->setAngularVelocity(turn_speed * getSystemEffectiveness(SYS_Maneuver)); + else if (rotationDiff < -1.0f) + physics->setAngularVelocity(-turn_speed * getSystemEffectiveness(SYS_Maneuver)); + else + physics->setAngularVelocity(rotationDiff * turn_speed * getSystemEffectiveness(SYS_Maneuver)); + } //Here we want to have max speed at 100% impulse, and max reverse speed at -100% impulse float cap_speed = impulse_max_speed; @@ -846,7 +851,8 @@ void SpaceShip::update(float delta) // Determine forward direction and velocity. auto forward = vec2FromAngle(getRotation()); - setVelocity(forward * (current_impulse * cap_speed * getSystemEffectiveness(SYS_Impulse) + current_warp * warp_speed_per_warp_level * getSystemEffectiveness(SYS_Warp))); + if (physics) + physics->setVelocity(forward * (current_impulse * cap_speed * getSystemEffectiveness(SYS_Impulse) + current_warp * warp_speed_per_warp_level * getSystemEffectiveness(SYS_Warp))); if (combat_maneuver_boost_active > combat_maneuver_boost_request) { @@ -886,10 +892,10 @@ void SpaceShip::update(float delta) combat_maneuver_charge = 0.0f; combat_maneuver_boost_request = 0.0f; combat_maneuver_strafe_request = 0.0f; - }else + }else if (physics) { - setVelocity(getVelocity() + forward * combat_maneuver_boost_speed * combat_maneuver_boost_active); - setVelocity(getVelocity() + vec2FromAngle(getRotation() + 90) * combat_maneuver_strafe_speed * combat_maneuver_strafe_active); + physics->setVelocity(physics->getVelocity() + forward * combat_maneuver_boost_speed * combat_maneuver_boost_active); + physics->setVelocity(physics->getVelocity() + vec2FromAngle(getRotation() + 90) * combat_maneuver_strafe_speed * combat_maneuver_strafe_active); } // If the ship isn't making a combat maneuver, recharge its boost. }else if (combat_maneuver_charge < 1.0f) @@ -979,11 +985,11 @@ DockStyle SpaceShip::canBeDockedBy(P obj) return DockStyle::None; } -void SpaceShip::collide(Collisionable* other, float force) +void SpaceShip::collide(SpaceObject* other, float force) { if (docking_state == DS_Docking && fabs(angleDifference(target_rotation, getRotation())) < 10.0f) { - P dock_object = P(other); + P dock_object = other; if (dock_object == docking_target) { docking_state = DS_Docked; diff --git a/src/spaceObjects/spaceship.h b/src/spaceObjects/spaceship.h index ea1455963a..de26bbe831 100644 --- a/src/spaceObjects/spaceship.h +++ b/src/spaceObjects/spaceship.h @@ -274,7 +274,7 @@ class SpaceShip : public ShipTemplateBasedObject */ virtual DockStyle canBeDockedBy(P obj) override; - virtual void collide(Collisionable* other, float force) override; + virtual void collide(SpaceObject* other, float force) override; /*! * Start the jumping procedure. diff --git a/src/spaceObjects/supplyDrop.cpp b/src/spaceObjects/supplyDrop.cpp index 1b6dada91e..34f767740c 100644 --- a/src/spaceObjects/supplyDrop.cpp +++ b/src/spaceObjects/supplyDrop.cpp @@ -38,9 +38,9 @@ void SupplyDrop::drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, flo renderer.drawSprite("radar/blip.png", position, 8, color); } -void SupplyDrop::collide(Collisionable* target, float force) +void SupplyDrop::collide(SpaceObject* target, float force) { - P ship = P(target); + P ship = P(target); if (ship && isFriendly(ship)) { bool picked_up = false; diff --git a/src/spaceObjects/supplyDrop.h b/src/spaceObjects/supplyDrop.h index 0f0c128ac6..6519fc63fa 100644 --- a/src/spaceObjects/supplyDrop.h +++ b/src/spaceObjects/supplyDrop.h @@ -16,7 +16,7 @@ class SupplyDrop : public SpaceObject virtual void drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) override; - virtual void collide(Collisionable* target, float force) override; + virtual void collide(SpaceObject* target, float force) override; void setEnergy(float amount); void setWeaponStorage(EMissileWeapons weapon, int amount); diff --git a/src/spaceObjects/wormHole.cpp b/src/spaceObjects/wormHole.cpp index bcb99435dc..ac6e8e7022 100644 --- a/src/spaceObjects/wormHole.cpp +++ b/src/spaceObjects/wormHole.cpp @@ -118,12 +118,12 @@ void WormHole::update(float delta) update_delta = delta; } -void WormHole::collide(Collisionable* target, float collision_force) +void WormHole::collide(SpaceObject* target, float collision_force) { if (update_delta == 0.0f) return; - P obj = P(target); + P obj = target; if (!obj) return; if (!obj->hasWeight()) { return; } // the object is not affected by gravitation @@ -131,7 +131,7 @@ void WormHole::collide(Collisionable* target, float collision_force) float distance = glm::length(diff); float force = (getRadius() * getRadius() * FORCE_MULTIPLIER) / (distance * distance); - P spaceship = P(target); + P spaceship = obj; // Warp postprocessor-alpha is calculated using alpha = (1 - (delay/10)) if (spaceship) diff --git a/src/spaceObjects/wormHole.h b/src/spaceObjects/wormHole.h index 8a316c01eb..f95aa50149 100644 --- a/src/spaceObjects/wormHole.h +++ b/src/spaceObjects/wormHole.h @@ -25,7 +25,7 @@ class WormHole : public SpaceObject, public Updatable virtual void drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) override; virtual void drawOnGMRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) override; virtual void update(float delta) override; - virtual void collide(Collisionable* target, float force) override; + virtual void collide(SpaceObject* target, float force) override; virtual ERadarLayer getRadarLayer() const override { return ERadarLayer::BackgroundObjects; } void setTargetPosition(glm::vec2 v); /* Where to jump to */ diff --git a/src/spaceObjects/zone.cpp b/src/spaceObjects/zone.cpp index 00abeb665c..194d84cd52 100644 --- a/src/spaceObjects/zone.cpp +++ b/src/spaceObjects/zone.cpp @@ -4,6 +4,7 @@ #include "particleEffect.h" #include "explosionEffect.h" #include "pathPlanner.h" +#include "components/collision.h" #include "math/triangulate.h" #include "math/centerOfMass.h" @@ -88,7 +89,7 @@ void Zone::setPoints(const std::vector& points) setPosition(position); setRadius(radius); - setCollisionRadius(1); + entity.removeComponent(); //TODO: Never add this in the first place. } void Zone::setLabel(string label) diff --git a/src/threatLevelEstimate.cpp b/src/threatLevelEstimate.cpp index 62c9a6aea4..df389e6052 100644 --- a/src/threatLevelEstimate.cpp +++ b/src/threatLevelEstimate.cpp @@ -1,9 +1,10 @@ #include "gameGlobalInfo.h" #include "threatLevelEstimate.h" -#include "collisionable.h" #include "spaceObjects/spaceship.h" #include "spaceObjects/beamEffect.h" #include "spaceObjects/missiles/missileWeapon.h" +#include "systems/collision.h" + ThreatLevelEstimate::ThreatLevelEstimate() { @@ -55,9 +56,13 @@ float ThreatLevelEstimate::getThreatFor(P ship) threat += ship->hull_max - ship->hull_strength; float radius = 7000.0; - PVector objectList = CollisionManager::queryArea(ship->getPosition() - glm::vec2(radius, radius), ship->getPosition() + glm::vec2(radius, radius)); - foreach(Collisionable, obj, objectList) + + auto ship_position = ship->getPosition(); + for(auto entity : sp::CollisionSystem::queryArea(ship_position - glm::vec2(radius, radius), ship_position + glm::vec2(radius, radius))) { + auto ptr = entity.getComponent(); + if (!ptr) continue; + P obj = *ptr; P other_ship = obj; if (!other_ship || !ship->isEnemy(other_ship)) { From 7ceb0910651f34f6d9a5d25189bd8cadaf2e4490 Mon Sep 17 00:00:00 2001 From: Daid Date: Fri, 4 Nov 2022 07:10:29 +0100 Subject: [PATCH 008/320] WIP --- CMakeLists.txt | 1 + src/components/radar.h | 13 +++--- src/components/rendering.h | 19 +++++++++ src/screenComponents/radarView.cpp | 33 +++++++++++++-- src/spaceObjects/shipTemplateBasedObject.cpp | 15 ++++++- src/spaceObjects/shipTemplateBasedObject.h | 3 +- src/spaceObjects/spaceStation.cpp | 14 ------- src/spaceObjects/spaceship.cpp | 42 +++----------------- src/spaceObjects/spaceship.h | 2 - 9 files changed, 77 insertions(+), 65 deletions(-) create mode 100644 src/components/rendering.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c9be0b90b..b67f9c3b5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -354,6 +354,7 @@ set(MAIN_SOURCES src/spaceObjects/spaceshipParts/beamWeapon.cpp src/spaceObjects/spaceshipParts/weaponTube.cpp src/components/radar.h + src/components/rendering.h src/ai/fighterAI.cpp src/ai/ai.cpp src/ai/aiFactory.cpp diff --git a/src/components/radar.h b/src/components/radar.h index b0ed7b4665..f75153c1d7 100644 --- a/src/components/radar.h +++ b/src/components/radar.h @@ -5,22 +5,25 @@ class RadarTrace { public: + static constexpr uint32_t Rotate = 1 << 0; + static constexpr uint32_t ColorByFaction = 1 << 1; + static constexpr uint32_t ArrowIfNotScanned = 1 << 2; + string icon; float min_size = 8.0; //Size in screen "pixels" float max_size = 256.0; //Size in screen "pixels" float radius; // Size in world "units" glm::u8vec4 color{255,255,255,255}; - bool rotate = true; - //TODO: color by ffi/faction + uint32_t flags = Rotate; bool operator!=(const RadarTrace& o) { - return icon != o.icon || min_size != o.min_size || max_size != o.max_size || radius != o.radius || color != o.color || rotate != o.rotate; + return icon != o.icon || min_size != o.min_size || max_size != o.max_size || radius != o.radius || color != o.color || flags != o.flags; } }; -static inline sp::io::DataBuffer& operator << (sp::io::DataBuffer& packet, const RadarTrace& rt) { return packet << rt.icon << rt.min_size << rt.max_size << rt.radius << rt.color << rt.rotate; } -static inline sp::io::DataBuffer& operator >> (sp::io::DataBuffer& packet, RadarTrace& rt) { return packet >> rt.icon >> rt.min_size >> rt.max_size >> rt.radius >> rt.color >> rt.rotate; } +static inline sp::io::DataBuffer& operator << (sp::io::DataBuffer& packet, const RadarTrace& rt) { return packet << rt.icon << rt.min_size << rt.max_size << rt.radius << rt.color << rt.flags; } +static inline sp::io::DataBuffer& operator >> (sp::io::DataBuffer& packet, RadarTrace& rt) { return packet >> rt.icon >> rt.min_size >> rt.max_size >> rt.radius >> rt.color >> rt.flags; } // Radar signature data, used by rawScannerDataOverlay. diff --git a/src/components/rendering.h b/src/components/rendering.h new file mode 100644 index 0000000000..757c79b078 --- /dev/null +++ b/src/components/rendering.h @@ -0,0 +1,19 @@ +#pragma once + +#include "io/dataBuffer.h" + +#include "graphics/texture.h" +#include "mesh.h" +#include "shaderRegistry.h" + + +class MeshRenderComponent +{ +public: + string mesh_name; + string texture_name; + string specular_texture_name; + string illumination_texture_name; + glm::vec3 mesh_offset{}; + float scale; +}; diff --git a/src/screenComponents/radarView.cpp b/src/screenComponents/radarView.cpp index 0aaf0bd287..be919e1a0f 100644 --- a/src/screenComponents/radarView.cpp +++ b/src/screenComponents/radarView.cpp @@ -693,10 +693,37 @@ void GuiRadarView::drawObjects(sp::RenderTarget& renderer) auto size = trace.radius * scale * 2.0f; size = std::clamp(size, trace.min_size, trace.max_size); - if (trace.rotate) - renderer.drawRotatedSprite(trace.icon, object_position_on_screen, size, obj->getRotation() - view_rotation, trace.color); + auto color = trace.color; + if (trace.flags & RadarTrace::ColorByFaction) { + if (factionInfo[obj->getFactionId()]) + color = factionInfo[obj->getFactionId()]->getGMColor(); + if (my_spaceship) + { + if (obj == *my_spaceship) + color = glm::u8vec4(192, 192, 255, 255); + else if (obj->getScannedStateFor(my_spaceship) == SS_NotScanned) + color = glm::u8vec4(192, 192, 192, 255); + else if (obj->isEnemy(my_spaceship)) + color = glm::u8vec4(255, 0, 0, 255); + else if (obj->isFriendly(my_spaceship)) + color = glm::u8vec4(128, 255, 128, 255); + else + color = glm::u8vec4(128, 128, 255, 255); + } + } + auto icon = trace.icon; + if (trace.flags & RadarTrace::ArrowIfNotScanned) + { + // If the object is a ship that hasn't been scanned, draw the default icon. + // Otherwise, draw the ship-specific icon. + if (my_spaceship && (obj->getScannedStateFor(my_spaceship) == SS_NotScanned || obj->getScannedStateFor(my_spaceship) == SS_FriendOrFoeIdentified)) + icon = "radar/arrow.png"; + } + + if (trace.flags & RadarTrace::Rotate) + renderer.drawRotatedSprite(icon, object_position_on_screen, size, obj->getRotation() - view_rotation, color); else - renderer.drawSprite(trace.icon, object_position_on_screen, size, trace.color); + renderer.drawSprite(icon, object_position_on_screen, size, color); } if (my_spaceship) diff --git a/src/spaceObjects/shipTemplateBasedObject.cpp b/src/spaceObjects/shipTemplateBasedObject.cpp index 7b2eeefa5d..967b652501 100644 --- a/src/spaceObjects/shipTemplateBasedObject.cpp +++ b/src/spaceObjects/shipTemplateBasedObject.cpp @@ -132,7 +132,6 @@ ShipTemplateBasedObject::ShipTemplateBasedObject(float collision_range, string m registerMemberReplication(&shield_max[n]); registerMemberReplication(&shield_hit_effect[n], 0.5); } - registerMemberReplication(&radar_trace); registerMemberReplication(&impulse_sound_file); registerMemberReplication(&hull_strength, 0.5); registerMemberReplication(&hull_max); @@ -376,7 +375,13 @@ void ShipTemplateBasedObject::setTemplate(string template_name) long_range_radar_range = ship_template->long_range_radar_range; short_range_radar_range = ship_template->short_range_radar_range; - radar_trace = ship_template->radar_trace; + if (entity) { + auto trace = entity.getOrAddComponent(); + trace.radius = getRadius(); + trace.icon = ship_template->radar_trace; + trace.flags |= RadarTrace::ColorByFaction; + } + impulse_sound_file = ship_template->impulse_sound_file; shares_energy_with_docked = ship_template->shares_energy_with_docked; @@ -417,6 +422,12 @@ ESystem ShipTemplateBasedObject::getShieldSystemForShieldIndex(int index) return SYS_RearShield; } +void ShipTemplateBasedObject::setRadarTrace(string trace) +{ + if (!entity) return; + entity.getOrAddComponent().icon = "radar/" + trace; +} + void ShipTemplateBasedObject::onTakingDamage(ScriptSimpleCallback callback) { this->on_taking_damage = callback; diff --git a/src/spaceObjects/shipTemplateBasedObject.h b/src/spaceObjects/shipTemplateBasedObject.h index 5355b9858a..64e53d42f9 100644 --- a/src/spaceObjects/shipTemplateBasedObject.h +++ b/src/spaceObjects/shipTemplateBasedObject.h @@ -20,7 +20,6 @@ class ShipTemplateBasedObject : public SpaceObject, public Updatable public: string template_name; string type_name; - string radar_trace; string impulse_sound_file; P ship_template; @@ -98,7 +97,7 @@ class ShipTemplateBasedObject : public SpaceObject, public Updatable void setLongRangeRadarRange(float range) { range = std::max(range, 100.0f); long_range_radar_range = range; short_range_radar_range = std::min(short_range_radar_range, range); } void setShortRangeRadarRange(float range) { range = std::max(range, 100.0f); short_range_radar_range = range; long_range_radar_range = std::max(long_range_radar_range, range); } - void setRadarTrace(string trace) { radar_trace = "radar/" + trace; } + void setRadarTrace(string trace); void setImpulseSoundFile(string sound) { impulse_sound_file = sound; } bool getSharesEnergyWithDocked() { return shares_energy_with_docked; } diff --git a/src/spaceObjects/spaceStation.cpp b/src/spaceObjects/spaceStation.cpp index d4d63e7e71..3b38d674f2 100644 --- a/src/spaceObjects/spaceStation.cpp +++ b/src/spaceObjects/spaceStation.cpp @@ -35,20 +35,6 @@ void SpaceStation::drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, f sprite_scale *= 0.7f; drawShieldsOnRadar(renderer, position, scale, rotation, sprite_scale, true); } - sprite_scale = std::max(0.15f, sprite_scale); - glm::u8vec4 color{255,255,255,255}; - if (factionInfo[getFactionId()]) - color = factionInfo[getFactionId()]->getGMColor(); - if (my_spaceship) - { - if (isEnemy(my_spaceship)) - color = glm::u8vec4(255, 0, 0, 255); - else if (isFriendly(my_spaceship)) - color = glm::u8vec4(128, 255, 128, 255); - else - color = glm::u8vec4(128, 128, 255, 255); - } - renderer.drawSprite(radar_trace, position, sprite_scale * 32, color); } void SpaceStation::applyTemplateValues() diff --git a/src/spaceObjects/spaceship.cpp b/src/spaceObjects/spaceship.cpp index b38ca792dc..59296889ce 100644 --- a/src/spaceObjects/spaceship.cpp +++ b/src/spaceObjects/spaceship.cpp @@ -147,10 +147,6 @@ REGISTER_SCRIPT_SUBCLASS_NO_CREATE(SpaceShip, ShipTemplateBasedObject) // Sets the load time for a tube // Example ship:setTubeLoadTime(0, 15) REGISTER_SCRIPT_CLASS_FUNCTION(SpaceShip, setTubeLoadTime); - /// Set the icon to be used for this ship on the radar. - /// For example, ship:setRadarTrace("blip.png") will show a dot instead of an arrow for this ship. - /// Note: Icon is only shown after scanning, before the ship is scanned it is always shown as an arrow. - REGISTER_SCRIPT_CLASS_FUNCTION(SpaceShip, setRadarTrace); /// Get the dynamic radar signature values for each component band. /// Returns a float. /// Example: obj:getDynamicRadarSignatureGravity() @@ -247,7 +243,6 @@ SpaceShip::SpaceShip(string multiplayerClassName, float multiplayer_significant_ registerMemberReplication(&combat_maneuver_strafe_active, 0.2f); registerMemberReplication(&combat_maneuver_boost_speed); registerMemberReplication(&combat_maneuver_strafe_speed); - registerMemberReplication(&radar_trace); for(unsigned int n=0; ngetNextShipCallsign()); + + if (entity) { + auto trace = entity.getOrAddComponent(); + trace.flags |= RadarTrace::ArrowIfNotScanned; + } } //due to a suspected compiler bug this deconstructor needs to be explicitly defined @@ -614,38 +614,6 @@ void SpaceShip::drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, floa drawShieldsOnRadar(renderer, position, scale, rotation, 1.f, false); } } - - // Set up the radar sprite for objects. - string object_sprite = radar_trace; - // If the object is a ship that hasn't been scanned, draw the default icon. - // Otherwise, draw the ship-specific icon. - if (my_spaceship && (getScannedStateFor(my_spaceship) == SS_NotScanned || getScannedStateFor(my_spaceship) == SS_FriendOrFoeIdentified)) - { - object_sprite = "radar/arrow.png"; - } - - glm::u8vec4 color; - if (my_spaceship == this) - { - color = glm::u8vec4(192, 192, 255, 255); - }else if (my_spaceship) - { - if (getScannedStateFor(my_spaceship) != SS_NotScanned) - { - if (isEnemy(my_spaceship)) - color = glm::u8vec4(255, 0, 0, 255); - else if (isFriendly(my_spaceship)) - color = glm::u8vec4(128, 255, 128, 255); - else - color = glm::u8vec4(128, 128, 255, 255); - }else{ - color = glm::u8vec4(192, 192, 192, 255); - } - }else{ - if (factionInfo[getFactionId()]) - color = factionInfo[getFactionId()]->getGMColor(); - } - renderer.drawRotatedSprite(object_sprite, position, long_range ? 22.f : 32.f, getRotation() - rotation, color); } void SpaceShip::drawOnGMRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) diff --git a/src/spaceObjects/spaceship.h b/src/spaceObjects/spaceship.h index de26bbe831..8405cde949 100644 --- a/src/spaceObjects/spaceship.h +++ b/src/spaceObjects/spaceship.h @@ -499,8 +499,6 @@ class SpaceShip : public ShipTemplateBasedObject void setTubeLoadTime(int index, float time); float getTubeLoadTime(int index); - void setRadarTrace(string trace) { radar_trace = "radar/" + trace; } - void addBroadcast(int threshold, string message); // Return a string that can be appended to an object create function in the lua scripting. From e7cb6b527009eb1fd8df932185e0fdbf308380f4 Mon Sep 17 00:00:00 2001 From: Daid Date: Fri, 4 Nov 2022 10:41:33 +0100 Subject: [PATCH 009/320] WIP --- src/components/radar.h | 3 ++- src/modelData.cpp | 2 +- src/screenComponents/radarView.cpp | 6 +++-- src/spaceObjects/asteroid.cpp | 23 ++++++++++---------- src/spaceObjects/asteroid.h | 2 -- src/spaceObjects/mine.cpp | 18 +++++++++------ src/spaceObjects/mine.h | 1 - src/spaceObjects/missiles/hvli.cpp | 2 +- src/spaceObjects/shipTemplateBasedObject.cpp | 5 +++-- src/spaceObjects/spaceStation.cpp | 2 ++ src/spaceObjects/spaceship.cpp | 2 +- 11 files changed, 37 insertions(+), 29 deletions(-) diff --git a/src/components/radar.h b/src/components/radar.h index f75153c1d7..75cc2e6afa 100644 --- a/src/components/radar.h +++ b/src/components/radar.h @@ -1,6 +1,7 @@ #pragma once #include "io/dataBuffer.h" +#include "multiplayer.h" class RadarTrace { @@ -12,7 +13,7 @@ class RadarTrace string icon; float min_size = 8.0; //Size in screen "pixels" float max_size = 256.0; //Size in screen "pixels" - float radius; // Size in world "units" + float radius = 0.0; // Size in world "units" glm::u8vec4 color{255,255,255,255}; uint32_t flags = Rotate; diff --git a/src/modelData.cpp b/src/modelData.cpp index 89980e2359..54dafb93eb 100644 --- a/src/modelData.cpp +++ b/src/modelData.cpp @@ -125,7 +125,7 @@ void ModelData::setCollisionData(P object) { object->setRadius(radius); if (collision_box.x > 0 && collision_box.y > 0) { - auto physics = object->entity.getOrAddComponent(); + auto& physics = object->entity.getOrAddComponent(); physics.setRectangle(physics.getType(), collision_box); } } diff --git a/src/screenComponents/radarView.cpp b/src/screenComponents/radarView.cpp index be919e1a0f..e8846abd4d 100644 --- a/src/screenComponents/radarView.cpp +++ b/src/screenComponents/radarView.cpp @@ -2,6 +2,7 @@ #include "ecs/query.h" #include "systems/collision.h" +#include "components/collision.h" #include "main.h" #include "gameGlobalInfo.h" #include "spaceObjects/nebula.h" @@ -687,8 +688,9 @@ void GuiRadarView::drawObjects(sp::RenderTarget& renderer) draw_object(obj); } - for(auto [entity, trace, obj] : sp::ecs::Query()) { - auto object_position_on_screen = worldToScreen(obj->getPosition()); + for(auto [entity, trace, position, obj] : sp::ecs::Query()) { + auto object_position_on_screen = worldToScreen(position.getPosition()); + //TODO: Only draw things that are in range of this radar view. auto size = trace.radius * scale * 2.0f; size = std::clamp(size, trace.min_size, trace.max_size); diff --git a/src/spaceObjects/asteroid.cpp b/src/spaceObjects/asteroid.cpp index 61b901f356..4478d2b355 100644 --- a/src/spaceObjects/asteroid.cpp +++ b/src/spaceObjects/asteroid.cpp @@ -1,5 +1,6 @@ #include #include +#include "components/radar.h" #include "asteroid.h" #include "explosionEffect.h" #include "main.h" @@ -40,6 +41,14 @@ Asteroid::Asteroid() registerMemberReplication(&size); PathPlannerManager::getInstance()->addAvoidObject(this, 300); + + if (entity) { + auto& trace = entity.getOrAddComponent(); + trace.icon = "radar/blip.png"; + trace.radius = getRadius(); + trace.color = glm::u8vec4(255, 200, 100, 255); + trace.flags = 0; + } } void Asteroid::draw3D() @@ -70,17 +79,6 @@ void Asteroid::draw3D() glActiveTexture(GL_TEXTURE0); } -void Asteroid::drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) -{ - if (size != getRadius()) - setRadius(size); - - float size = getRadius() * scale / 64.0f; - if (size < 0.2f) - size = 0.2f; - renderer.drawSprite("radar/blip.png", position, size * 32.0f, glm::u8vec4(255, 200, 100, 255)); -} - void Asteroid::collide(SpaceObject* target, float force) { if (!isServer()) @@ -103,6 +101,9 @@ void Asteroid::setSize(float size) { this->size = size; setRadius(size); + auto trace = entity.getComponent(); + if (trace) + trace->radius = size; } float Asteroid::getSize() diff --git a/src/spaceObjects/asteroid.h b/src/spaceObjects/asteroid.h index 9c65784cc9..36de90dcd1 100644 --- a/src/spaceObjects/asteroid.h +++ b/src/spaceObjects/asteroid.h @@ -15,8 +15,6 @@ class Asteroid : public SpaceObject virtual void draw3D() override; - virtual void drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) override; - virtual void collide(SpaceObject* target, float force) override; void setSize(float size); diff --git a/src/spaceObjects/mine.cpp b/src/spaceObjects/mine.cpp index bcfd184214..187eea2096 100644 --- a/src/spaceObjects/mine.cpp +++ b/src/spaceObjects/mine.cpp @@ -7,6 +7,7 @@ #include "random.h" #include "multiplayer_server.h" #include "components/collision.h" +#include "components/radar.h" #include "scriptInterface.h" @@ -26,8 +27,10 @@ REGISTER_MULTIPLAYER_CLASS(Mine, "Mine"); Mine::Mine() : SpaceObject(50, "Mine"), data(MissileWeaponData::getDataFor(MW_Mine)) { - auto physics = entity.getOrAddComponent(); - physics.setCircle(sp::Physics::Type::Sensor, trigger_range); + if (entity) { + auto& physics = entity.getOrAddComponent(); + physics.setCircle(sp::Physics::Type::Sensor, trigger_range); + } triggered = false; triggerTimeout = triggerDelay; ejectTimeout = 0.0; @@ -35,6 +38,12 @@ Mine::Mine() setRadarSignatureInfo(0.0, 0.05, 0.0); PathPlannerManager::getInstance()->addAvoidObject(this, blastRange * 1.2f); + if (entity) { + auto& trace = entity.getOrAddComponent(); + trace.icon = "radar/blip.png"; + trace.min_size = 10; + trace.max_size = 10; + } } Mine::~Mine() @@ -49,11 +58,6 @@ void Mine::draw3DTransparent() { } -void Mine::drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) -{ - renderer.drawSprite("radar/blip.png", position, 0.3 * 32); -} - void Mine::drawOnGMRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) { renderer.drawCircleOutline(position, trigger_range * scale, 3.0, triggered ? glm::u8vec4(255, 0, 0, 128) : glm::u8vec4(255, 255, 255, 128)); diff --git a/src/spaceObjects/mine.h b/src/spaceObjects/mine.h index 9680717d3d..1c54804b1a 100644 --- a/src/spaceObjects/mine.h +++ b/src/spaceObjects/mine.h @@ -25,7 +25,6 @@ class Mine : public SpaceObject, public Updatable virtual void draw3D() override; virtual void draw3DTransparent() override; - virtual void drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) override; virtual void drawOnGMRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) override; virtual void update(float delta) override; diff --git a/src/spaceObjects/missiles/hvli.cpp b/src/spaceObjects/missiles/hvli.cpp index ebc60a9015..fac07bbfb5 100644 --- a/src/spaceObjects/missiles/hvli.cpp +++ b/src/spaceObjects/missiles/hvli.cpp @@ -14,7 +14,7 @@ HVLI::HVLI() : MissileWeapon("HVLI", MissileWeaponData::getDataFor(MW_HVLI)) { setRadarSignatureInfo(0.1, 0.0, 0.0); - auto physics = entity.getOrAddComponent(); + auto& physics = entity.getOrAddComponent(); physics.setRectangle(sp::Physics::Type::Sensor, {10, 30}); // Make it a bit harder to the HVLI to phase trough smaller enemies } diff --git a/src/spaceObjects/shipTemplateBasedObject.cpp b/src/spaceObjects/shipTemplateBasedObject.cpp index 967b652501..2734a9af1c 100644 --- a/src/spaceObjects/shipTemplateBasedObject.cpp +++ b/src/spaceObjects/shipTemplateBasedObject.cpp @@ -376,9 +376,10 @@ void ShipTemplateBasedObject::setTemplate(string template_name) short_range_radar_range = ship_template->short_range_radar_range; if (entity) { - auto trace = entity.getOrAddComponent(); - trace.radius = getRadius(); + auto& trace = entity.getOrAddComponent(); + trace.radius = ship_template->model_data->getRadius() * 0.8f; trace.icon = ship_template->radar_trace; + trace.max_size = 1024; trace.flags |= RadarTrace::ColorByFaction; } diff --git a/src/spaceObjects/spaceStation.cpp b/src/spaceObjects/spaceStation.cpp index 3b38d674f2..c82f5971a9 100644 --- a/src/spaceObjects/spaceStation.cpp +++ b/src/spaceObjects/spaceStation.cpp @@ -2,6 +2,7 @@ #include "spaceObjects/spaceStation.h" #include "spaceObjects/spaceship.h" #include "spaceObjects/playerSpaceship.h" +#include "components/collision.h" #include "shipTemplate.h" #include "playerInfo.h" #include "factionInfo.h" @@ -24,6 +25,7 @@ SpaceStation::SpaceStation() setRadarSignatureInfo(0.2, 0.5, 0.5); callsign = "DS" + string(getMultiplayerId()); + entity.getOrAddComponent().setCircle(sp::Physics::Type::Static, 300); } void SpaceStation::drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) diff --git a/src/spaceObjects/spaceship.cpp b/src/spaceObjects/spaceship.cpp index 59296889ce..cb224b96f5 100644 --- a/src/spaceObjects/spaceship.cpp +++ b/src/spaceObjects/spaceship.cpp @@ -295,7 +295,7 @@ SpaceShip::SpaceShip(string multiplayerClassName, float multiplayer_significant_ setCallSign(gameGlobalInfo->getNextShipCallsign()); if (entity) { - auto trace = entity.getOrAddComponent(); + auto& trace = entity.getOrAddComponent(); trace.flags |= RadarTrace::ArrowIfNotScanned; } } From 11b94071c942295c5a5057e21a3a617255cbb645 Mon Sep 17 00:00:00 2001 From: Daid Date: Fri, 4 Nov 2022 17:22:25 +0100 Subject: [PATCH 010/320] WIP: Docking ECS --- CMakeLists.txt | 3 + src/ai/ai.cpp | 58 +++--- src/components/docking.h | 50 ++++++ src/gameStateLogger.cpp | 2 + src/hardware/hardwareController.cpp | 4 +- src/main.cpp | 2 + src/screenComponents/dockingButton.cpp | 87 +++++---- src/screens/gm/gameMasterScreen.cpp | 4 +- src/spaceObjects/cpuShip.cpp | 33 ---- src/spaceObjects/playerSpaceship.cpp | 47 +---- src/spaceObjects/playerSpaceship.h | 6 +- src/spaceObjects/shipTemplateBasedObject.cpp | 25 ++- src/spaceObjects/shipTemplateBasedObject.h | 22 +-- src/spaceObjects/spaceObject.h | 9 - src/spaceObjects/spaceStation.cpp | 20 +-- src/spaceObjects/spaceStation.h | 1 - src/spaceObjects/spaceship.cpp | 169 ++++++------------ src/spaceObjects/spaceship.h | 20 +-- .../spaceshipParts/beamWeapon.cpp | 3 +- .../spaceshipParts/weaponTube.cpp | 4 +- src/systems/docking.cpp | 149 +++++++++++++++ src/systems/docking.h | 9 + 22 files changed, 407 insertions(+), 320 deletions(-) create mode 100644 src/components/docking.h create mode 100644 src/systems/docking.cpp create mode 100644 src/systems/docking.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b67f9c3b5f..5c70e0abcc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -355,6 +355,9 @@ set(MAIN_SOURCES src/spaceObjects/spaceshipParts/weaponTube.cpp src/components/radar.h src/components/rendering.h + src/components/docking.h + src/systems/docking.h + src/systems/docking.cpp src/ai/fighterAI.cpp src/ai/ai.cpp src/ai/aiFactory.cpp diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp index 2b388248ac..2468362644 100644 --- a/src/ai/ai.cpp +++ b/src/ai/ai.cpp @@ -4,7 +4,10 @@ #include "ai/ai.h" #include "ai/aiFactory.h" #include "random.h" +#include "components/docking.h" #include "systems/collision.h" +#include "ecs/query.h" + REGISTER_SHIP_AI(ShipAI, "default"); @@ -361,6 +364,7 @@ void ShipAI::runOrders() // Update ranges before calculating long_range = owner->getLongRangeRadarRange(); relay_range = long_range * 2.0f; + auto docking_port = owner->entity.getComponent(); //When we are not attacking a target, follow orders switch(owner->getOrder()) @@ -446,24 +450,26 @@ void ShipAI::runOrders() pathPlanner.clear(); break; case AI_Retreat: - if ((owner->docking_state == DS_Docked) && (owner->getOrderTarget()) && P(owner->getOrderTarget())) + if ((docking_port && docking_port->state == DockingPort::State::Docked && docking_port->target) && (owner->getOrderTarget()) && P(owner->getOrderTarget())) { - P target = owner->getOrderTarget(); + auto bay = docking_port->target.getComponent(); bool allow_undock = true; - if (target->restocks_missiles_docked) - { - for(int n = 0; n < MW_Count; n++) + if (bay) { + if (bay->flags & DockingBay::RestockMissiles) { - if (owner->weapon_storage[n] < owner->weapon_storage_max[n]) + for(int n = 0; n < MW_Count; n++) { - allow_undock = false; - break; + if (owner->weapon_storage[n] < owner->weapon_storage_max[n]) + { + allow_undock = false; + break; + } } } - } - if (allow_undock && target->repair_docked && (owner->hull_strength < owner->hull_max)) - { - allow_undock = false; + if ((bay->flags & DockingBay::Repair) && (owner->hull_strength < owner->hull_max)) + { + allow_undock = false; + } } if (allow_undock) { @@ -479,9 +485,9 @@ void ShipAI::runOrders() } [[fallthrough]]; // continue with docking or roaming case AI_Dock: //Dock with [order_target] - if (owner->getOrderTarget()) + if (owner->getOrderTarget() && docking_port) { - if (owner->docking_state == DS_NotDocking || owner->docking_target != owner->getOrderTarget()) + if (docking_port->state == DockingPort::State::NotDocking || docking_port->target != owner->getOrderTarget()->entity) { auto target_position = owner->getOrderTarget()->getPosition(); auto diff = owner->getPosition() - target_position; @@ -557,7 +563,8 @@ void ShipAI::flyTowards(glm::vec2 target, float keep_distance) if (pathPlanner.route.size() > 0) { - if (owner->docking_state == DS_Docked) + auto docking_port = owner->entity.getComponent(); + if (docking_port && docking_port->state == DockingPort::State::Docked) owner->requestUndock(); auto diff = pathPlanner.route[0] - owner->getPosition(); @@ -617,7 +624,8 @@ void ShipAI::flyFormation(P target, glm::vec2 offset) if (pathPlanner.route.size() == 1) { - if (owner->docking_state == DS_Docked) + auto docking_port = owner->entity.getComponent(); + if (docking_port && docking_port->state == DockingPort::State::Docked) owner->requestUndock(); auto diff = target_position - owner->getPosition(); @@ -822,26 +830,26 @@ float ShipAI::calculateFiringSolution(P target, int tube_index) P ShipAI::findBestMissileRestockTarget(glm::vec2 position, float radius) { + auto port = owner->entity.getComponent(); + if (!port) + return nullptr; // Check each object within the given radius. If it's friendly, we can dock // to it, and it can restock our missiles, then select it. float target_score = 0.0; P target; auto owner_position = owner->getPosition(); - for(auto entity : sp::CollisionSystem::queryArea(position - glm::vec2(radius, radius), position + glm::vec2(radius, radius))) + for(auto [entity, dockingbay, obj] : sp::ecs::Query()) { - auto ptr = entity.getComponent(); - if (!ptr || !*ptr) continue; - P space_object = *ptr; - if (!space_object || !owner->isFriendly(space_object) || space_object == target) + if (!obj || !owner->isFriendly(obj) || obj == *target) continue; - if (space_object->canBeDockedBy(owner) == DockStyle::None || !space_object->canRestockMissiles()) + if (port->canDockOn(dockingbay) == DockingStyle::None || !(dockingbay.flags & DockingBay::RestockMissiles)) continue; //calculate score - auto position_difference = space_object->getPosition() - owner_position; + auto position_difference = obj->getPosition() - owner_position; float distance = glm::length(position_difference); float angle_difference = angleDifference(owner->getRotation(), vec2ToAngle(position_difference)); float score = -distance - std::abs(angle_difference / owner->turn_speed * owner->impulse_max_speed) * 1.5f; - if (P(space_object)) + if (P(P(obj))) { score -= 5000; } @@ -849,7 +857,7 @@ P ShipAI::findBestMissileRestockTarget(glm::vec2 position, float ra continue; if (!target || score > target_score) { - target = space_object; + target = obj; target_score = score; } } diff --git a/src/components/docking.h b/src/components/docking.h new file mode 100644 index 0000000000..f8e8ede9fe --- /dev/null +++ b/src/components/docking.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include "io/dataBuffer.h" +#include "multiplayer.h" + +// Component that indicates things can dock to this. +enum class DockingStyle { + None, External, Internal, +}; + +class DockingBay +{ +public: + static constexpr uint32_t ShareEnergy = 1 << 0; + static constexpr uint32_t Repair = 1 << 1; + static constexpr uint32_t ChargeShield = 1 << 2; // Increased shield recharge rate + static constexpr uint32_t RestockProbes = 1 << 3; + static constexpr uint32_t RestockMissiles = 1 << 4; // Only for AI controlled ships. Players use the comms system. + + std::unordered_set external_dock_classes; + std::unordered_set internal_dock_classes; + + uint32_t flags = 0; +}; + +// Component to indicate that we can do to things. +class DockingPort +{ +public: + string dock_class; + string dock_subclass; + + enum class State { + NotDocking = 0, + Docking, + Docked + } state = State::NotDocking; + + sp::ecs::Entity target; + glm::vec2 docked_offset; + + DockingStyle canDockOn(DockingBay& bay) { + if (bay.external_dock_classes.find(dock_class) != bay.external_dock_classes.end()) return DockingStyle::External; + if (bay.external_dock_classes.find(dock_subclass) != bay.external_dock_classes.end()) return DockingStyle::External; + if (bay.internal_dock_classes.find(dock_class) != bay.internal_dock_classes.end()) return DockingStyle::Internal; + if (bay.internal_dock_classes.find(dock_subclass) != bay.internal_dock_classes.end()) return DockingStyle::Internal; + return DockingStyle::None; + } +}; \ No newline at end of file diff --git a/src/gameStateLogger.cpp b/src/gameStateLogger.cpp index 009cb8620a..9e0a1ee092 100644 --- a/src/gameStateLogger.cpp +++ b/src/gameStateLogger.cpp @@ -314,6 +314,7 @@ void GameStateLogger::writeShipEntry(JSONGenerator& json, P ship) json.write("hull", ship->hull_strength); if (ship->target_id > -1) json.write("target", ship->target_id); + /* if (ship->docking_state != DS_NotDocking && ship->docking_target) { if (ship->docking_state == DS_Docking) @@ -321,6 +322,7 @@ void GameStateLogger::writeShipEntry(JSONGenerator& json, P ship) if (ship->docking_state == DS_Docked) json.write("docked", ship->docking_target->getMultiplayerId()); } + */ if (ship->shield_count > 0) { if (gameGlobalInfo->use_beam_shield_frequencies) diff --git a/src/hardware/hardwareController.cpp b/src/hardware/hardwareController.cpp index ffcaf7974c..bfb3ce90c1 100644 --- a/src/hardware/hardwareController.cpp +++ b/src/hardware/hardwareController.cpp @@ -373,8 +373,8 @@ bool HardwareController::getVariableValue(string variable_name, float& value) SHIP_VARIABLE("ShieldsUp", ship->shields_active ? 1.0f : 0.0f); SHIP_VARIABLE("Impulse", ship->current_impulse * ship->getSystemEffectiveness(SYS_Impulse)); SHIP_VARIABLE("Warp", ship->current_warp * ship->getSystemEffectiveness(SYS_Warp)); - SHIP_VARIABLE("Docking", ship->docking_state == DS_Docking ? 1.0f : 0.0f); - SHIP_VARIABLE("Docked", ship->docking_state == DS_Docked ? 1.0f : 0.0f); + //SHIP_VARIABLE("Docking", ship->docking_state == DS_Docking ? 1.0f : 0.0f); + //SHIP_VARIABLE("Docked", ship->docking_state == DS_Docked ? 1.0f : 0.0f); SHIP_VARIABLE("InNebula", Nebula::inNebula(ship->getPosition()) ? 1.0f : 0.0f); SHIP_VARIABLE("IsJammed", WarpJammer::isWarpJammed(ship->getPosition()) ? 1.0f : 0.0f); SHIP_VARIABLE("Jumping", ship->jump_delay > 0.0f ? 1.0f : 0.0f); diff --git a/src/main.cpp b/src/main.cpp index d0d111f486..145f9597e2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,6 +27,7 @@ #include "factionInfo.h" #include "gameGlobalInfo.h" #include "spaceObjects/spaceObject.h" +#include "systems/docking.h" #include "packResourceProvider.h" #include "main.h" #include "epsilonServer.h" @@ -133,6 +134,7 @@ int main(int argc, char** argv) #endif LOG(Info, "Starting..."); new Engine(); + engine->registerSystem(); string configuration_path = "."; if (getenv("HOME")) configuration_path = string(getenv("HOME")) + "/.emptyepsilon"; diff --git a/src/screenComponents/dockingButton.cpp b/src/screenComponents/dockingButton.cpp index ac7c8536b0..bea30542e0 100644 --- a/src/screenComponents/dockingButton.cpp +++ b/src/screenComponents/dockingButton.cpp @@ -3,6 +3,8 @@ #include "spaceObjects/playerSpaceship.h" #include "dockingButton.h" #include "systems/collision.h" +#include "components/collision.h" +#include "ecs/query.h" GuiDockingButton::GuiDockingButton(GuiContainer* owner, string id) @@ -13,17 +15,19 @@ GuiDockingButton::GuiDockingButton(GuiContainer* owner, string id) void GuiDockingButton::click() { - if (!my_spaceship) - return; - switch(my_spaceship->docking_state) + if (!my_spaceship) { return; } + auto port = my_spaceship->entity.getComponent(); + if (!port) { return; } + + switch(port->state) { - case DS_NotDocking: + case DockingPort::State::NotDocking: my_spaceship->commandDock(findDockingTarget()); break; - case DS_Docking: + case DockingPort::State::Docking: my_spaceship->commandAbortDock(); break; - case DS_Docked: + case DockingPort::State::Docked: my_spaceship->commandUndock(); break; } @@ -31,21 +35,23 @@ void GuiDockingButton::click() void GuiDockingButton::onUpdate() { - setVisible(my_spaceship && my_spaceship->getCanDock()); + if (!my_spaceship) { hide(); return; } + auto port = my_spaceship->entity.getComponent(); + if (!port) { hide(); return; } - if (my_spaceship && isVisible()) + if (isVisible()) { if (keys.helms_dock_action.getDown()) { - switch(my_spaceship->docking_state) + switch(port->state) { - case DS_NotDocking: + case DockingPort::State::NotDocking: my_spaceship->commandDock(findDockingTarget()); break; - case DS_Docking: + case DockingPort::State::Docking: my_spaceship->commandAbortDock(); break; - case DS_Docked: + case DockingPort::State::Docked: my_spaceship->commandUndock(); break; } @@ -61,43 +67,50 @@ void GuiDockingButton::onUpdate() void GuiDockingButton::onDraw(sp::RenderTarget& renderer) { - if (my_spaceship) + if (!my_spaceship) { return; } + auto port = my_spaceship->entity.getComponent(); + if (!port) { return; } + + switch(port->state) { - switch(my_spaceship->docking_state) + case DockingPort::State::NotDocking: + setText(tr("Request Dock")); + if (my_spaceship->canStartDocking() && findDockingTarget()) { - case DS_NotDocking: - setText(tr("Request Dock")); - if (my_spaceship->canStartDocking() && findDockingTarget()) - { - enable(); - }else{ - disable(); - } - break; - case DS_Docking: - setText(tr("Cancel Docking")); - enable(); - break; - case DS_Docked: - setText(tr("Undock")); enable(); - break; + }else{ + disable(); } + break; + case DockingPort::State::Docking: + setText(tr("Cancel Docking")); + enable(); + break; + case DockingPort::State::Docked: + setText(tr("Undock")); + enable(); + break; } + GuiButton::onDraw(renderer); } P GuiDockingButton::findDockingTarget() { + if (!my_spaceship) { return nullptr; } + auto port = my_spaceship->entity.getComponent(); + if (!port) { return nullptr; } + P dock_object; - for(auto entity : sp::CollisionSystem::queryArea(my_spaceship->getPosition() - glm::vec2(1000, 1000), my_spaceship->getPosition() + glm::vec2(1000, 1000))) + for(auto [entity, bay, position, physics, obj] : sp::ecs::Query()) { - auto ptr = entity.getComponent(); - if (!ptr || !*ptr) continue; - dock_object = *ptr; - if (dock_object && dock_object != my_spaceship && dock_object->canBeDockedBy(my_spaceship) != DockStyle::None && glm::length(dock_object->getPosition() - my_spaceship->getPosition()) < 1000.0f + dock_object->getRadius()) - break; - dock_object = NULL; + if (obj == *my_spaceship) continue; + if (obj->isEnemy(my_spaceship)) continue; + if (port->canDockOn(bay) == DockingStyle::None) continue; + if (glm::length(position.getPosition() - my_spaceship->getPosition()) > 1000.0f + physics.getSize().x) continue; + + dock_object = obj; + break; } return dock_object; } diff --git a/src/screens/gm/gameMasterScreen.cpp b/src/screens/gm/gameMasterScreen.cpp index 87707d0690..e8d6f6796e 100644 --- a/src/screens/gm/gameMasterScreen.cpp +++ b/src/screens/gm/gameMasterScreen.cpp @@ -526,7 +526,9 @@ void GameMasterScreen::onMouseUp(glm::vec2 position) { cpu_ship->orderAttack(target); }else{ - if (!shift_down && target->canBeDockedBy(cpu_ship) != DockStyle::None) + auto port = cpu_ship->entity.getComponent(); + auto bay = target->entity.getComponent(); + if (!shift_down && port && bay && port->canDockOn(*bay) != DockingStyle::None) cpu_ship->orderDock(target); else cpu_ship->orderDefendTarget(target); diff --git a/src/spaceObjects/cpuShip.cpp b/src/spaceObjects/cpuShip.cpp index c272cb0924..c6c53ff107 100644 --- a/src/spaceObjects/cpuShip.cpp +++ b/src/spaceObjects/cpuShip.cpp @@ -105,7 +105,6 @@ CpuShip::CpuShip() setRotation(random(0, 360)); target_rotation = getRotation(); - restocks_missiles_docked = true; comms_script_name = "comms_ship.lua"; missile_resupply = 0.0; @@ -139,36 +138,6 @@ void CpuShip::update(float delta) } if (ai) ai->run(delta); - - //recharge missiles of CPU ships docked to station. Can be disabled setting the restocks_missiles_docked flag to false. - if (docking_state == DS_Docked) - { - P docked_with_template_based = docking_target; - P docked_with_ship = docking_target; - - if (docked_with_template_based && docked_with_template_based->restocks_missiles_docked) - { - bool needs_missile = 0; - - for(int n=0; n= missile_resupply_time) - { - weapon_storage[n] += 1; - missile_resupply = 0.0; - break; - } - else - needs_missile = 1; - } - } - - if (needs_missile) - missile_resupply += delta; - } - } } void CpuShip::applyTemplateValues() @@ -297,8 +266,6 @@ void CpuShip::orderDock(P object) void CpuShip::drawOnGMRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) { - if (docked_style == DockStyle::Internal) return; - SpaceShip::drawOnGMRadar(renderer, position, scale, rotation, long_range); if (game_server && ai) ai->drawOnGMRadar(renderer, position, scale); diff --git a/src/spaceObjects/playerSpaceship.cpp b/src/spaceObjects/playerSpaceship.cpp index 00967c5cdd..94457bec24 100644 --- a/src/spaceObjects/playerSpaceship.cpp +++ b/src/spaceObjects/playerSpaceship.cpp @@ -347,7 +347,6 @@ PlayerSpaceship::PlayerSpaceship() updateMemberReplicationUpdateDelay(&target_rotation, 0.1); registerMemberReplication(&can_scan); registerMemberReplication(&can_hack); - registerMemberReplication(&can_dock); registerMemberReplication(&can_combat_maneuver); registerMemberReplication(&can_self_destruct); registerMemberReplication(&can_launch_probe); @@ -458,45 +457,6 @@ void PlayerSpaceship::update(float delta) shield_calibration_delay -= delta * (getSystemEffectiveness(SYS_FrontShield) + getSystemEffectiveness(SYS_RearShield)) / 2.0f; } - // Docking actions. - if (docking_state == DS_Docked) - { - P docked_with_template_based = docking_target; - P docked_with_ship = docking_target; - - // Derive a base energy request rate from the player ship's maximum - // energy capacity. - float energy_request = std::min(delta * 10.0f, max_energy_level - energy_level); - - // If we're docked with a shipTemplateBasedObject, and that object is - // set to share its energy with docked ships, transfer energy from the - // mothership to docked ships until the mothership runs out of energy - // or the docked ship doesn't require any. - if (docked_with_template_based && docked_with_template_based->shares_energy_with_docked) - { - if (!docked_with_ship || docked_with_ship->useEnergy(energy_request)) - energy_level += energy_request; - } - - // If a shipTemplateBasedObject and is allowed to restock - // scan probes with docked ships. - if (docked_with_template_based && docked_with_template_based->restocks_scan_probes) - { - if (scan_probe_stock < max_scan_probes) - { - scan_probe_recharge += delta; - - if (scan_probe_recharge > scan_probe_charge_time) - { - scan_probe_stock += 1; - scan_probe_recharge = 0.0; - } - } - } - }else{ - scan_probe_recharge = 0.0; - } - // Automate cooling if auto_coolant_enabled is true. Distributes coolant to // subsystems proportionally to their share of the total generated heat. if (auto_coolant_enabled) @@ -749,7 +709,6 @@ void PlayerSpaceship::applyTemplateValues() // Set the ship's capabilities. can_scan = ship_template->can_scan; can_hack = ship_template->can_hack; - can_dock = ship_template->can_dock; can_combat_maneuver = ship_template->can_combat_maneuver; can_self_destruct = ship_template->can_self_destruct; can_launch_probe = ship_template->can_launch_probe; @@ -2023,8 +1982,6 @@ void PlayerSpaceship::onReceiveServerCommand(sp::io::DataBuffer& packet) void PlayerSpaceship::drawOnGMRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) { - if (docked_style == DockStyle::Internal) return; - SpaceShip::drawOnGMRadar(renderer, position, scale, rotation, long_range); if (long_range) @@ -2051,8 +2008,8 @@ string PlayerSpaceship::getExportLine() result += ":setCanScan(" + string(can_scan, true) + ")"; if (can_hack != ship_template->can_hack) result += ":setCanHack(" + string(can_hack, true) + ")"; - if (can_dock != ship_template->can_dock) - result += ":setCanDock(" + string(can_dock, true) + ")"; + //if (can_dock != ship_template->can_dock) + // result += ":setCanDock(" + string(can_dock, true) + ")"; if (can_combat_maneuver != ship_template->can_combat_maneuver) result += ":setCanCombatManeuver(" + string(can_combat_maneuver, true) + ")"; if (can_self_destruct != ship_template->can_self_destruct) diff --git a/src/spaceObjects/playerSpaceship.h b/src/spaceObjects/playerSpaceship.h index f691272a09..ee76fbfd56 100644 --- a/src/spaceObjects/playerSpaceship.h +++ b/src/spaceObjects/playerSpaceship.h @@ -134,8 +134,6 @@ class PlayerSpaceship : public SpaceShip // Capable of hacking a target bool can_hack = true; - // Capable of docking with a target - bool can_dock = true; // Capable of combat maneuvers bool can_combat_maneuver = true; @@ -207,8 +205,8 @@ class PlayerSpaceship : public SpaceShip bool getCanScan() { return can_scan; } void setCanHack(bool enabled) { can_hack = enabled; } bool getCanHack() { return can_hack; } - void setCanDock(bool enabled) { can_dock = enabled; } - bool getCanDock() { return can_dock; } + void setCanDock(bool enabled); + bool getCanDock(); void setCanCombatManeuver(bool enabled) { can_combat_maneuver = enabled; } bool getCanCombatManeuver() { return can_combat_maneuver; } void setCanSelfDestruct(bool enabled) { can_self_destruct = enabled; } diff --git a/src/spaceObjects/shipTemplateBasedObject.cpp b/src/spaceObjects/shipTemplateBasedObject.cpp index 2734a9af1c..4b967f043a 100644 --- a/src/spaceObjects/shipTemplateBasedObject.cpp +++ b/src/spaceObjects/shipTemplateBasedObject.cpp @@ -2,6 +2,7 @@ #include "scriptInterface.h" #include "components/collision.h" +#include "components/docking.h" #include "tween.h" #include "i18n.h" @@ -381,13 +382,31 @@ void ShipTemplateBasedObject::setTemplate(string template_name) trace.icon = ship_template->radar_trace; trace.max_size = 1024; trace.flags |= RadarTrace::ColorByFaction; + + if (!ship_template->external_dock_classes.empty()) + entity.getOrAddComponent().external_dock_classes = ship_template->external_dock_classes; + if (!ship_template->internal_dock_classes.empty()) + entity.getOrAddComponent().external_dock_classes = ship_template->internal_dock_classes; + + auto bay = entity.getComponent(); + if (bay) { + if (ship_template->shares_energy_with_docked) + bay->flags |= DockingBay::ShareEnergy; + if (ship_template->repair_docked) + bay->flags |= DockingBay::Repair; + } + + + if (ship_template->can_dock) { + if (!ship_template->getClass().empty()) + entity.getOrAddComponent().dock_class = ship_template->getClass(); + if (!ship_template->getSubClass().empty()) + entity.getOrAddComponent().dock_subclass = ship_template->getSubClass(); + } } impulse_sound_file = ship_template->impulse_sound_file; - shares_energy_with_docked = ship_template->shares_energy_with_docked; - repair_docked = ship_template->repair_docked; - ship_template->setCollisionData(this); model_info.setData(ship_template->model_data); diff --git a/src/spaceObjects/shipTemplateBasedObject.h b/src/spaceObjects/shipTemplateBasedObject.h index 64e53d42f9..8e64947fb6 100644 --- a/src/spaceObjects/shipTemplateBasedObject.h +++ b/src/spaceObjects/shipTemplateBasedObject.h @@ -30,11 +30,6 @@ class ShipTemplateBasedObject : public SpaceObject, public Updatable float shield_hit_effect[max_shield_count]; bool can_be_destroyed; - bool shares_energy_with_docked; //[config] - bool repair_docked; //[config] - bool restocks_scan_probes; - bool restocks_missiles_docked; //only restocks cpuships; playerships should use comms - ScriptSimpleCallback on_destruction; ScriptSimpleCallback on_taking_damage; public: @@ -45,7 +40,6 @@ class ShipTemplateBasedObject : public SpaceObject, public Updatable virtual void update(float delta) override; virtual std::unordered_map getGMInfo() override; - virtual bool canRestockMissiles() override { return restocks_missiles_docked; } virtual bool canBeTargetedBy(P other) override { return true; } virtual bool hasShield() override; virtual string getCallSign() override { return callsign; } @@ -100,14 +94,14 @@ class ShipTemplateBasedObject : public SpaceObject, public Updatable void setRadarTrace(string trace); void setImpulseSoundFile(string sound) { impulse_sound_file = sound; } - bool getSharesEnergyWithDocked() { return shares_energy_with_docked; } - void setSharesEnergyWithDocked(bool enabled) { shares_energy_with_docked = enabled; } - bool getRepairDocked() { return repair_docked; } - void setRepairDocked(bool enabled) { repair_docked = enabled; } - bool getRestocksScanProbes() { return restocks_scan_probes; } - void setRestocksScanProbes(bool enabled) { restocks_scan_probes = enabled; } - bool getRestocksMissilesDocked() { return restocks_missiles_docked; } - void setRestocksMissilesDocked(bool enabled) { restocks_missiles_docked = enabled; } + bool getSharesEnergyWithDocked(); + void setSharesEnergyWithDocked(bool enabled); + bool getRepairDocked(); + void setRepairDocked(bool enabled); + bool getRestocksScanProbes(); + void setRestocksScanProbes(bool enabled); + bool getRestocksMissilesDocked(); + void setRestocksMissilesDocked(bool enabled); void onTakingDamage(ScriptSimpleCallback callback); void onDestruction(ScriptSimpleCallback callback); diff --git a/src/spaceObjects/spaceObject.h b/src/spaceObjects/spaceObject.h index 2fb19ad453..d9f361e1f5 100644 --- a/src/spaceObjects/spaceObject.h +++ b/src/spaceObjects/spaceObject.h @@ -20,13 +20,6 @@ enum EDamageType DT_EMP }; -enum class DockStyle -{ - None, - External, - Internal, -}; - class DamageInfo { public: @@ -168,8 +161,6 @@ class SpaceObject : public MultiplayerObject virtual void setCallSign(string new_callsign) { callsign = new_callsign; } virtual string getCallSign() { return callsign; } - virtual DockStyle canBeDockedBy(P obj) { return DockStyle::None; } - virtual bool canRestockMissiles() { return false; } virtual bool hasShield() { return false; } virtual bool canHideInNebula() { return true; } virtual bool canBeTargetedBy(P other); diff --git a/src/spaceObjects/spaceStation.cpp b/src/spaceObjects/spaceStation.cpp index c82f5971a9..f75c45eae3 100644 --- a/src/spaceObjects/spaceStation.cpp +++ b/src/spaceObjects/spaceStation.cpp @@ -19,13 +19,17 @@ REGISTER_MULTIPLAYER_CLASS(SpaceStation, "SpaceStation"); SpaceStation::SpaceStation() : ShipTemplateBasedObject(300, "SpaceStation") { - restocks_scan_probes = true; - restocks_missiles_docked = true; comms_script_name = "comms_station.lua"; setRadarSignatureInfo(0.2, 0.5, 0.5); callsign = "DS" + string(getMultiplayerId()); - entity.getOrAddComponent().setCircle(sp::Physics::Type::Static, 300); + + if (entity) { + entity.getOrAddComponent().setCircle(sp::Physics::Type::Static, 300); + + auto& bay = entity.getOrAddComponent(); + bay.flags |= DockingBay::RestockMissiles | DockingBay::RestockProbes; + } } void SpaceStation::drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) @@ -70,16 +74,6 @@ void SpaceStation::destroyedByDamage(DamageInfo& info) } } -DockStyle SpaceStation::canBeDockedBy(P obj) -{ - if (isEnemy(obj)) - return DockStyle::None; - P ship = obj; - if (!ship) - return DockStyle::None; - return DockStyle::External; -} - string SpaceStation::getExportLine() { string ret = "SpaceStation()"; diff --git a/src/spaceObjects/spaceStation.h b/src/spaceObjects/spaceStation.h index d9c6078d9f..06900bd1cc 100644 --- a/src/spaceObjects/spaceStation.h +++ b/src/spaceObjects/spaceStation.h @@ -9,7 +9,6 @@ class SpaceStation : public ShipTemplateBasedObject SpaceStation(); virtual void drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) override; - virtual DockStyle canBeDockedBy(P obj) override; virtual void destroyedByDamage(DamageInfo& info) override; virtual void applyTemplateValues() override; diff --git a/src/spaceObjects/spaceship.cpp b/src/spaceObjects/spaceship.cpp index cb224b96f5..87c4a1a5f3 100644 --- a/src/spaceObjects/spaceship.cpp +++ b/src/spaceObjects/spaceship.cpp @@ -17,6 +17,7 @@ #include "multiplayer_client.h" #include "gameGlobalInfo.h" #include "components/collision.h" +#include "components/docking.h" #include "scriptInterface.h" @@ -204,7 +205,6 @@ SpaceShip::SpaceShip(string multiplayerClassName, float multiplayer_significant_ beam_frequency = irandom(0, max_frequency); beam_system_target = SYS_None; shield_frequency = irandom(0, max_frequency); - docking_state = DS_NotDocking; impulse_acceleration = 20.f; impulse_reverse_acceleration = 20.f; energy_level = 1000; @@ -233,8 +233,6 @@ SpaceShip::SpaceShip(string multiplayerClassName, float multiplayer_significant_ registerMemberReplication(&impulse_reverse_acceleration); registerMemberReplication(&warp_speed_per_warp_level); registerMemberReplication(&shield_frequency); - registerMemberReplication(&docking_state); - registerMemberReplication(&docked_style); registerMemberReplication(&beam_frequency); registerMemberReplication(&combat_maneuver_charge, 0.5f); registerMemberReplication(&combat_maneuver_boost_request); @@ -359,16 +357,9 @@ void SpaceShip::applyTemplateValues() model_info.setData(ship_template->model_data); } -void SpaceShip::draw3D() -{ - if (docked_style == DockStyle::Internal) return; - ShipTemplateBasedObject::draw3D(); -} - void SpaceShip::draw3DTransparent() { if (!ship_template) return; - if (docked_style == DockStyle::Internal) return; ShipTemplateBasedObject::draw3DTransparent(); if ((has_jump_drive && jump_delay > 0.0f) || @@ -453,8 +444,6 @@ void SpaceShip::updateDynamicRadarSignature() void SpaceShip::drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) { - if (docked_style == DockStyle::Internal) return; - // Draw beam arcs on short-range radar only, and only for fully scanned // ships. if (!long_range && (!my_spaceship || (getScannedStateFor(my_spaceship) == SS_FullScan))) @@ -618,8 +607,6 @@ void SpaceShip::drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, floa void SpaceShip::drawOnGMRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) { - if (docked_style == DockStyle::Internal) return; - if (!long_range) { renderer.fillRect(sp::Rect(position.x - 30, position.y - 30, 60 * hull_strength / hull_max, 5), glm::u8vec4(128, 255, 128, 128)); @@ -632,56 +619,6 @@ void SpaceShip::update(float delta) auto physics = entity.getComponent(); - if (bool(physics) != (docked_style != DockStyle::Internal)) - { - if (docked_style == DockStyle::Internal) { - entity.removeComponent(); - physics = nullptr; - } else if (ship_template) { - ship_template->setCollisionData(this); - } - } - - if (game_server) - { - if (docking_state == DS_Docking) - { - if (!docking_target) - docking_state = DS_NotDocking; - else - target_rotation = vec2ToAngle(getPosition() - docking_target->getPosition()); - if (fabs(angleDifference(target_rotation, getRotation())) < 10.0f) - impulse_request = -1.f; - else - impulse_request = 0.f; - } - if (docking_state == DS_Docked) - { - if (!docking_target) - { - docking_state = DS_NotDocking; - docked_style = DockStyle::None; - }else{ - setPosition(docking_target->getPosition() + rotateVec2(docking_offset, docking_target->getRotation())); - target_rotation = vec2ToAngle(getPosition() - docking_target->getPosition()); - - P docked_with_template_based = docking_target; - if (docked_with_template_based && docked_with_template_based->repair_docked) //Check if what we are docked to allows hull repairs, and if so, do it. - { - if (hull_strength < hull_max) - { - hull_strength += delta; - if (hull_strength > hull_max) - hull_strength = hull_max; - } - } - } - impulse_request = 0.f; - } - if ((docking_state == DS_Docked) || (docking_state == DS_Docking)) - warp_request = 0; - } - float rotationDiff; if (fabs(turnSpeed) < 0.0005f) { rotationDiff = angleDifference(getRotation(), target_rotation); @@ -906,10 +843,11 @@ float SpaceShip::getShieldRechargeRate(int shield_index) { float rate = 0.3f; rate *= getSystemEffectiveness(getShieldSystemForShieldIndex(shield_index)); - if (docking_state == DS_Docked) + auto port = entity.getComponent(); + if (port && port->state == DockingPort::State::Docked && port->target) { - P docked_with_ship = docking_target; - if (!docked_with_ship) + auto bay = port->target.getComponent(); + if (bay && (bay->flags & DockingBay::ChargeShield)) rate *= 4.0f; } return rate; @@ -935,44 +873,14 @@ void SpaceShip::executeJump(float distance) addHeat(SYS_JumpDrive, jump_drive_heat_per_jump); } -DockStyle SpaceShip::canBeDockedBy(P obj) -{ - if (isEnemy(obj) || !ship_template) - return DockStyle::None; - P ship = obj; - if (!ship || !ship->ship_template) - return DockStyle::None; - if (ship_template->external_dock_classes.count(ship->ship_template->getClass()) > 0) - return DockStyle::External; - if (ship_template->external_dock_classes.count(ship->ship_template->getSubClass()) > 0) - return DockStyle::External; - if (ship_template->internal_dock_classes.count(ship->ship_template->getClass()) > 0) - return DockStyle::Internal; - if (ship_template->internal_dock_classes.count(ship->ship_template->getSubClass()) > 0) - return DockStyle::Internal; - return DockStyle::None; -} - void SpaceShip::collide(SpaceObject* other, float force) { - if (docking_state == DS_Docking && fabs(angleDifference(target_rotation, getRotation())) < 10.0f) - { - P dock_object = other; - if (dock_object == docking_target) - { - docking_state = DS_Docked; - docked_style = docking_target->canBeDockedBy(this); - docking_offset = rotateVec2(getPosition() - other->getPosition(), -other->getRotation()); - float length = glm::length(docking_offset); - docking_offset = docking_offset / length * (length + 2.0f); - } - } } void SpaceShip::initializeJump(float distance) { - if (docking_state != DS_NotDocking) - return; + auto docking_port = entity.getComponent(); + if (docking_port && docking_port->state != DockingPort::State::NotDocking) return; if (jump_drive_charge < jump_drive_max_distance) // You can only jump when the drive is fully charged return; if (jump_delay <= 0.0f) @@ -985,37 +893,42 @@ void SpaceShip::initializeJump(float distance) void SpaceShip::requestDock(P target) { - if (!target || docking_state != DS_NotDocking || target->canBeDockedBy(this) == DockStyle::None) + auto docking_port = entity.getComponent(); + if (!docking_port || docking_port->state != DockingPort::State::NotDocking) return; + if (!target) return; + auto bay = target->entity.getComponent(); + if (!bay || docking_port->canDockOn(*bay) == DockingStyle::None) return; + if (glm::length(getPosition() - target->getPosition()) > 1000 + target->getRadius()) return; if (!canStartDocking()) return; - docking_state = DS_Docking; - docking_target = target; + docking_port->state = DockingPort::State::Docking; + docking_port->target = target->entity; warp_request = 0; } void SpaceShip::requestUndock() { - if (docking_state == DS_Docked && getSystemEffectiveness(SYS_Impulse) > 0.1f) - { - docked_style = DockStyle::None; - docking_state = DS_NotDocking; - impulse_request = 0.5; - } + auto docking_port = entity.getComponent(); + if (!docking_port || docking_port->state != DockingPort::State::Docked) return; + if (getSystemEffectiveness(SYS_Impulse) < 0.1f) return; + + docking_port->state = DockingPort::State::NotDocking; + impulse_request = 0.5; } void SpaceShip::abortDock() { - if (docking_state == DS_Docking) - { - docking_state = DS_NotDocking; - impulse_request = 0.f; - warp_request = 0; - target_rotation = getRotation(); - } + auto docking_port = entity.getComponent(); + if (!docking_port || docking_port->state != DockingPort::State::Docking) return; + + docking_port->state = DockingPort::State::NotDocking; + impulse_request = 0.f; + warp_request = 0; + target_rotation = getRotation(); } int SpaceShip::scanningComplexity(P other) @@ -1442,6 +1355,32 @@ std::unordered_map SpaceShip::getGMInfo() return ret; } +bool SpaceShip::isDocked(P target) +{ + if (!entity) return false; + auto port = entity.getComponent(); + if (!port) return false; + return port->state == DockingPort::State::Docked && *port->target.getComponent() == *target; +} + +P SpaceShip::getDockedWith() +{ + if (!entity) return nullptr; + auto port = entity.getComponent(); + if (!port) return nullptr; + if (port->state != DockingPort::State::Docked) return nullptr; + return *port->target.getComponent(); +} + +DockingPort::State SpaceShip::getDockingState() +{ + if (!entity) return DockingPort::State::NotDocking; + auto port = entity.getComponent(); + if (!port) return DockingPort::State::NotDocking; + return port->state; +} + + string SpaceShip::getScriptExportModificationsOnTemplate() { // Exports attributes common to ships as Lua script function calls. diff --git a/src/spaceObjects/spaceship.h b/src/spaceObjects/spaceship.h index 8405cde949..3d726b4561 100644 --- a/src/spaceObjects/spaceship.h +++ b/src/spaceObjects/spaceship.h @@ -10,6 +10,7 @@ #include "spaceshipParts/beamWeapon.h" #include "spaceshipParts/weaponTube.h" #include "tween.h" +#include "components/docking.h" enum EMainScreenSetting @@ -207,15 +208,9 @@ class SpaceShip : public ShipTemplateBasedObject /// MultiplayerObjectID of the targeted object, or -1 when no target is selected. int32_t target_id; - EDockingState docking_state; - DockStyle docked_style = DockStyle::None; - P docking_target; //Server only - glm::vec2 docking_offset{0, 0}; //Server only - SpaceShip(string multiplayerClassName, float multiplayer_significant_range=-1); virtual ~SpaceShip(); - virtual void draw3D() override; virtual void draw3DTransparent() override; /*! * Get this ship's radar signature dynamically modified by the state of its @@ -268,12 +263,6 @@ class SpaceShip : public ShipTemplateBasedObject */ virtual void executeJump(float distance); - /*! - * Check if object can dock with this ship. - * \param object Object that wants to dock. - */ - virtual DockStyle canBeDockedBy(P obj) override; - virtual void collide(SpaceObject* other, float force) override; /*! @@ -338,10 +327,10 @@ class SpaceShip : public ShipTemplateBasedObject virtual std::unordered_map getGMInfo() override; - bool isDocked(P target) { return docking_state == DS_Docked && docking_target == target; } - P getDockedWith() { if (docking_state == DS_Docked) return docking_target; return NULL; } + bool isDocked(P target); + P getDockedWith(); + DockingPort::State getDockingState(); bool canStartDocking() { return current_warp <= 0.0f && (!has_jump_drive || jump_delay <= 0.0f); } - EDockingState getDockingState() { return docking_state; } int getWeaponStorage(EMissileWeapons weapon) { if (weapon == MW_None) return 0; return weapon_storage[weapon]; } int getWeaponStorageMax(EMissileWeapons weapon) { if (weapon == MW_None) return 0; return weapon_storage_max[weapon]; } void setWeaponStorage(EMissileWeapons weapon, int amount) { if (weapon == MW_None) return; weapon_storage[weapon] = amount; } @@ -516,7 +505,6 @@ REGISTER_MULTIPLAYER_ENUM(EWeaponTubeState); REGISTER_MULTIPLAYER_ENUM(EMainScreenSetting); REGISTER_MULTIPLAYER_ENUM(EMainScreenOverlay); REGISTER_MULTIPLAYER_ENUM(EDockingState); -REGISTER_MULTIPLAYER_ENUM(DockStyle); REGISTER_MULTIPLAYER_ENUM(EScannedState); string frequencyToString(int frequency); diff --git a/src/spaceObjects/spaceshipParts/beamWeapon.cpp b/src/spaceObjects/spaceshipParts/beamWeapon.cpp index 97c85ba7fd..ce541dcbcb 100644 --- a/src/spaceObjects/spaceshipParts/beamWeapon.cpp +++ b/src/spaceObjects/spaceshipParts/beamWeapon.cpp @@ -199,10 +199,11 @@ void BeamWeapon::update(float delta) cooldown -= delta * parent->getSystemEffectiveness(SYS_BeamWeapons); P target = parent->getTarget(); + auto docking_port = parent->entity.getComponent(); // Check on beam weapons only if we are on the server, have a target, and // not paused, and if the beams are cooled down or have a turret arc. - if (game_server && range > 0.0f && target && parent->isEnemy(target) && delta > 0 && parent->current_warp == 0.0f && parent->docking_state == DS_NotDocking) + if (game_server && range > 0.0f && target && parent->isEnemy(target) && delta > 0 && parent->current_warp == 0.0f && (!docking_port || docking_port->state == DockingPort::State::NotDocking)) { // Get the angle to the target. auto diff = target->getPosition() - (parent->getPosition() + rotateVec2(glm::vec2(position.x, position.y), parent->getRotation())); diff --git a/src/spaceObjects/spaceshipParts/weaponTube.cpp b/src/spaceObjects/spaceshipParts/weaponTube.cpp index 478a100b4b..ab96c6d4ef 100644 --- a/src/spaceObjects/spaceshipParts/weaponTube.cpp +++ b/src/spaceObjects/spaceshipParts/weaponTube.cpp @@ -93,7 +93,9 @@ void WeaponTube::fire(float target_angle) { parent->didAnOffensiveAction(); - if (parent->docking_state != DS_NotDocking) return; + auto docking_port = parent->entity.getComponent(); + if (docking_port && docking_port->state != DockingPort::State::NotDocking) return; + if (parent->current_warp > 0.0f) return; if (state != WTS_Loaded) return; diff --git a/src/systems/docking.cpp b/src/systems/docking.cpp new file mode 100644 index 0000000000..ae7f2723b0 --- /dev/null +++ b/src/systems/docking.cpp @@ -0,0 +1,149 @@ +#include "systems/docking.h" +#include "components/docking.h" +#include "ecs/query.h" + + +void DockingSystem::update(float delta) +{ +/* ==Spaceship + +if (bool(physics) != (docked_style != DockStyle::Internal)) + { + if (docked_style == DockStyle::Internal) { + entity.removeComponent(); + physics = nullptr; + } else if (ship_template) { + ship_template->setCollisionData(this); + } + } + + if (game_server) + { + if (docking_state == DS_Docking) + { + if (!docking_target) + docking_state = DS_NotDocking; + else + target_rotation = vec2ToAngle(getPosition() - docking_target->getPosition()); + if (fabs(angleDifference(target_rotation, getRotation())) < 10.0f) + impulse_request = -1.f; + else + impulse_request = 0.f; + } + if (docking_state == DS_Docked) + { + if (!docking_target) + { + docking_state = DS_NotDocking; + docked_style = DockStyle::None; + }else{ + setPosition(docking_target->getPosition() + rotateVec2(docking_offset, docking_target->getRotation())); + target_rotation = vec2ToAngle(getPosition() - docking_target->getPosition()); + + P docked_with_template_based = docking_target; + if (docked_with_template_based && docked_with_template_based->repair_docked) //Check if what we are docked to allows hull repairs, and if so, do it. + { + if (hull_strength < hull_max) + { + hull_strength += delta; + if (hull_strength > hull_max) + hull_strength = hull_max; + } + } + } + impulse_request = 0.f; + } + if ((docking_state == DS_Docked) || (docking_state == DS_Docking)) + warp_request = 0; + } + + ==PlayerShip + + // Docking actions. + if (docking_state == DS_Docked) + { + P docked_with_template_based = docking_target; + P docked_with_ship = docking_target; + + // Derive a base energy request rate from the player ship's maximum + // energy capacity. + float energy_request = std::min(delta * 10.0f, max_energy_level - energy_level); + + // If we're docked with a shipTemplateBasedObject, and that object is + // set to share its energy with docked ships, transfer energy from the + // mothership to docked ships until the mothership runs out of energy + // or the docked ship doesn't require any. + if (docked_with_template_based && docked_with_template_based->shares_energy_with_docked) + { + if (!docked_with_ship || docked_with_ship->useEnergy(energy_request)) + energy_level += energy_request; + } + + // If a shipTemplateBasedObject and is allowed to restock + // scan probes with docked ships. + if (docked_with_template_based && docked_with_template_based->restocks_scan_probes) + { + if (scan_probe_stock < max_scan_probes) + { + scan_probe_recharge += delta; + + if (scan_probe_recharge > scan_probe_charge_time) + { + scan_probe_stock += 1; + scan_probe_recharge = 0.0; + } + } + } + }else{ + scan_probe_recharge = 0.0; + } + + ==CpuShip + + //recharge missiles of CPU ships docked to station. Can be disabled setting the restocks_missiles_docked flag to false. + if (docking_state == DS_Docked) + { + P docked_with_template_based = docking_target; + P docked_with_ship = docking_target; + + if (docked_with_template_based && docked_with_template_based->restocks_missiles_docked) + { + bool needs_missile = 0; + + for(int n=0; n= missile_resupply_time) + { + weapon_storage[n] += 1; + missile_resupply = 0.0; + break; + } + else + needs_missile = 1; + } + } + + if (needs_missile) + missile_resupply += delta; + } + } +*/ +} + +/* +Collision: + if (docking_state == DS_Docking && fabs(angleDifference(target_rotation, getRotation())) < 10.0f) + { + P dock_object = other; + if (dock_object == docking_target) + { + docking_state = DS_Docked; + docked_style = docking_target->canBeDockedBy(this); + docking_offset = rotateVec2(getPosition() - other->getPosition(), -other->getRotation()); + float length = glm::length(docking_offset); + docking_offset = docking_offset / length * (length + 2.0f); + } + } +*/ \ No newline at end of file diff --git a/src/systems/docking.h b/src/systems/docking.h new file mode 100644 index 0000000000..7fcedff189 --- /dev/null +++ b/src/systems/docking.h @@ -0,0 +1,9 @@ +#pragma once + +#include "ecs/system.h" + +class DockingSystem : public sp::ecs::System +{ +public: + void update(float delta) override; +}; From e40aae2632faa10e0b6f4524ecc3da296a7fd446 Mon Sep 17 00:00:00 2001 From: Daid Date: Sat, 5 Nov 2022 19:19:06 +0100 Subject: [PATCH 011/320] Compiles! --- scripts/scenario_10_empty.lua | 8 +++++--- src/ai/evasionAI.cpp | 3 ++- src/spaceObjects/playerSpaceship.cpp | 17 ++++++++++++++++ src/spaceObjects/shipTemplateBasedObject.cpp | 21 ++++++++++++++++++++ src/spaceObjects/spaceship.cpp | 2 +- src/spaceObjects/spaceship.h | 8 -------- 6 files changed, 46 insertions(+), 13 deletions(-) diff --git a/scripts/scenario_10_empty.lua b/scripts/scenario_10_empty.lua index 14d0c1e9e8..1cc4819e49 100644 --- a/scripts/scenario_10_empty.lua +++ b/scripts/scenario_10_empty.lua @@ -13,13 +13,14 @@ function init() --player1 = PlayerSpaceship():setFaction("Human Navy"):setTemplate("Atlantis"):setRotation(200) --player2 = PlayerSpaceship():setFaction("Human Navy"):setTemplate("Atlantis"):setRotation(0) --Nebula():setPosition(-5000, 0) - --Artifact():setPosition(1000, 9000):setModel("small_frigate_1"):setDescription("An old space derelict.") - --Artifact():setPosition(9000, 2000):setModel("small_frigate_1"):setDescription("A wrecked ship.") - --Artifact():setPosition(3000, 4000):setModel("small_frigate_1"):setDescription("Tons of rotting plasteel.") + Artifact():setPosition(1000, 9000):setModel("small_frigate_1"):setDescription("An old space derelict.") + Artifact():setPosition(9000, 2000):setModel("small_frigate_1"):setDescription("A wrecked ship."):setRadarTraceColor(255, 0, 0) + Artifact():setPosition(3000, 4000):setModel("small_frigate_1"):setDescription("Tons of rotting plasteel.") --addGMFunction("move 1 to 2", function() player1:transferPlayersToShip(player2) end) --addGMFunction("move 2 to 1", function() player2:transferPlayersToShip(player1) end) --CpuShip():setTemplate("Adder MK5"):setPosition(0, 0):setRotation(0):setFaction("Human Navy") --CpuShip():setTemplate("Piranha F12"):setPosition(2000, 0):setRotation(-90):setFaction("Kraylor") + --[[ local planet1 = Planet():setPosition(5000, 5000):setPlanetRadius(3000):setDistanceFromMovementPlane(-2000):setPlanetSurfaceTexture("planets/planet-1.png"):setPlanetCloudTexture("planets/clouds-1.png"):setPlanetAtmosphereTexture("planets/atmosphere.png"):setPlanetAtmosphereColor(0.2, 0.2, 1.0) local moon1 = Planet():setPosition(5000, 0):setPlanetRadius(1000):setDistanceFromMovementPlane(-2000):setPlanetSurfaceTexture("planets/moon-1.png"):setAxialRotationTime(20.0) local sun1 = Planet():setPosition(5000, 15000):setPlanetRadius(1000):setDistanceFromMovementPlane(-2000):setPlanetAtmosphereTexture("planets/star-1.png"):setPlanetAtmosphereColor(1.0, 1.0, 1.0) @@ -62,6 +63,7 @@ function init() end end ) + --]] end function cleanup() diff --git a/src/ai/evasionAI.cpp b/src/ai/evasionAI.cpp index 4868e7ecb4..e1e7dd99a8 100644 --- a/src/ai/evasionAI.cpp +++ b/src/ai/evasionAI.cpp @@ -30,6 +30,7 @@ void EvasionAI::run(float delta) // @TODO: consider jump drives void EvasionAI::runOrders() { + auto docking_port = owner->entity.getComponent(); //When we are not attacking a target, follow orders switch(owner->getOrder()) { @@ -40,7 +41,7 @@ void EvasionAI::runOrders() } break; case AI_Dock: - if (owner->getOrderTarget() && owner->docking_state == DS_NotDocking) + if (owner->getOrderTarget() && (!docking_port || docking_port->state == DockingPort::State::NotDocking)) { auto target_position = owner->getOrderTarget()->getPosition(); auto diff = owner->getPosition() - target_position; diff --git a/src/spaceObjects/playerSpaceship.cpp b/src/spaceObjects/playerSpaceship.cpp index 94457bec24..2d977441c3 100644 --- a/src/spaceObjects/playerSpaceship.cpp +++ b/src/spaceObjects/playerSpaceship.cpp @@ -1131,6 +1131,23 @@ void PlayerSpaceship::closeComms() } } +void PlayerSpaceship::setCanDock(bool enabled) +{ + if (!enabled) { + //TODO: Undock first! + entity.removeComponent(); + } else { + auto port = entity.getOrAddComponent(); + port.dock_class = ship_template->getClass(); + port.dock_subclass = ship_template->getSubClass(); + } +} + +bool PlayerSpaceship::getCanDock() +{ + return entity.hasComponent(); +} + void PlayerSpaceship::onReceiveClientCommand(int32_t client_id, sp::io::DataBuffer& packet) { // Receive a command from a client. Code in this function is executed on diff --git a/src/spaceObjects/shipTemplateBasedObject.cpp b/src/spaceObjects/shipTemplateBasedObject.cpp index 4b967f043a..0bf70a4d2d 100644 --- a/src/spaceObjects/shipTemplateBasedObject.cpp +++ b/src/spaceObjects/shipTemplateBasedObject.cpp @@ -448,6 +448,27 @@ void ShipTemplateBasedObject::setRadarTrace(string trace) entity.getOrAddComponent().icon = "radar/" + trace; } +bool ShipTemplateBasedObject::getSharesEnergyWithDocked() +{ + return false;//TODO +} +void ShipTemplateBasedObject::setSharesEnergyWithDocked(bool enabled) { /*TODO*/ } +bool ShipTemplateBasedObject::getRepairDocked() +{ + return false;//TODO +} +void ShipTemplateBasedObject::setRepairDocked(bool enabled) { /*TODO*/ } +bool ShipTemplateBasedObject::getRestocksScanProbes() +{ + return false;//TODO +} +void ShipTemplateBasedObject::setRestocksScanProbes(bool enabled) { /*TODO*/ } +bool ShipTemplateBasedObject::getRestocksMissilesDocked() +{ + return false;//TODO +} +void ShipTemplateBasedObject::setRestocksMissilesDocked(bool enabled) { /*TODO*/ } + void ShipTemplateBasedObject::onTakingDamage(ScriptSimpleCallback callback) { this->on_taking_damage = callback; diff --git a/src/spaceObjects/spaceship.cpp b/src/spaceObjects/spaceship.cpp index 87c4a1a5f3..43075a2f7c 100644 --- a/src/spaceObjects/spaceship.cpp +++ b/src/spaceObjects/spaceship.cpp @@ -35,7 +35,7 @@ REGISTER_SCRIPT_SUBCLASS_NO_CREATE(SpaceShip, ShipTemplateBasedObject) REGISTER_SCRIPT_CLASS_FUNCTION(SpaceShip, isFullyScannedByFaction); REGISTER_SCRIPT_CLASS_FUNCTION(SpaceShip, isDocked); REGISTER_SCRIPT_CLASS_FUNCTION(SpaceShip, getDockedWith); - REGISTER_SCRIPT_CLASS_FUNCTION(SpaceShip, getDockingState); + //REGISTER_SCRIPT_CLASS_FUNCTION(SpaceShip, getDockingState); /// Returns gets this ship target. /// For example enemy targetted by player ship's weapons. REGISTER_SCRIPT_CLASS_FUNCTION(SpaceShip, getTarget); diff --git a/src/spaceObjects/spaceship.h b/src/spaceObjects/spaceship.h index 3d726b4561..b9e3a5a97b 100644 --- a/src/spaceObjects/spaceship.h +++ b/src/spaceObjects/spaceship.h @@ -32,13 +32,6 @@ enum EMainScreenOverlay }; template<> void convert::param(lua_State* L, int& idx, EMainScreenOverlay& mso); -enum EDockingState -{ - DS_NotDocking = 0, - DS_Docking, - DS_Docked -}; - struct Speeds { float forward; @@ -504,7 +497,6 @@ REGISTER_MULTIPLAYER_ENUM(EMissileWeapons); REGISTER_MULTIPLAYER_ENUM(EWeaponTubeState); REGISTER_MULTIPLAYER_ENUM(EMainScreenSetting); REGISTER_MULTIPLAYER_ENUM(EMainScreenOverlay); -REGISTER_MULTIPLAYER_ENUM(EDockingState); REGISTER_MULTIPLAYER_ENUM(EScannedState); string frequencyToString(int frequency); From c77254cdceced5057fb5a6ad533b8137002ad2c5 Mon Sep 17 00:00:00 2001 From: Daid Date: Sun, 6 Nov 2022 11:13:55 +0100 Subject: [PATCH 012/320] Implement rest of the docking system. --- src/spaceObjects/artifact.cpp | 2 +- src/spaceObjects/cpuShip.h | 3 +- src/systems/docking.cpp | 237 +++++++++++++++++----------------- src/systems/docking.h | 8 +- 4 files changed, 127 insertions(+), 123 deletions(-) diff --git a/src/spaceObjects/artifact.cpp b/src/spaceObjects/artifact.cpp index 76c179d8d6..4e8602ace4 100644 --- a/src/spaceObjects/artifact.cpp +++ b/src/spaceObjects/artifact.cpp @@ -70,7 +70,7 @@ Artifact::Artifact() registerMemberReplication(&artifact_spin); if (entity) { - auto& trace = entity.addComponent(); + auto& trace = entity.getOrAddComponent(); trace.radius = getRadius(); trace.icon = "radar/blip.png"; } diff --git a/src/spaceObjects/cpuShip.h b/src/spaceObjects/cpuShip.h index a7ec27c639..b79078f5f2 100644 --- a/src/spaceObjects/cpuShip.h +++ b/src/spaceObjects/cpuShip.h @@ -24,7 +24,6 @@ class ShipAI; class CpuShip : public SpaceShip { static constexpr float auto_system_repair_per_second = 0.005f; - static constexpr float missile_resupply_time = 10.0f; EAIOrder orders; //Server only glm::vec2 order_target_location{}; //Server only @@ -33,6 +32,8 @@ class CpuShip : public SpaceShip string new_ai_name; public: + static constexpr float missile_resupply_time = 10.0f; + CpuShip(); virtual ~CpuShip(); diff --git a/src/systems/docking.cpp b/src/systems/docking.cpp index ae7f2723b0..07aaeb7aba 100644 --- a/src/systems/docking.cpp +++ b/src/systems/docking.cpp @@ -1,149 +1,146 @@ #include "systems/docking.h" #include "components/docking.h" +#include "components/collision.h" +#include "spaceObjects/spaceship.h" +#include "spaceObjects/playerSpaceship.h" +#include "spaceObjects/cpuShip.h" #include "ecs/query.h" +#include "multiplayer_server.h" +DockingSystem::DockingSystem() +{ + sp::CollisionSystem::addHandler(this); +} +//TODO: Handle internal docking. void DockingSystem::update(float delta) { -/* ==Spaceship - -if (bool(physics) != (docked_style != DockStyle::Internal)) - { - if (docked_style == DockStyle::Internal) { - entity.removeComponent(); - physics = nullptr; - } else if (ship_template) { - ship_template->setCollisionData(this); - } - } - - if (game_server) - { - if (docking_state == DS_Docking) - { - if (!docking_target) - docking_state = DS_NotDocking; - else - target_rotation = vec2ToAngle(getPosition() - docking_target->getPosition()); - if (fabs(angleDifference(target_rotation, getRotation())) < 10.0f) - impulse_request = -1.f; - else - impulse_request = 0.f; - } - if (docking_state == DS_Docked) - { - if (!docking_target) + if (!game_server) return; + + for(auto [entity, docking_port, position, obj] : sp::ecs::Query, SpaceObject*>()) { + SpaceShip* ship = dynamic_cast(obj); + PlayerSpaceship* player = dynamic_cast(obj); + if (!ship) continue; + sp::Position* target_position; + switch(docking_port.state) { + case DockingPort::State::NotDocking: + break; + case DockingPort::State::Docking: + if (!docking_port.target || !(target_position = docking_port.target.getComponent())) { + docking_port.state = DockingPort::State::NotDocking; + } else { + ship->target_rotation = vec2ToAngle(position->getPosition() - target_position->getPosition()); + if (fabs(angleDifference(ship->target_rotation, position->getRotation())) < 10.0f) + ship->impulse_request = -1.f; + else + ship->impulse_request = 0.f; + ship->warp_request = 0.f; + } + break; + case DockingPort::State::Docked: + if (!docking_port.target || !(target_position = docking_port.target.getComponent())) { - docking_state = DS_NotDocking; - docked_style = DockStyle::None; + docking_port.state = DockingPort::State::NotDocking; + if (!position) { // Internal docking and our bay is destroyed. So, destroy ourselves as well. + entity.destroy(); + } }else{ - setPosition(docking_target->getPosition() + rotateVec2(docking_offset, docking_target->getRotation())); - target_rotation = vec2ToAngle(getPosition() - docking_target->getPosition()); + if (position) { + position->setPosition(target_position->getPosition() + rotateVec2(docking_port.docked_offset, target_position->getRotation())); + ship->target_rotation = vec2ToAngle(position->getPosition() - target_position->getPosition()); + } - P docked_with_template_based = docking_target; - if (docked_with_template_based && docked_with_template_based->repair_docked) //Check if what we are docked to allows hull repairs, and if so, do it. + auto bay = docking_port.target.getComponent(); + if (bay && (bay->flags & DockingBay::Repair)) //Check if what we are docked to allows hull repairs, and if so, do it. { - if (hull_strength < hull_max) + if (ship->hull_strength < ship->hull_max) { - hull_strength += delta; - if (hull_strength > hull_max) - hull_strength = hull_max; + ship->hull_strength += delta; + if (ship->hull_strength > ship->hull_max) + ship->hull_strength = ship->hull_max; } } - } - impulse_request = 0.f; - } - if ((docking_state == DS_Docked) || (docking_state == DS_Docking)) - warp_request = 0; - } - - ==PlayerShip - - // Docking actions. - if (docking_state == DS_Docked) - { - P docked_with_template_based = docking_target; - P docked_with_ship = docking_target; - - // Derive a base energy request rate from the player ship's maximum - // energy capacity. - float energy_request = std::min(delta * 10.0f, max_energy_level - energy_level); - - // If we're docked with a shipTemplateBasedObject, and that object is - // set to share its energy with docked ships, transfer energy from the - // mothership to docked ships until the mothership runs out of energy - // or the docked ship doesn't require any. - if (docked_with_template_based && docked_with_template_based->shares_energy_with_docked) - { - if (!docked_with_ship || docked_with_ship->useEnergy(energy_request)) - energy_level += energy_request; - } - // If a shipTemplateBasedObject and is allowed to restock - // scan probes with docked ships. - if (docked_with_template_based && docked_with_template_based->restocks_scan_probes) - { - if (scan_probe_stock < max_scan_probes) - { - scan_probe_recharge += delta; - - if (scan_probe_recharge > scan_probe_charge_time) - { - scan_probe_stock += 1; - scan_probe_recharge = 0.0; + if (bay && (bay->flags & DockingBay::ShareEnergy)) { + auto target_ship = dynamic_cast(*docking_port.target.getComponent()); + // Derive a base energy request rate from the player ship's maximum + // energy capacity. + float energy_request = std::min(delta * 10.0f, player->max_energy_level - player->energy_level); + + // If we're docked with a shipTemplateBasedObject, and that object is + // set to share its energy with docked ships, transfer energy from the + // mothership to docked ships until the mothership runs out of energy + // or the docked ship doesn't require any. + if (!target_ship || target_ship->useEnergy(energy_request)) + ship->energy_level += energy_request; } - } - } - }else{ - scan_probe_recharge = 0.0; - } - ==CpuShip - - //recharge missiles of CPU ships docked to station. Can be disabled setting the restocks_missiles_docked flag to false. - if (docking_state == DS_Docked) - { - P docked_with_template_based = docking_target; - P docked_with_ship = docking_target; + if (player && bay && (bay->flags & DockingBay::RestockProbes)) { + // If a shipTemplateBasedObject and is allowed to restock + // scan probes with docked ships. + if (player->scan_probe_stock < player->max_scan_probes) + { + player->scan_probe_recharge += delta; - if (docked_with_template_based && docked_with_template_based->restocks_missiles_docked) - { - bool needs_missile = 0; + if (player->scan_probe_recharge > player->scan_probe_charge_time) + { + player->scan_probe_stock += 1; + player->scan_probe_recharge = 0.0; + } + } + } - for(int n=0; n= missile_resupply_time) - { - weapon_storage[n] += 1; - missile_resupply = 0.0; - break; + //recharge missiles of CPU ships docked to station. Can be disabled + if (!player && bay && (bay->flags & DockingBay::RestockMissiles)) { + auto cpu = dynamic_cast(ship); + if (cpu) { + bool needs_missile = false; + + for(int n=0; nweapon_storage[n] < ship->weapon_storage_max[n]) + { + if (cpu->missile_resupply >= cpu->missile_resupply_time) + { + cpu->weapon_storage[n] += 1; + cpu->missile_resupply = 0.0; + break; + } + else + needs_missile = true; + } + } + + if (needs_missile) + cpu->missile_resupply += delta; } - else - needs_missile = 1; } } - - if (needs_missile) - missile_resupply += delta; + ship->impulse_request = 0.f; + ship->warp_request = 0.f; + break; } } -*/ } -/* -Collision: - if (docking_state == DS_Docking && fabs(angleDifference(target_rotation, getRotation())) < 10.0f) - { - P dock_object = other; - if (dock_object == docking_target) +void DockingSystem::collision(sp::ecs::Entity a, sp::ecs::Entity b, float force) +{ + auto port = a.getComponent(); + if (port && port->state == DockingPort::State::Docking && port->target == b) { + auto position = a.getComponent(); + auto other_position = b.getComponent(); + auto ship = dynamic_cast(*a.getComponent()); + + if (ship && position && other_position && fabs(angleDifference(ship->target_rotation, position->getRotation())) < 10.0f) { - docking_state = DS_Docked; - docked_style = docking_target->canBeDockedBy(this); - docking_offset = rotateVec2(getPosition() - other->getPosition(), -other->getRotation()); - float length = glm::length(docking_offset); - docking_offset = docking_offset / length * (length + 2.0f); + port->state = DockingPort::State::Docked; + auto bay = b.getComponent(); + port->docked_offset = rotateVec2(position->getPosition() - other_position->getPosition(), -other_position->getRotation()); + float length = glm::length(port->docked_offset); + port->docked_offset = port->docked_offset / length * (length + 2.0f); + + if (bay && port->canDockOn(*bay) == DockingStyle::Internal) + a.removeComponent(); } } -*/ \ No newline at end of file +} diff --git a/src/systems/docking.h b/src/systems/docking.h index 7fcedff189..7af597a58b 100644 --- a/src/systems/docking.h +++ b/src/systems/docking.h @@ -1,9 +1,15 @@ #pragma once #include "ecs/system.h" +#include "systems/collision.h" -class DockingSystem : public sp::ecs::System + +class DockingSystem : public sp::ecs::System, public sp::CollisionHandler { public: + DockingSystem(); + void update(float delta) override; + + void collision(sp::ecs::Entity a, sp::ecs::Entity b, float force) override; }; From a1027ddd7aa05bff963cd9cb9c2e53e1231b30a4 Mon Sep 17 00:00:00 2001 From: Daid Date: Thu, 10 Nov 2022 15:42:06 +0100 Subject: [PATCH 013/320] Add impulse and reactor systems, and breaking a lot of things. --- CMakeLists.txt | 4 + src/ai/ai.cpp | 44 ++-- src/ai/fighterAI.cpp | 5 +- src/components/impulse.h | 19 ++ src/components/reactor.h | 16 ++ src/components/shipsystem.h | 24 ++ src/gameStateLogger.cpp | 14 +- src/hardware/hardwareController.cpp | 4 +- src/main.cpp | 2 + src/screenComponents/impulseControls.cpp | 41 +-- src/screenComponents/impulseSound.cpp | 14 +- src/screenComponents/powerDamageIndicator.cpp | 6 +- src/screens/crew1/singlePilotScreen.cpp | 7 +- src/screens/crew4/tacticalScreen.cpp | 7 +- src/screens/crew6/engineeringScreen.cpp | 44 ++-- src/screens/crew6/helmsScreen.cpp | 7 +- src/screens/crew6/weaponsScreen.cpp | 7 +- src/screens/extra/powerManagement.cpp | 32 +-- src/screens/gm/tweak.cpp | 20 +- src/spaceObjects/playerSpaceship.cpp | 62 +++-- src/spaceObjects/playerSpaceship.h | 10 +- src/spaceObjects/shipTemplateBasedObject.cpp | 9 +- src/spaceObjects/shipTemplateBasedObject.h | 3 +- src/spaceObjects/spaceship.cpp | 236 ++++++------------ src/spaceObjects/spaceship.h | 64 +---- src/spaceObjects/supplyDrop.cpp | 9 +- src/systems/docking.cpp | 41 +-- src/systems/impulse.cpp | 142 +++++++++++ src/systems/impulse.h | 10 + 29 files changed, 532 insertions(+), 371 deletions(-) create mode 100644 src/components/impulse.h create mode 100644 src/components/reactor.h create mode 100644 src/components/shipsystem.h create mode 100644 src/systems/impulse.cpp create mode 100644 src/systems/impulse.h diff --git a/CMakeLists.txt b/CMakeLists.txt index fb06217efa..a2c92fab2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -356,8 +356,12 @@ set(MAIN_SOURCES src/components/radar.h src/components/rendering.h src/components/docking.h + src/components/shipsystem.h + src/components/impulse.h src/systems/docking.h src/systems/docking.cpp + src/systems/impulse.h + src/systems/impulse.cpp src/ai/fighterAI.cpp src/ai/ai.cpp src/ai/aiFactory.cpp diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp index 2468362644..8d93f28cdc 100644 --- a/src/ai/ai.cpp +++ b/src/ai/ai.cpp @@ -5,6 +5,7 @@ #include "ai/aiFactory.h" #include "random.h" #include "components/docking.h" +#include "components/impulse.h" #include "systems/collision.h" #include "ecs/query.h" @@ -56,7 +57,9 @@ void ShipAI::run(float delta) { owner->target_rotation = owner->getRotation(); owner->warp_request = 0.0; - owner->impulse_request = 0.0f; + auto impulse = owner->entity.getComponent(); + if (impulse) + impulse->request = 0.0f; updateWeaponState(delta); if (update_target_delay > 0.0f) @@ -606,14 +609,17 @@ void ShipAI::flyTowards(glm::vec2 target, float keep_distance) if (pathPlanner.route.size() > 1) keep_distance = 0.0; - if (distance > keep_distance + owner->impulse_max_speed * 5.0f) - owner->impulse_request = 1.0f; - else - owner->impulse_request = (distance - keep_distance) / owner->impulse_max_speed * 5.0f; - if (rotation_diff > 90) - owner->impulse_request = -owner->impulse_request; - else if (rotation_diff < 45) - owner->impulse_request *= 1.0f - ((rotation_diff - 45.0f) / 45.0f); + auto impulse = owner->entity.getComponent(); + if (impulse) { + if (distance > keep_distance + impulse->max_speed_forward * 5.0f) + impulse->request = 1.0f; + else + impulse->request = (distance - keep_distance) / impulse->max_speed_forward * 5.0f; + if (rotation_diff > 90) + impulse->request = -impulse->request; + else if (rotation_diff < 45) + impulse->request *= 1.0f - ((rotation_diff - 45.0f) / 45.0f); + } } } @@ -622,6 +628,9 @@ void ShipAI::flyFormation(P target, glm::vec2 offset) auto target_position = target->getPosition() + rotateVec2(owner->getOrderTargetLocation(), target->getRotation()); pathPlanner.plan(owner->getPosition(), target_position); + auto impulse = owner->entity.getComponent(); + if (!impulse) return; + if (pathPlanner.route.size() == 1) { auto docking_port = owner->entity.getComponent(); @@ -642,19 +651,19 @@ void ShipAI::flyFormation(P target, glm::vec2 offset) { float angle_diff = angleDifference(owner->target_rotation, owner->getRotation()); if (angle_diff > 10.0f) - owner->impulse_request = 0.0f; + impulse->request = 0.0f; else if (angle_diff > 5.0f) - owner->impulse_request = (10.0f - angle_diff) / 5.0f; + impulse->request = (10.0f - angle_diff) / 5.0f; else - owner->impulse_request = 1.0f; + impulse->request = 1.0f; }else{ if (distance > r / 2.0f) { owner->target_rotation += angleDifference(owner->target_rotation, target->getRotation()) * (1.0f - distance / r); - owner->impulse_request = distance / r; + impulse->request = distance / r; }else{ owner->target_rotation = target->getRotation(); - owner->impulse_request = 0.0f; + impulse->request = 0.0f; } } }else{ @@ -690,12 +699,13 @@ P ShipAI::findBestTarget(glm::vec2 position, float radius) float ShipAI::targetScore(P target) { + auto impulse = owner->entity.getComponent(); auto position_difference = target->getPosition() - owner->getPosition(); float distance = glm::length(position_difference); //auto position_difference_normal = position_difference / distance; //float rel_velocity = dot(target->getVelocity(), position_difference_normal) - dot(getVelocity(), position_difference_normal); float angle_difference = angleDifference(owner->getRotation(), vec2ToAngle(position_difference)); - float score = -distance - std::abs(angle_difference / owner->turn_speed * owner->impulse_max_speed) * 1.5f; + float score = -distance - std::abs(angle_difference / owner->turn_speed * (impulse ? impulse->max_speed_forward : 0.0f)) * 1.5f; if (P(target)) { score -= 5000; @@ -838,7 +848,7 @@ P ShipAI::findBestMissileRestockTarget(glm::vec2 position, float ra float target_score = 0.0; P target; auto owner_position = owner->getPosition(); - for(auto [entity, dockingbay, obj] : sp::ecs::Query()) + for(auto [entity, dockingbay, impulse, obj] : sp::ecs::Query()) { if (!obj || !owner->isFriendly(obj) || obj == *target) continue; @@ -848,7 +858,7 @@ P ShipAI::findBestMissileRestockTarget(glm::vec2 position, float ra auto position_difference = obj->getPosition() - owner_position; float distance = glm::length(position_difference); float angle_difference = angleDifference(owner->getRotation(), vec2ToAngle(position_difference)); - float score = -distance - std::abs(angle_difference / owner->turn_speed * owner->impulse_max_speed) * 1.5f; + float score = -distance - std::abs(angle_difference / owner->turn_speed * impulse.max_speed_forward) * 1.5f; if (P(P(obj))) { score -= 5000; diff --git a/src/ai/fighterAI.cpp b/src/ai/fighterAI.cpp index 893d19d5b5..d75cd87748 100644 --- a/src/ai/fighterAI.cpp +++ b/src/ai/fighterAI.cpp @@ -1,4 +1,5 @@ #include "spaceObjects/cpuShip.h" +#include "components/impulse.h" #include "ai/fighterAI.h" #include "ai/aiFactory.h" #include "random.h" @@ -93,7 +94,9 @@ void FighterAI::runAttack(P target) else { owner->target_rotation = evade_direction; - owner->impulse_request = 1.0; + auto impulse = owner->entity.getComponent(); + if (impulse) + impulse->request = 1.0; } break; case recharge: diff --git a/src/components/impulse.h b/src/components/impulse.h new file mode 100644 index 0000000000..5200219699 --- /dev/null +++ b/src/components/impulse.h @@ -0,0 +1,19 @@ +#pragma once + +#include "stringImproved.h" +#include "shipsystem.h" + +// Impulse engine component, indicate that this entity can move under impulse control. +class ImpulseEngine : public ShipSystem { +public: + // Config + float max_speed_forward = 500.0f; // in U/sec + float max_speed_reverse = 500.0f; // in U/sec + float acceleration_forward = 20.0f;// in U/sec^2 + float acceleration_reverse = 20.0f;// in U/sec^2 + string sound; + + // Runtime + float request = 0.0f; // -1.0 to 1.0 + float actual = 0.0f; // -1.0 to 1.0 +}; \ No newline at end of file diff --git a/src/components/reactor.h b/src/components/reactor.h new file mode 100644 index 0000000000..653b1cd0f5 --- /dev/null +++ b/src/components/reactor.h @@ -0,0 +1,16 @@ +#pragma once + +#include "shipsystem.h" + +// The reactor component stores and generates energy, any shipsystem can use energy and drain this. While the reactor generates energy. +class Reactor : public ShipSystem { +public: + // Config + + // Runtime + float energy = 1000.0f; + float max_energy = 1000.0f; + + + bool use_energy(float amount) { if (amount > energy) return false; energy -= amount; return true; } +}; \ No newline at end of file diff --git a/src/components/shipsystem.h b/src/components/shipsystem.h new file mode 100644 index 0000000000..7d5049b746 --- /dev/null +++ b/src/components/shipsystem.h @@ -0,0 +1,24 @@ +#pragma once + +//Base class for ship systems, ever created directly, use as base class for other components. +class ShipSystem +{ +public: + static constexpr float power_factor_rate = 0.08f; + static constexpr float default_add_heat_rate_per_second = 0.05f; + static constexpr float default_power_rate_per_second = 0.3f; + static constexpr float default_coolant_rate_per_second = 1.2f; + + float health; //1.0-0.0, where 0.0 is fully broken. + float health_max; //1.0-0.0, where 0.0 is fully broken. + float power_level; //0.0-3.0, default 1.0 + float power_request; + float heat_level; //0.0-1.0, system will damage at 1.0 + float coolant_level; //0.0-10.0 + float coolant_request; + float hacked_level; //0.0-1.0 + float power_factor; + float coolant_change_rate_per_second = default_coolant_rate_per_second; + float heat_add_rate_per_second = default_add_heat_rate_per_second; + float power_change_rate_per_second = default_power_rate_per_second; +}; \ No newline at end of file diff --git a/src/gameStateLogger.cpp b/src/gameStateLogger.cpp index 9e0a1ee092..5c53350e07 100644 --- a/src/gameStateLogger.cpp +++ b/src/gameStateLogger.cpp @@ -310,7 +310,7 @@ void GameStateLogger::writeShipEntry(JSONGenerator& json, P ship) json.write("callsign", ship->getCallSign()); json.write("faction", ship->getFaction()); json.write("ship_type", ship->type_name); - json.write("energy_level", ship->energy_level); + //json.write("energy_level", ship->energy_level); json.write("hull", ship->hull_strength); if (ship->target_id > -1) json.write("target", ship->target_id); @@ -402,7 +402,7 @@ void GameStateLogger::writeShipEntry(JSONGenerator& json, P ship) { JSONGenerator input = json.createDict("input"); input.write("rotation", ship->target_rotation); - input.write("impulse", ship->impulse_request); + //input.write("impulse", ship->impulse_request); if (ship->has_warp_drive) input.write("warp", ship->warp_request); if (ship->combat_maneuver_boost_speed > 0) @@ -412,7 +412,7 @@ void GameStateLogger::writeShipEntry(JSONGenerator& json, P ship) } { JSONGenerator output = json.createDict("output"); - output.write("impulse", ship->current_impulse); + //output.write("impulse", ship->current_impulse); if (ship->has_warp_drive) output.write("warp", ship->current_warp); if (ship->combat_maneuver_boost_speed > 0 || ship->combat_maneuver_strafe_speed > 0) @@ -436,10 +436,10 @@ void GameStateLogger::writeShipEntry(JSONGenerator& json, P ship) { JSONGenerator config = json.createDict("config"); config.write("turn_speed", ship->turn_speed); - config.write("impulse_speed", ship->impulse_max_speed); - config.write("impulse_acceleration", ship->impulse_acceleration); - config.write("impulse_reverse_speed", ship->impulse_max_reverse_speed); - config.write("impulse_reverse_acceleration", ship->impulse_reverse_acceleration); + //config.write("impulse_speed", ship->impulse_max_speed); + //config.write("impulse_acceleration", ship->impulse_acceleration); + //config.write("impulse_reverse_speed", ship->impulse_max_reverse_speed); + //config.write("impulse_reverse_acceleration", ship->impulse_reverse_acceleration); config.write("hull", ship->hull_max); if (ship->has_warp_drive) config.write("warp", ship->warp_speed_per_warp_level); diff --git a/src/hardware/hardwareController.cpp b/src/hardware/hardwareController.cpp index bfb3ce90c1..b821035d4a 100644 --- a/src/hardware/hardwareController.cpp +++ b/src/hardware/hardwareController.cpp @@ -369,9 +369,9 @@ bool HardwareController::getVariableValue(string variable_name, float& value) SHIP_VARIABLE("Shield5", ship->getShieldPercentage(5)); SHIP_VARIABLE("Shield6", ship->getShieldPercentage(6)); SHIP_VARIABLE("Shield7", ship->getShieldPercentage(7)); - SHIP_VARIABLE("Energy", ship->energy_level * 100 / ship->max_energy_level); + //SHIP_VARIABLE("Energy", ship->energy_level * 100 / ship->max_energy_level); SHIP_VARIABLE("ShieldsUp", ship->shields_active ? 1.0f : 0.0f); - SHIP_VARIABLE("Impulse", ship->current_impulse * ship->getSystemEffectiveness(SYS_Impulse)); + //SHIP_VARIABLE("Impulse", ship->current_impulse * ship->getSystemEffectiveness(SYS_Impulse)); SHIP_VARIABLE("Warp", ship->current_warp * ship->getSystemEffectiveness(SYS_Warp)); //SHIP_VARIABLE("Docking", ship->docking_state == DS_Docking ? 1.0f : 0.0f); //SHIP_VARIABLE("Docked", ship->docking_state == DS_Docked ? 1.0f : 0.0f); diff --git a/src/main.cpp b/src/main.cpp index 145f9597e2..482f12fee1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,6 +28,7 @@ #include "gameGlobalInfo.h" #include "spaceObjects/spaceObject.h" #include "systems/docking.h" +#include "systems/impulse.h" #include "packResourceProvider.h" #include "main.h" #include "epsilonServer.h" @@ -135,6 +136,7 @@ int main(int argc, char** argv) LOG(Info, "Starting..."); new Engine(); engine->registerSystem(); + engine->registerSystem(); string configuration_path = "."; if (getenv("HOME")) configuration_path = string(getenv("HOME")) + "/.emptyepsilon"; diff --git a/src/screenComponents/impulseControls.cpp b/src/screenComponents/impulseControls.cpp index cb328ba37e..6a7c0ce240 100644 --- a/src/screenComponents/impulseControls.cpp +++ b/src/screenComponents/impulseControls.cpp @@ -2,6 +2,7 @@ #include "playerInfo.h" #include "spaceObjects/playerSpaceship.h" #include "impulseControls.h" +#include "components/impulse.h" #include "powerDamageIndicator.h" #include "gui/gui2_keyvaluedisplay.h" #include "gui/gui2_slider.h" @@ -25,8 +26,11 @@ void GuiImpulseControls::onDraw(sp::RenderTarget& target) { if (my_spaceship) { - label->setValue(string(int(my_spaceship->current_impulse * 100)) + "%"); - slider->setValue(my_spaceship->impulse_request); + auto engine = my_spaceship->entity.getComponent(); + if (engine) { + label->setValue(string(int(engine->actual * 100)) + "%"); + slider->setValue(engine->request); + } } } @@ -34,21 +38,24 @@ void GuiImpulseControls::onUpdate() { if (my_spaceship && isVisible()) { - float change = keys.helms_increase_impulse.getValue() - keys.helms_decrease_impulse.getValue(); - if (change != 0.0f) - my_spaceship->commandImpulse(std::min(1.0f, slider->getValue() + change * 0.1f)); - if (keys.helms_zero_impulse.getDown()) - my_spaceship->commandImpulse(0.0f); - if (keys.helms_max_impulse.getDown()) - my_spaceship->commandImpulse(1.0f); - if (keys.helms_min_impulse.getDown()) - my_spaceship->commandImpulse(-1.0f); - - float set_value = keys.helms_set_impulse.getValue(); - if (set_value != my_spaceship->impulse_request && (set_value != 0.0f || set_active)) - { - my_spaceship->commandImpulse(set_value); - set_active = set_value != 0.0f; //Make sure the next update is send, even if it is back to zero. + auto engine = my_spaceship->entity.getComponent(); + if (engine) { + float change = keys.helms_increase_impulse.getValue() - keys.helms_decrease_impulse.getValue(); + if (change != 0.0f) + my_spaceship->commandImpulse(std::min(1.0f, slider->getValue() + change * 0.1f)); + if (keys.helms_zero_impulse.getDown()) + my_spaceship->commandImpulse(0.0f); + if (keys.helms_max_impulse.getDown()) + my_spaceship->commandImpulse(1.0f); + if (keys.helms_min_impulse.getDown()) + my_spaceship->commandImpulse(-1.0f); + + float set_value = keys.helms_set_impulse.getValue(); + if (set_value != engine->request && (set_value != 0.0f || set_active)) + { + my_spaceship->commandImpulse(set_value); + set_active = set_value != 0.0f; //Make sure the next update is send, even if it is back to zero. + } } } } diff --git a/src/screenComponents/impulseSound.cpp b/src/screenComponents/impulseSound.cpp index 198a878499..5f481e1071 100644 --- a/src/screenComponents/impulseSound.cpp +++ b/src/screenComponents/impulseSound.cpp @@ -1,6 +1,7 @@ #include "impulseSound.h" #include "playerInfo.h" #include "spaceObjects/playerSpaceship.h" +#include "components/impulse.h" #include "preferenceManager.h" #include "soundManager.h" @@ -12,8 +13,9 @@ ImpulseSound::ImpulseSound(bool enabled) impulse_sound_volume = PreferencesManager::get("impulse_sound_volume", "50").toInt(); // If defined, use this ship's impulse sound file. - if (my_spaceship) - impulse_sound_file = my_spaceship->impulse_sound_file; + ImpulseEngine* engine; + if (my_spaceship && (engine = my_spaceship->entity.getComponent())) + impulse_sound_file = engine->sound; else impulse_sound_file = "sfx/engine.wav"; @@ -57,14 +59,16 @@ void ImpulseSound::update(float delta) // Update only if an impulse sound is defined. if (impulse_sound_id > -1) { + if (!my_spaceship) return; + auto engine = my_spaceship->entity.getComponent(); // Get whether the ship's impulse engines are functional. float impulse_ability = std::max(0.0f, std::min(my_spaceship->getSystemEffectiveness(SYS_Impulse), my_spaceship->getSystemPower(SYS_Impulse))); // If so, update their pitch and volume. - if (impulse_ability > 0.0f) + if (impulse_ability > 0.0f && engine) { - soundManager->setSoundVolume(impulse_sound_id, (std::max(10.0f * impulse_ability, fabsf(my_spaceship->current_impulse) * 10.0f * std::max(0.1f, impulse_ability))) * (impulse_sound_volume / 100.0f)); - soundManager->setSoundPitch(impulse_sound_id, std::max(0.7f * impulse_ability, fabsf(my_spaceship->current_impulse) + 0.2f * std::max(0.1f, impulse_ability))); + soundManager->setSoundVolume(impulse_sound_id, (std::max(10.0f * impulse_ability, fabsf(engine->actual) * 10.0f * std::max(0.1f, impulse_ability))) * (impulse_sound_volume / 100.0f)); + soundManager->setSoundPitch(impulse_sound_id, std::max(0.7f * impulse_ability, fabsf(engine->actual) + 0.2f * std::max(0.1f, impulse_ability))); } else { // If not, silence the impulse sound. // TODO: Play an engine failure sound. diff --git a/src/screenComponents/powerDamageIndicator.cpp b/src/screenComponents/powerDamageIndicator.cpp index c54c6edb1f..524890cfe3 100644 --- a/src/screenComponents/powerDamageIndicator.cpp +++ b/src/screenComponents/powerDamageIndicator.cpp @@ -2,6 +2,7 @@ #include "spaceObjects/playerSpaceship.h" #include "powerDamageIndicator.h" #include "spaceObjects/warpJammer.h" +#include "components/reactor.h" #include "main.h" GuiPowerDamageIndicator::GuiPowerDamageIndicator(GuiContainer* owner, string name, ESystem system, sp::Alignment icon_align) @@ -13,6 +14,7 @@ void GuiPowerDamageIndicator::onDraw(sp::RenderTarget& renderer) { if (!my_spaceship) return; + auto reactor = my_spaceship->entity.getComponent(); glm::u8vec4 color; string display_text; @@ -40,7 +42,7 @@ void GuiPowerDamageIndicator::onDraw(sp::RenderTarget& renderer) { color = colorConfig.overlay_no_power; display_text = tr("systems", "NO POWER"); - }else if (my_spaceship->energy_level < 10) + }else if (reactor && reactor->energy < 10.0f) { color = colorConfig.overlay_low_energy; display_text = tr("systems", "LOW ENERGY"); @@ -124,7 +126,7 @@ void GuiPowerDamageIndicator::onDraw(sp::RenderTarget& renderer) { drawIcon(renderer, "gui/icons/status_low_power", colorConfig.overlay_low_power); } - if (my_spaceship->energy_level < 10) + if (reactor && reactor->energy < 10.0f) { drawIcon(renderer, "gui/icons/status_low_energy", colorConfig.overlay_low_energy); } diff --git a/src/screens/crew1/singlePilotScreen.cpp b/src/screens/crew1/singlePilotScreen.cpp index 4d5e1c2fd9..572f8477f5 100644 --- a/src/screens/crew1/singlePilotScreen.cpp +++ b/src/screens/crew1/singlePilotScreen.cpp @@ -4,6 +4,8 @@ #include "singlePilotScreen.h" #include "preferenceManager.h" +#include "components/reactor.h" + #include "screenComponents/viewport3d.h" #include "screenComponents/alertOverlay.h" @@ -114,7 +116,10 @@ void SinglePilotScreen::onDraw(sp::RenderTarget& renderer) { if (my_spaceship) { - energy_display->setValue(string(int(my_spaceship->energy_level))); + auto reactor = my_spaceship->entity.getComponent(); + energy_display->setVisible(reactor); + if (reactor) + energy_display->setValue(string(int(reactor->energy))); heading_display->setValue(string(my_spaceship->getHeading(), 1)); float velocity = glm::length(my_spaceship->getVelocity()) / 1000 * 60; velocity_display->setValue(tr("{value} {unit}/min").format({{"value", string(velocity, 1)}, {"unit", DISTANCE_UNIT_1K}})); diff --git a/src/screens/crew4/tacticalScreen.cpp b/src/screens/crew4/tacticalScreen.cpp index 232ecdc17d..be81c69c49 100644 --- a/src/screens/crew4/tacticalScreen.cpp +++ b/src/screens/crew4/tacticalScreen.cpp @@ -4,6 +4,8 @@ #include "tacticalScreen.h" #include "preferenceManager.h" +#include "components/reactor.h" + #include "screenComponents/combatManeuver.h" #include "screenComponents/radarView.h" #include "screenComponents/impulseControls.h" @@ -115,7 +117,10 @@ void TacticalScreen::onDraw(sp::RenderTarget& renderer) { if (my_spaceship) { - energy_display->setValue(string(int(my_spaceship->energy_level))); + auto reactor = my_spaceship->entity.getComponent(); + energy_display->setVisible(reactor); + if (reactor) + energy_display->setValue(string(int(reactor->energy))); heading_display->setValue(string(my_spaceship->getHeading(), 1)); float velocity = glm::length(my_spaceship->getVelocity()) / 1000 * 60; velocity_display->setValue(tr("{value} {unit}/min").format({{"value", string(velocity, 1)}, {"unit", DISTANCE_UNIT_1K}})); diff --git a/src/screens/crew6/engineeringScreen.cpp b/src/screens/crew6/engineeringScreen.cpp index cd5764d8cd..a07f60f1dc 100644 --- a/src/screens/crew6/engineeringScreen.cpp +++ b/src/screens/crew6/engineeringScreen.cpp @@ -2,6 +2,8 @@ #include "gameGlobalInfo.h" #include "engineeringScreen.h" +#include "components/reactor.h" + #include "screenComponents/shipInternalView.h" #include "screenComponents/selfDestructButton.h" #include "screenComponents/alertOverlay.h" @@ -174,29 +176,31 @@ void EngineeringScreen::onDraw(sp::RenderTarget& renderer) { if (my_spaceship) { - // Update the energy usage. - if (previous_energy_measurement == 0.0f) - { - previous_energy_level = my_spaceship->energy_level; - previous_energy_measurement = engine->getElapsedTime(); - }else{ - if (previous_energy_measurement != engine->getElapsedTime()) + auto reactor = my_spaceship->entity.getComponent(); + if (reactor) { + // Update the energy usage. + if (previous_energy_measurement == 0.0f) { - float delta_t = engine->getElapsedTime() - previous_energy_measurement; - float delta_e = my_spaceship->energy_level - previous_energy_level; - float delta_e_per_second = delta_e / delta_t; - average_energy_delta = average_energy_delta * 0.99f + delta_e_per_second * 0.01f; - - previous_energy_level = my_spaceship->energy_level; + previous_energy_level = reactor->energy; previous_energy_measurement = engine->getElapsedTime(); + }else{ + if (previous_energy_measurement != engine->getElapsedTime()) + { + float delta_t = engine->getElapsedTime() - previous_energy_measurement; + float delta_e = reactor->energy - previous_energy_level; + float delta_e_per_second = delta_e / delta_t; + average_energy_delta = average_energy_delta * 0.99f + delta_e_per_second * 0.01f; + + previous_energy_level = reactor->energy; + previous_energy_measurement = engine->getElapsedTime(); + } } + energy_display->setValue(toNearbyIntString(reactor->energy) + " (" + tr("{energy}/min").format({{"energy", toNearbyIntString(average_energy_delta * 60.0f)}}) + ")"); + if (reactor->energy < 100.0f) + energy_display->setColor(glm::u8vec4(255, 0, 0, 255)); + else + energy_display->setColor(glm::u8vec4{255,255,255,255}); } - - energy_display->setValue(toNearbyIntString(my_spaceship->energy_level) + " (" + tr("{energy}/min").format({{"energy", toNearbyIntString(average_energy_delta * 60.0f)}}) + ")"); - if (my_spaceship->energy_level < 100.0f) - energy_display->setColor(glm::u8vec4(255, 0, 0, 255)); - else - energy_display->setColor(glm::u8vec4{255,255,255,255}); hull_display->setValue(toNearbyIntString(100.0f * my_spaceship->hull_strength / my_spaceship->hull_max) + "%"); if (my_spaceship->hull_strength < my_spaceship->hull_max / 4.0f) hull_display->setColor(glm::u8vec4(255, 0, 0, 255)); @@ -267,7 +271,7 @@ void EngineeringScreen::onDraw(sp::RenderTarget& renderer) if (selected_system != SYS_None) { - ShipSystem& system = my_spaceship->systems[selected_system]; + auto& system = my_spaceship->systems[selected_system]; power_label->setText(tr("slider", "Power: {current_level}% / {requested}%").format({{"current_level", toNearbyIntString(system.power_level * 100)}, {"requested", toNearbyIntString(system.power_request * 100)}})); power_slider->setValue(system.power_request); coolant_label->setText(tr("slider", "Coolant: {current_level}% / {requested}%").format({{"current_level", toNearbyIntString(system.coolant_level / PlayerSpaceship::max_coolant_per_system * 100)}, {"requested", toNearbyIntString(std::min(system.coolant_request, my_spaceship->max_coolant) / PlayerSpaceship::max_coolant_per_system * 100)}})); diff --git a/src/screens/crew6/helmsScreen.cpp b/src/screens/crew6/helmsScreen.cpp index b29d492903..93865e8fdc 100644 --- a/src/screens/crew6/helmsScreen.cpp +++ b/src/screens/crew6/helmsScreen.cpp @@ -4,6 +4,8 @@ #include "helmsScreen.h" #include "preferenceManager.h" +#include "components/reactor.h" + #include "screenComponents/combatManeuver.h" #include "screenComponents/radarView.h" #include "screenComponents/impulseControls.h" @@ -93,7 +95,10 @@ void HelmsScreen::onDraw(sp::RenderTarget& renderer) { if (my_spaceship) { - energy_display->setValue(string(int(my_spaceship->energy_level))); + auto reactor = my_spaceship->entity.getComponent(); + energy_display->setVisible(reactor); + if (reactor) + energy_display->setValue(string(int(reactor->energy))); heading_display->setValue(string(my_spaceship->getHeading(), 1)); float velocity = glm::length(my_spaceship->getVelocity()) / 1000 * 60; velocity_display->setValue(tr("{value} {unit}/min").format({{"value", string(velocity, 1)}, {"unit", DISTANCE_UNIT_1K}})); diff --git a/src/screens/crew6/weaponsScreen.cpp b/src/screens/crew6/weaponsScreen.cpp index 24545d4691..4dbf64d300 100644 --- a/src/screens/crew6/weaponsScreen.cpp +++ b/src/screens/crew6/weaponsScreen.cpp @@ -4,6 +4,8 @@ #include "weaponsScreen.h" #include "preferenceManager.h" +#include "components/reactor.h" + #include "screenComponents/missileTubeControls.h" #include "screenComponents/aimLock.h" #include "screenComponents/beamFrequencySelector.h" @@ -99,7 +101,10 @@ void WeaponsScreen::onDraw(sp::RenderTarget& renderer) { if (my_spaceship) { - energy_display->setValue(string(int(my_spaceship->energy_level))); + auto reactor = my_spaceship->entity.getComponent(); + energy_display->setVisible(reactor); + if (reactor) + energy_display->setValue(string(int(reactor->energy))); front_shield_display->setValue(string(my_spaceship->getShieldPercentage(0)) + "%"); if (my_spaceship->hasSystem(SYS_FrontShield)) { diff --git a/src/screens/extra/powerManagement.cpp b/src/screens/extra/powerManagement.cpp index 9b7d78acfa..1352f0442d 100644 --- a/src/screens/extra/powerManagement.cpp +++ b/src/screens/extra/powerManagement.cpp @@ -1,5 +1,6 @@ #include "powerManagement.h" #include "missileWeaponData.h" +#include "components/reactor.h" #include "playerInfo.h" #include "spaceObjects/playerSpaceship.h" @@ -76,24 +77,27 @@ void PowerManagementScreen::onDraw(sp::RenderTarget& renderer) GuiOverlay::onDraw(renderer); if (my_spaceship) { - //Update the energy usage. - if (previous_energy_measurement == 0.0f) - { - previous_energy_level = my_spaceship->energy_level; - previous_energy_measurement = engine->getElapsedTime(); - }else{ - if (previous_energy_measurement != engine->getElapsedTime()) + auto reactor = my_spaceship->entity.getComponent(); + if (reactor) { + //Update the energy usage. + if (previous_energy_measurement == 0.0f) { - float delta_t = engine->getElapsedTime() - previous_energy_measurement; - float delta_e = my_spaceship->energy_level - previous_energy_level; - float delta_e_per_second = delta_e / delta_t; - average_energy_delta = average_energy_delta * 0.99f + delta_e_per_second * 0.01f; - - previous_energy_level = my_spaceship->energy_level; + previous_energy_level = reactor->energy; previous_energy_measurement = engine->getElapsedTime(); + }else{ + if (previous_energy_measurement != engine->getElapsedTime()) + { + float delta_t = engine->getElapsedTime() - previous_energy_measurement; + float delta_e = reactor->energy - previous_energy_level; + float delta_e_per_second = delta_e / delta_t; + average_energy_delta = average_energy_delta * 0.99f + delta_e_per_second * 0.01f; + + previous_energy_level = reactor->energy; + previous_energy_measurement = engine->getElapsedTime(); + } } + energy_display->setValue(string(int(reactor->energy)) + " (" + string(int(average_energy_delta * 60.0f)) + "/m)"); } - energy_display->setValue(string(int(my_spaceship->energy_level)) + " (" + string(int(average_energy_delta * 60.0f)) + "/m)"); coolant_display->setValue(string(int(my_spaceship->max_coolant * 10)) + "%"); for(int n=0; nsetSize(GuiElement::GuiSizeMax, 50); impulse_speed_slider = new GuiSlider(left_col, "", 0.0, 250, 0.0, [this](float value) { - target->impulse_max_speed = value; + //TODO: target->impulse_max_speed = value; }); impulse_speed_slider->addOverlay()->setSize(GuiElement::GuiSizeMax, 40); (new GuiLabel(left_col, "", tr("Impulse reverse speed:"), 30))->setSize(GuiElement::GuiSizeMax, 50); impulse_reverse_speed_slider = new GuiSlider(left_col, "", 0.0, 250, 0.0, [this](float value) { - target->impulse_max_reverse_speed = value; + //TODO: target->impulse_max_reverse_speed = value; }); impulse_reverse_speed_slider->addOverlay()->setSize(GuiElement::GuiSizeMax, 40); @@ -223,9 +223,9 @@ void GuiTweakShip::onDraw(sp::RenderTarget& renderer) jump_max_distance_slider->setValue(target->jump_drive_max_distance); type_name->setText(target->getTypeName()); warp_toggle->setValue(target->has_warp_drive); - jump_toggle->setValue(target->hasJumpDrive()); - impulse_speed_slider->setValue(target->impulse_max_speed); - impulse_reverse_speed_slider->setValue(target->impulse_max_reverse_speed); + jump_toggle->setValue(target->hasJumpDrive());\ + //TODO: impulse_speed_slider->setValue(target->impulse_max_speed); + //TODO: impulse_reverse_speed_slider->setValue(target->impulse_max_reverse_speed); turn_speed_slider->setValue(target->turn_speed); hull_max_slider->setValue(target->hull_max); can_be_destroyed_toggle->setValue(target->getCanBeDestroyed()); @@ -860,15 +860,15 @@ GuiShipTweakPlayer::GuiShipTweakPlayer(GuiContainer* owner) (new GuiLabel(left_col, "", tr("Max energy:"), 30))->setSize(GuiElement::GuiSizeMax, 50); max_energy_level_slider = new GuiSlider(left_col, "", 0.0, 2000, 0.0, [this](float value) { - target->max_energy_level = value; - target->energy_level = std::min(target->energy_level, target->max_energy_level); + //TODO: target->max_energy_level = value; + //TODO: target->energy_level = std::min(target->energy_level, target->max_energy_level); }); max_energy_level_slider->addOverlay()->setSize(GuiElement::GuiSizeMax, 40); (new GuiLabel(left_col, "", tr("Current energy:"), 30))->setSize(GuiElement::GuiSizeMax, 50); energy_level_slider = new GuiSlider(left_col, "", 0.0, 2000, 0.0, [this](float value) { - target->energy_level = std::min(value, target->max_energy_level); + //TODO: target->energy_level = std::min(value, target->max_energy_level); }); energy_level_slider->addOverlay()->setSize(GuiElement::GuiSizeMax, 40); @@ -932,8 +932,8 @@ void GuiShipTweakPlayer::onDraw(sp::RenderTarget& renderer) position_count->setText(tr("Positions occupied: ") + string(position_counter)); // Update the ship's energy level. - energy_level_slider->setValue(target->energy_level); - max_energy_level_slider->setValue(target->max_energy_level); + //TODO: energy_level_slider->setValue(target->energy_level); + //TODO: max_energy_level_slider->setValue(target->max_energy_level); // Update reputation points. reputation_point_slider->setValue(target->getReputationPoints()); diff --git a/src/spaceObjects/playerSpaceship.cpp b/src/spaceObjects/playerSpaceship.cpp index 2d977441c3..24b481c5ad 100644 --- a/src/spaceObjects/playerSpaceship.cpp +++ b/src/spaceObjects/playerSpaceship.cpp @@ -3,11 +3,14 @@ #include "repairCrew.h" #include "explosionEffect.h" #include "gameGlobalInfo.h" +#include "components/impulse.h" #include "main.h" #include "preferenceManager.h" #include "soundManager.h" #include "random.h" +#include "components/reactor.h" + #include "scriptInterface.h" #include @@ -352,10 +355,8 @@ PlayerSpaceship::PlayerSpaceship() registerMemberReplication(&can_launch_probe); registerMemberReplication(&hull_damage_indicator, 0.5); registerMemberReplication(&jump_indicator, 0.5); - registerMemberReplication(&energy_level, 0.1); registerMemberReplication(&energy_warp_per_second, .5f); registerMemberReplication(&energy_shield_use_per_second, .5f); - registerMemberReplication(&max_energy_level); registerMemberReplication(&main_screen_setting); registerMemberReplication(&main_screen_overlay); registerMemberReplication(&scanning_delay, 0.5); @@ -401,12 +402,12 @@ PlayerSpaceship::PlayerSpaceship() SDL_assert(n < default_system_power_factors.size()); systems[n].health = 1.0f; systems[n].power_level = 1.0f; - systems[n].power_rate_per_second = ShipSystem::default_power_rate_per_second; + systems[n].power_rate_per_second = ShipSystemLegacy::default_power_rate_per_second; systems[n].power_request = 1.0f; systems[n].coolant_level = 0.0f; - systems[n].coolant_rate_per_second = ShipSystem::default_coolant_rate_per_second; + systems[n].coolant_rate_per_second = ShipSystemLegacy::default_coolant_rate_per_second; systems[n].heat_level = 0.0f; - systems[n].heat_rate_per_second = ShipSystem::default_heat_rate_per_second; + systems[n].heat_rate_per_second = ShipSystemLegacy::default_heat_rate_per_second; systems[n].power_factor = default_system_power_factors[n]; registerMemberReplication(&systems[n].power_level); @@ -530,7 +531,12 @@ void PlayerSpaceship::update(float delta) useEnergy(delta * getEnergyShieldUsePerSecond()); // Consume power based on subsystem requests and state. - energy_level += delta * getNetSystemEnergyUsage(); + auto reactor = entity.getComponent(); + if (reactor) { + reactor->energy += delta * getNetSystemEnergyUsage(); + // Cap energy at the max_energy_level. + reactor->energy = std::clamp(reactor->energy, 0.0f, reactor->max_energy); + } // Check how much coolant we have requested in total, and if that's beyond the // amount of coolant we have, see how much we need to adjust our request. @@ -595,11 +601,8 @@ void PlayerSpaceship::update(float delta) return; } - if (energy_level < 0.0f) - energy_level = 0.0f; - // If the ship has less than 10 energy, drop shields automatically. - if (energy_level < 10.0f) + if (reactor && reactor->energy < 10.0f) { shields_active = false; } @@ -691,10 +694,6 @@ void PlayerSpaceship::update(float delta) // Perform all other ship update actions. SpaceShip::update(delta); - - // Cap energy at the max_energy_level. - if (energy_level > max_energy_level) - energy_level = max_energy_level; } void PlayerSpaceship::applyTemplateValues() @@ -749,18 +748,6 @@ void PlayerSpaceship::setSystemCoolantRequest(ESystem system, float request) systems[system].coolant_request = request; } -bool PlayerSpaceship::useEnergy(float amount) -{ - // Try to consume an amount of energy. If it works, return true. - // If it doesn't, return false. - if (energy_level >= amount) - { - energy_level -= amount; - return true; - } - return false; -} - void PlayerSpaceship::addHeat(ESystem system, float amount) { // Add heat to a subsystem if it's present. @@ -1131,6 +1118,11 @@ void PlayerSpaceship::closeComms() } } +void PlayerSpaceship::setEnergyLevel(float amount) {} //TODO +void PlayerSpaceship::setEnergyLevelMax(float amount) {} //TODO +float PlayerSpaceship::getEnergyLevel() { return 0.0f; } //TODO +float PlayerSpaceship::getEnergyLevelMax() { return 0.0f; } //TODO + void PlayerSpaceship::setCanDock(bool enabled) { if (!enabled) { @@ -1165,9 +1157,15 @@ void PlayerSpaceship::onReceiveClientCommand(int32_t client_id, sp::io::DataBuff target_rotation = getRotation(); packet >> turnSpeed; break; - case CMD_IMPULSE: - packet >> impulse_request; - break; + case CMD_IMPULSE:{ + auto engine = entity.getComponent(); + if (engine) + packet >> engine->request; + else { + float f; + packet >> f; + } + } break; case CMD_WARP: packet >> warp_request; break; @@ -2053,17 +2051,17 @@ string PlayerSpaceship::getExportLine() result += ":setSystemPowerFactor(" + string(system) + ", " + string(current_factor, 1) + ")"; } - if (std::fabs(getSystemCoolantRate(system) - ShipSystem::default_coolant_rate_per_second) > std::numeric_limits::epsilon()) + if (std::fabs(getSystemCoolantRate(system) - ShipSystemLegacy::default_coolant_rate_per_second) > std::numeric_limits::epsilon()) { result += ":setSystemCoolantRate(" + string(system) + ", " + string(getSystemCoolantRate(system), 2) + ")"; } - if (std::fabs(getSystemHeatRate(system) - ShipSystem::default_heat_rate_per_second) > std::numeric_limits::epsilon()) + if (std::fabs(getSystemHeatRate(system) - ShipSystemLegacy::default_heat_rate_per_second) > std::numeric_limits::epsilon()) { result += ":setSystemHeatRate(" + string(system) + ", " + string(getSystemHeatRate(system), 2) + ")"; } - if (std::fabs(getSystemPowerRate(system) - ShipSystem::default_power_rate_per_second) > std::numeric_limits::epsilon()) + if (std::fabs(getSystemPowerRate(system) - ShipSystemLegacy::default_power_rate_per_second) > std::numeric_limits::epsilon()) { result += ":setSystemPowerRate(" + string(system) + ", " + string(getSystemPowerRate(system), 2) + ")"; } diff --git a/src/spaceObjects/playerSpaceship.h b/src/spaceObjects/playerSpaceship.h index ee76fbfd56..d209aead74 100644 --- a/src/spaceObjects/playerSpaceship.h +++ b/src/spaceObjects/playerSpaceship.h @@ -196,10 +196,11 @@ class PlayerSpaceship : public SpaceShip void switchCommsToGM(); void closeComms(); - void setEnergyLevel(float amount) { energy_level = std::max(0.0f, std::min(max_energy_level, amount)); } - void setEnergyLevelMax(float amount) { max_energy_level = std::max(0.0f, amount); energy_level = std::min(energy_level, max_energy_level); } - float getEnergyLevel() { return energy_level; } - float getEnergyLevelMax() { return max_energy_level; } + //Spaceship also has functions for these?!? + void setEnergyLevel(float amount); + void setEnergyLevelMax(float amount); + float getEnergyLevel(); + float getEnergyLevelMax(); void setCanScan(bool enabled) { can_scan = enabled; } bool getCanScan() { return can_scan; } @@ -307,7 +308,6 @@ class PlayerSpaceship : public SpaceShip // Ship update functions virtual void update(float delta) override; - virtual bool useEnergy(float amount) override; virtual void addHeat(ESystem system, float amount) override; // Call on the server to play a sound on the main screen. diff --git a/src/spaceObjects/shipTemplateBasedObject.cpp b/src/spaceObjects/shipTemplateBasedObject.cpp index 0bf70a4d2d..29cdd12ecc 100644 --- a/src/spaceObjects/shipTemplateBasedObject.cpp +++ b/src/spaceObjects/shipTemplateBasedObject.cpp @@ -3,6 +3,7 @@ #include "scriptInterface.h" #include "components/collision.h" #include "components/docking.h" +#include "components/impulse.h" #include "tween.h" #include "i18n.h" @@ -133,7 +134,6 @@ ShipTemplateBasedObject::ShipTemplateBasedObject(float collision_range, string m registerMemberReplication(&shield_max[n]); registerMemberReplication(&shield_hit_effect[n], 0.5); } - registerMemberReplication(&impulse_sound_file); registerMemberReplication(&hull_strength, 0.5); registerMemberReplication(&hull_max); registerMemberReplication(&long_range_radar_range, 0.5); @@ -405,8 +405,6 @@ void ShipTemplateBasedObject::setTemplate(string template_name) } } - impulse_sound_file = ship_template->impulse_sound_file; - ship_template->setCollisionData(this); model_info.setData(ship_template->model_data); @@ -448,6 +446,11 @@ void ShipTemplateBasedObject::setRadarTrace(string trace) entity.getOrAddComponent().icon = "radar/" + trace; } +void ShipTemplateBasedObject::setImpulseSoundFile(string sound) +{ + //TODO +} + bool ShipTemplateBasedObject::getSharesEnergyWithDocked() { return false;//TODO diff --git a/src/spaceObjects/shipTemplateBasedObject.h b/src/spaceObjects/shipTemplateBasedObject.h index 8e64947fb6..34198fac71 100644 --- a/src/spaceObjects/shipTemplateBasedObject.h +++ b/src/spaceObjects/shipTemplateBasedObject.h @@ -20,7 +20,6 @@ class ShipTemplateBasedObject : public SpaceObject, public Updatable public: string template_name; string type_name; - string impulse_sound_file; P ship_template; int shield_count; @@ -92,7 +91,7 @@ class ShipTemplateBasedObject : public SpaceObject, public Updatable void setShortRangeRadarRange(float range) { range = std::max(range, 100.0f); short_range_radar_range = range; long_range_radar_range = std::max(long_range_radar_range, range); } void setRadarTrace(string trace); - void setImpulseSoundFile(string sound) { impulse_sound_file = sound; } + void setImpulseSoundFile(string sound); bool getSharesEnergyWithDocked(); void setSharesEnergyWithDocked(bool enabled); diff --git a/src/spaceObjects/spaceship.cpp b/src/spaceObjects/spaceship.cpp index 43075a2f7c..f0fd27b8b5 100644 --- a/src/spaceObjects/spaceship.cpp +++ b/src/spaceObjects/spaceship.cpp @@ -18,6 +18,8 @@ #include "gameGlobalInfo.h" #include "components/collision.h" #include "components/docking.h" +#include "components/impulse.h" +#include "components/reactor.h" #include "scriptInterface.h" @@ -177,8 +179,6 @@ SpaceShip::SpaceShip(string multiplayerClassName, float multiplayer_significant_ : ShipTemplateBasedObject(50, multiplayerClassName, multiplayer_significant_range) { target_rotation = getRotation(); - impulse_request = 0; - current_impulse = 0; has_warp_drive = true; warp_request = 0; current_warp = 0; @@ -192,8 +192,6 @@ SpaceShip::SpaceShip(string multiplayerClassName, float multiplayer_significant_ wormhole_alpha = 0.f; weapon_tube_count = 0; turn_speed = 10.f; - impulse_max_speed = 600.f; - impulse_max_reverse_speed = 600.f; combat_maneuver_charge = 1.f; combat_maneuver_boost_request = 0.f; combat_maneuver_boost_active = 0.f; @@ -205,16 +203,10 @@ SpaceShip::SpaceShip(string multiplayerClassName, float multiplayer_significant_ beam_frequency = irandom(0, max_frequency); beam_system_target = SYS_None; shield_frequency = irandom(0, max_frequency); - impulse_acceleration = 20.f; - impulse_reverse_acceleration = 20.f; - energy_level = 1000; - max_energy_level = 1000; turnSpeed = 0.0f; registerMemberReplication(&target_rotation, 1.5f); registerMemberReplication(&turnSpeed, 0.1f); - registerMemberReplication(&impulse_request, 0.1f); - registerMemberReplication(¤t_impulse, 0.5f); registerMemberReplication(&has_warp_drive); registerMemberReplication(&warp_request, 0.1f); registerMemberReplication(¤t_warp, 0.1f); @@ -227,10 +219,6 @@ SpaceShip::SpaceShip(string multiplayerClassName, float multiplayer_significant_ registerMemberReplication(&weapon_tube_count); registerMemberReplication(&target_id); registerMemberReplication(&turn_speed); - registerMemberReplication(&impulse_max_speed); - registerMemberReplication(&impulse_max_reverse_speed); - registerMemberReplication(&impulse_acceleration); - registerMemberReplication(&impulse_reverse_acceleration); registerMemberReplication(&warp_speed_per_warp_level); registerMemberReplication(&shield_frequency); registerMemberReplication(&beam_frequency); @@ -248,13 +236,13 @@ SpaceShip::SpaceShip(string multiplayerClassName, float multiplayer_significant_ systems[n].health = 1.0f; systems[n].health_max = 1.0f; systems[n].power_level = 1.0f; - systems[n].power_rate_per_second = ShipSystem::default_power_rate_per_second; + systems[n].power_rate_per_second = ShipSystemLegacy::default_power_rate_per_second; systems[n].power_request = 1.0f; systems[n].coolant_level = 0.0f; - systems[n].coolant_rate_per_second = ShipSystem::default_coolant_rate_per_second; + systems[n].coolant_rate_per_second = ShipSystemLegacy::default_coolant_rate_per_second; systems[n].coolant_request = 0.0f; systems[n].heat_level = 0.0f; - systems[n].heat_rate_per_second = ShipSystem::default_heat_rate_per_second; + systems[n].heat_rate_per_second = ShipSystemLegacy::default_heat_rate_per_second; systems[n].hacked_level = 0.0f; systems[n].power_factor = default_system_power_factors[n]; @@ -321,12 +309,21 @@ void SpaceShip::applyTemplateValues() beam_weapons[n].setHeatPerFire(ship_template->beams[n].getHeatPerFire()); } weapon_tube_count = ship_template->weapon_tube_count; - energy_level = max_energy_level = ship_template->energy_storage_amount; - impulse_max_speed = ship_template->impulse_speed; - impulse_max_reverse_speed = ship_template->impulse_reverse_speed; - impulse_acceleration = ship_template->impulse_acceleration; - impulse_reverse_acceleration = ship_template->impulse_reverse_acceleration; + if (ship_template->energy_storage_amount) { + auto& reactor = entity.getOrAddComponent(); + reactor.energy = reactor.max_energy = ship_template->energy_storage_amount; + } + + + if (ship_template->impulse_speed) { + auto& engine = entity.getOrAddComponent(); + engine.max_speed_forward = ship_template->impulse_speed; + engine.max_speed_reverse = ship_template->impulse_reverse_speed; + engine.acceleration_forward = ship_template->impulse_acceleration; + engine.acceleration_reverse = ship_template->impulse_reverse_acceleration; + engine.sound = ship_template->impulse_sound_file; + } turn_speed = ship_template->turn_speed; combat_maneuver_boost_speed = ship_template->combat_maneuver_boost_speed; @@ -635,130 +632,6 @@ void SpaceShip::update(float delta) physics->setAngularVelocity(rotationDiff * turn_speed * getSystemEffectiveness(SYS_Maneuver)); } - //Here we want to have max speed at 100% impulse, and max reverse speed at -100% impulse - float cap_speed = impulse_max_speed; - - if(current_impulse < 0 && impulse_max_reverse_speed <= 0.01f) - { - current_impulse = 0; //we could get stuck with a ship with no reverse speed, not being able to accelerate - } - if(current_impulse < 0) - { - cap_speed = impulse_max_reverse_speed; - } - if ((has_jump_drive && jump_delay > 0) || (has_warp_drive && warp_request > 0)) - { - if (WarpJammer::isWarpJammed(getPosition())) - { - jump_delay = 0; - warp_request = 0; - } - } - if (has_jump_drive && jump_delay > 0) - { - if (current_impulse > 0.0f) - { - if (cap_speed > 0) - current_impulse -= delta * (impulse_reverse_acceleration / cap_speed); - if (current_impulse < 0.0f) - current_impulse = 0.f; - } - if (current_impulse < 0.0f) - { - if (cap_speed > 0) - current_impulse += delta * (impulse_acceleration / cap_speed); - if (current_impulse > 0.0f) - current_impulse = 0.f; - } - if (current_warp > 0.0f) - { - current_warp -= delta; - if (current_warp < 0.0f) - current_warp = 0.f; - } - jump_delay -= delta * getSystemEffectiveness(SYS_JumpDrive); - if (jump_delay <= 0.0f) - { - executeJump(jump_distance); - jump_delay = 0.f; - } - }else if (has_warp_drive && (warp_request > 0 || current_warp > 0)) - { - if (current_impulse > 0.0f) - { - if (cap_speed > 0) - current_impulse -= delta * (impulse_reverse_acceleration / cap_speed); - if (current_impulse < 0.0f) - current_impulse = 0.0f; - }else if (current_impulse < 0.0f) - { - if (cap_speed > 0) - current_impulse += delta * (impulse_acceleration / cap_speed); - if (current_impulse > 0.0f) - current_impulse = 0.0f; - }else{ - if (current_warp < warp_request) - { - current_warp += delta / warp_charge_time; - if (current_warp > warp_request) - current_warp = warp_request; - }else if (current_warp > warp_request) - { - current_warp -= delta / warp_decharge_time; - if (current_warp < warp_request) - current_warp = warp_request; - } - } - }else{ - if (has_jump_drive) - { - float f = getJumpDriveRechargeRate(); - if (f > 0) - { - if (jump_drive_charge < jump_drive_max_distance) - { - float extra_charge = (delta / jump_drive_charge_time * jump_drive_max_distance) * f; - if (useEnergy(extra_charge * jump_drive_energy_per_km_charge / 1000.0f)) - { - jump_drive_charge += extra_charge; - if (jump_drive_charge >= jump_drive_max_distance) - jump_drive_charge = jump_drive_max_distance; - } - } - }else{ - jump_drive_charge += (delta / jump_drive_charge_time * jump_drive_max_distance) * f; - if (jump_drive_charge < 0.0f) - jump_drive_charge = 0.0f; - } - } - current_warp = 0.f; - if (impulse_request > 1.0f) - impulse_request = 1.0f; - if (impulse_request < -1.0f) - impulse_request = -1.0f; - if (current_impulse < impulse_request) - { - if (cap_speed > 0) - current_impulse += delta * (impulse_acceleration / cap_speed); - if (current_impulse > impulse_request) - current_impulse = impulse_request; - }else if (current_impulse > impulse_request) - { - if (cap_speed > 0) - current_impulse -= delta * (impulse_reverse_acceleration / cap_speed); - if (current_impulse < impulse_request) - current_impulse = impulse_request; - } - } - - // Add heat based on warp factor. - addHeat(SYS_Warp, current_warp * delta * heat_per_warp * getSystemEffectiveness(SYS_Warp)); - - // Determine forward direction and velocity. - auto forward = vec2FromAngle(getRotation()); - if (physics) - physics->setVelocity(forward * (current_impulse * cap_speed * getSystemEffectiveness(SYS_Impulse) + current_warp * warp_speed_per_warp_level * getSystemEffectiveness(SYS_Warp))); - if (combat_maneuver_boost_active > combat_maneuver_boost_request) { combat_maneuver_boost_active -= delta; @@ -799,6 +672,7 @@ void SpaceShip::update(float delta) combat_maneuver_strafe_request = 0.0f; }else if (physics) { + auto forward = vec2FromAngle(getRotation()); physics->setVelocity(physics->getVelocity() + forward * combat_maneuver_boost_speed * combat_maneuver_boost_active); physics->setVelocity(physics->getVelocity() + vec2FromAngle(getRotation() + 90) * combat_maneuver_strafe_speed * combat_maneuver_strafe_active); } @@ -830,7 +704,11 @@ void SpaceShip::update(float delta) systems[n].health = std::min(systems[n].health,systems[n].health_max); } - model_info.engine_scale = std::min(1.0f, (float) std::max(fabs(getAngularVelocity() / turn_speed), fabs(current_impulse))); + model_info.engine_scale = std::abs(getAngularVelocity() / turn_speed); + auto impulse = entity.getComponent(); + if (impulse) + model_info.engine_scale = std::max(model_info.engine_scale, std::abs(impulse->actual)); + model_info.engine_scale = std::min(1.0f, model_info.engine_scale); if (has_jump_drive && jump_delay > 0.0f) model_info.warp_scale = (10.0f - jump_delay) / 10.0f; else @@ -917,7 +795,8 @@ void SpaceShip::requestUndock() if (getSystemEffectiveness(SYS_Impulse) < 0.1f) return; docking_port->state = DockingPort::State::NotDocking; - impulse_request = 0.5; + auto engine = entity.getComponent(); + if (engine) engine->request = 0.5; } void SpaceShip::abortDock() @@ -926,11 +805,23 @@ void SpaceShip::abortDock() if (!docking_port || docking_port->state != DockingPort::State::Docking) return; docking_port->state = DockingPort::State::NotDocking; - impulse_request = 0.f; + auto engine = entity.getComponent(); + if (engine) engine->request = 0.f; warp_request = 0; target_rotation = getRotation(); } +bool SpaceShip::useEnergy(float amount) +{ + // Try to consume an amount of energy. If it works, return true. + // If it doesn't, return false. + auto reactor = entity.getComponent(); + if (reactor) + return reactor->use_energy(amount); + return true; +} + + int SpaceShip::scanningComplexity(P other) { if (scanning_complexity_value > -1) @@ -1194,7 +1085,7 @@ bool SpaceShip::hasSystem(ESystem system) case SYS_Maneuver: return turn_speed > 0.0f; case SYS_Impulse: - return impulse_max_speed > 0.0f; + return entity.hasComponent(); } return true; } @@ -1209,10 +1100,13 @@ float SpaceShip::getSystemEffectiveness(ESystem system) // Degrade all systems except the reactor once energy level drops below 10. if (system != SYS_Reactor) { - if (energy_level < 10.0f && energy_level > 0.0f && power > 0.0f) - power = std::min(power * energy_level / 10.0f, power); - else if (energy_level <= 0.0f || power <= 0.0f) - power = 0.0f; + auto reactor = entity.getComponent(); + if (reactor) { + if (reactor->energy < 10.0f && reactor->energy > 0.0f && power > 0.0f) + power = std::min(power * reactor->energy / 10.0f, power); + else if (reactor->energy <= 0.0f || power <= 0.0f) + power = 0.0f; + } } // Degrade damaged systems. @@ -1380,6 +1274,32 @@ DockingPort::State SpaceShip::getDockingState() return port->state; } +float SpaceShip::getMaxEnergy() { return 0.0f; } // TODO +void SpaceShip::setMaxEnergy(float amount) {} // TODO +float SpaceShip::getEnergy() { return 0.0f; } // TODO +void SpaceShip::setEnergy(float amount) {} // TODO + +Speeds SpaceShip::getAcceleration() +{ + //TODO + return {0.0f, 0.0f}; +} + +void SpaceShip::setAcceleration(float acceleration, std::optional reverse_acceleration) +{ + //TODO +} + +Speeds SpaceShip::getImpulseMaxSpeed() +{ + //TODO + return {0.0f, 0.0f}; +} +void SpaceShip::setImpulseMaxSpeed(float forward_speed, std::optional reverse_speed) +{ + //TODO +} + string SpaceShip::getScriptExportModificationsOnTemplate() { @@ -1395,10 +1315,10 @@ string SpaceShip::getScriptExportModificationsOnTemplate() ret += ":setHullMax(" + string(hull_max, 0) + ")"; if (hull_strength != ship_template->hull) ret += ":setHull(" + string(hull_strength, 0) + ")"; - if (impulse_max_speed != ship_template->impulse_speed) - ret += ":setImpulseMaxSpeed(" + string(impulse_max_speed, 1) + ")"; - if (impulse_max_reverse_speed != ship_template->impulse_reverse_speed) - ret += ":setImpulseMaxReverseSpeed(" + string(impulse_max_reverse_speed, 1) + ")"; + //if (impulse_max_speed != ship_template->impulse_speed) + // ret += ":setImpulseMaxSpeed(" + string(impulse_max_speed, 1) + ")"; + //if (impulse_max_reverse_speed != ship_template->impulse_reverse_speed) + // ret += ":setImpulseMaxReverseSpeed(" + string(impulse_max_reverse_speed, 1) + ")"; if (turn_speed != ship_template->turn_speed) ret += ":setRotationMaxSpeed(" + string(turn_speed, 1) + ")"; if (has_jump_drive != ship_template->has_jump_drive) diff --git a/src/spaceObjects/spaceship.h b/src/spaceObjects/spaceship.h index b9e3a5a97b..dc6b0c17a7 100644 --- a/src/spaceObjects/spaceship.h +++ b/src/spaceObjects/spaceship.h @@ -40,7 +40,7 @@ struct Speeds template<> int convert::returnType(lua_State* L, const Speeds &speeds); -class ShipSystem +class ShipSystemLegacy { public: static constexpr float power_factor_rate = 0.08f; @@ -88,9 +88,7 @@ class SpaceShip : public ShipTemplateBasedObject constexpr static float heat_per_warp = 0.02f; constexpr static float unhack_time = 180.0f; //It takes this amount of time to go from 100% hacked to 0% hacked for systems. - float energy_level; - float max_energy_level; - ShipSystem systems[SYS_COUNT]; + ShipSystemLegacy systems[SYS_COUNT]; static std::array default_system_power_factors; /*! *[input] Ship will try to aim to this rotation. (degrees) @@ -102,41 +100,11 @@ class SpaceShip : public ShipTemplateBasedObject */ float turnSpeed; - /*! - * [input] Amount of impulse requested from the user (-1.0 to 1.0) - */ - float impulse_request; - - /*! - * [output] Amount of actual impulse from the engines (-1.0 to 1.0) - */ - float current_impulse; - /*! * [config] Speed of rotation, in deg/second */ float turn_speed; - /*! - * [config] Max speed of the impulse engines, in m/s - */ - float impulse_max_speed; - - /*! - * [config] Max speed of the reverse impulse engines, in m/s - */ - float impulse_max_reverse_speed; - - /*! - * [config] Impulse engine acceleration, in (m/s)/s - */ - float impulse_acceleration; - - /*! - * [config] Impulse engine acceleration in reverse, in (m/s)/s - */ - float impulse_reverse_acceleration; - /*! * [config] True if we have a warpdrive. */ @@ -278,8 +246,8 @@ class SpaceShip : public ShipTemplateBasedObject */ void abortDock(); - /// Dummy virtual function to use energy. Only player ships currently model energy use. - virtual bool useEnergy(float amount) { return true; } + /// Function to use energy. Only player ships currently model energy use. + bool useEnergy(float amount); /// Dummy virtual function to add heat on a system. The player ship class has an actual implementation of this as only player ships model heat right now. virtual void addHeat(ESystem system, float amount) {} @@ -328,10 +296,10 @@ class SpaceShip : public ShipTemplateBasedObject int getWeaponStorageMax(EMissileWeapons weapon) { if (weapon == MW_None) return 0; return weapon_storage_max[weapon]; } void setWeaponStorage(EMissileWeapons weapon, int amount) { if (weapon == MW_None) return; weapon_storage[weapon] = amount; } void setWeaponStorageMax(EMissileWeapons weapon, int amount) { if (weapon == MW_None) return; weapon_storage_max[weapon] = amount; weapon_storage[weapon] = std::min(int(weapon_storage[weapon]), amount); } - float getMaxEnergy() { return max_energy_level; } - void setMaxEnergy(float amount) { if (amount > 0.0f) { max_energy_level = amount;} } - float getEnergy() { return energy_level; } - void setEnergy(float amount) { if ( (amount > 0.0f) && (amount <= max_energy_level)) { energy_level = amount; } } + float getMaxEnergy(); + void setMaxEnergy(float amount); + float getEnergy(); + void setEnergy(float amount); float getSystemHackedLevel(ESystem system) { if (system >= SYS_COUNT) return 0.0; if (system <= SYS_None) return 0.0; return systems[system].hacked_level; } void setSystemHackedLevel(ESystem system, float hacked_level) { if (system >= SYS_COUNT) return; if (system <= SYS_None) return; systems[system].hacked_level = std::min(1.0f, std::max(0.0f, hacked_level)); } float getSystemHealth(ESystem system) { if (system >= SYS_COUNT) return 0.0; if (system <= SYS_None) return 0.0; return systems[system].health; } @@ -352,22 +320,14 @@ class SpaceShip : public ShipTemplateBasedObject void setSystemPowerFactor(ESystem system, float factor) { if (system >= SYS_COUNT) return; if (system <= SYS_None) return; systems[system].power_factor = factor; } float getSystemCoolant(ESystem system) { if (system >= SYS_COUNT) return 0.0; if (system <= SYS_None) return 0.0; return systems[system].coolant_level; } void setSystemCoolant(ESystem system, float coolant) { if (system >= SYS_COUNT) return; if (system <= SYS_None) return; systems[system].coolant_level = std::min(1.0f, std::max(0.0f, coolant)); } - Speeds getImpulseMaxSpeed() {return {impulse_max_speed, impulse_max_reverse_speed};} - void setImpulseMaxSpeed(float forward_speed, std::optional reverse_speed) - { - impulse_max_speed = forward_speed; - impulse_max_reverse_speed = reverse_speed.value_or(forward_speed); - } + Speeds getImpulseMaxSpeed(); + void setImpulseMaxSpeed(float forward_speed, std::optional reverse_speed); float getSystemCoolantRate(ESystem system) const { if (system >= SYS_COUNT) return 0.f; if (system <= SYS_None) return 0.f; return systems[system].coolant_rate_per_second; } void setSystemCoolantRate(ESystem system, float rate) { if (system >= SYS_COUNT) return; if (system <= SYS_None) return; systems[system].coolant_rate_per_second = rate; } float getRotationMaxSpeed() { return turn_speed; } void setRotationMaxSpeed(float speed) { turn_speed = speed; } - Speeds getAcceleration() { return {impulse_acceleration, impulse_reverse_acceleration};} - void setAcceleration(float acceleration, std::optional reverse_acceleration) - { - impulse_acceleration = acceleration; - impulse_reverse_acceleration = reverse_acceleration.value_or(acceleration); - } + Speeds getAcceleration(); + void setAcceleration(float acceleration, std::optional reverse_acceleration); void setCombatManeuver(float boost, float strafe) { combat_maneuver_boost_speed = boost; combat_maneuver_strafe_speed = strafe; } bool hasJumpDrive() { return has_jump_drive; } void setJumpDrive(bool has_jump) { has_jump_drive = has_jump; } diff --git a/src/spaceObjects/supplyDrop.cpp b/src/spaceObjects/supplyDrop.cpp index 34f767740c..e8c8bf2ec7 100644 --- a/src/spaceObjects/supplyDrop.cpp +++ b/src/spaceObjects/supplyDrop.cpp @@ -2,6 +2,7 @@ #include "spaceship.h" #include "playerInfo.h" #include "playerSpaceship.h" +#include "components/reactor.h" #include "main.h" #include "scriptInterface.h" @@ -44,10 +45,10 @@ void SupplyDrop::collide(SpaceObject* target, float force) if (ship && isFriendly(ship)) { bool picked_up = false; - P player = ship; - if (player) + auto reactor = ship->entity.getComponent(); + if (reactor) { - player->energy_level += energy; + reactor->energy += energy; picked_up = true; } for(int n=0; n(P(this), player); + on_pickup_callback.call(P(this), ship); picked_up = true; } diff --git a/src/systems/docking.cpp b/src/systems/docking.cpp index 07aaeb7aba..949d445160 100644 --- a/src/systems/docking.cpp +++ b/src/systems/docking.cpp @@ -1,6 +1,8 @@ #include "systems/docking.h" #include "components/docking.h" #include "components/collision.h" +#include "components/impulse.h" +#include "components/reactor.h" #include "spaceObjects/spaceship.h" #include "spaceObjects/playerSpaceship.h" #include "spaceObjects/cpuShip.h" @@ -17,7 +19,7 @@ void DockingSystem::update(float delta) { if (!game_server) return; - for(auto [entity, docking_port, position, obj] : sp::ecs::Query, SpaceObject*>()) { + for(auto [entity, docking_port, position, engine, obj] : sp::ecs::Query, sp::ecs::optional, SpaceObject*>()) { SpaceShip* ship = dynamic_cast(obj); PlayerSpaceship* player = dynamic_cast(obj); if (!ship) continue; @@ -30,10 +32,12 @@ void DockingSystem::update(float delta) docking_port.state = DockingPort::State::NotDocking; } else { ship->target_rotation = vec2ToAngle(position->getPosition() - target_position->getPosition()); - if (fabs(angleDifference(ship->target_rotation, position->getRotation())) < 10.0f) - ship->impulse_request = -1.f; - else - ship->impulse_request = 0.f; + if (engine) { + if (fabs(angleDifference(ship->target_rotation, position->getRotation())) < 10.0f) + engine->request = -1.f; + else + engine->request = 0.f; + } ship->warp_request = 0.f; } break; @@ -62,17 +66,20 @@ void DockingSystem::update(float delta) } if (bay && (bay->flags & DockingBay::ShareEnergy)) { - auto target_ship = dynamic_cast(*docking_port.target.getComponent()); - // Derive a base energy request rate from the player ship's maximum - // energy capacity. - float energy_request = std::min(delta * 10.0f, player->max_energy_level - player->energy_level); + auto my_reactor = entity.getComponent(); + if (my_reactor) { + auto other_reactor = docking_port.target.getComponent(); + // Derive a base energy request rate from the player ship's maximum + // energy capacity. + float energy_request = std::min(delta * 10.0f, my_reactor->max_energy - my_reactor->energy); - // If we're docked with a shipTemplateBasedObject, and that object is - // set to share its energy with docked ships, transfer energy from the - // mothership to docked ships until the mothership runs out of energy - // or the docked ship doesn't require any. - if (!target_ship || target_ship->useEnergy(energy_request)) - ship->energy_level += energy_request; + // If we're docked with a shipTemplateBasedObject, and that object is + // set to share its energy with docked ships, transfer energy from the + // mothership to docked ships until the mothership runs out of energy + // or the docked ship doesn't require any. + if (!other_reactor || other_reactor->use_energy(energy_request)) + my_reactor->energy += energy_request; + } } if (player && bay && (bay->flags & DockingBay::RestockProbes)) { @@ -116,7 +123,9 @@ void DockingSystem::update(float delta) } } } - ship->impulse_request = 0.f; + + if (engine) + engine->request = 0.f; ship->warp_request = 0.f; break; } diff --git a/src/systems/impulse.cpp b/src/systems/impulse.cpp new file mode 100644 index 0000000000..0f0018d449 --- /dev/null +++ b/src/systems/impulse.cpp @@ -0,0 +1,142 @@ +#include "systems/impulse.h" +#include "components/docking.h" +#include "components/collision.h" +#include "components/impulse.h" +#include "spaceObjects/spaceship.h" +#include "spaceObjects/playerSpaceship.h" +#include "spaceObjects/cpuShip.h" +#include "spaceObjects/warpjammer.h" +#include "ecs/query.h" + + +void ImpulseSystem::update(float delta) +{ + //TODO: Turn this into better individual systems + //TODO: This crashes if the object is not a ship + for(auto [entity, impulse, physics, obj] : sp::ecs::Query()) + { + SpaceShip* ship = dynamic_cast(obj); + //Here we want to have max speed at 100% impulse, and max reverse speed at -100% impulse + float cap_speed = impulse.max_speed_forward; + + if(impulse.actual < 0 && impulse.max_speed_reverse <= 0.01f) + { + impulse.actual = 0; //we could get stuck with a ship with no reverse speed, not being able to accelerate + } + if(impulse.actual < 0) + { + cap_speed = impulse.max_speed_reverse; + } + if ((ship->has_jump_drive && ship->jump_delay > 0) || (ship->has_warp_drive && ship->warp_request > 0)) + { + if (WarpJammer::isWarpJammed(ship->getPosition())) + { + ship->jump_delay = 0; + ship->warp_request = 0; + } + } + if (ship->has_jump_drive && ship->jump_delay > 0) + { + if (impulse.actual > 0.0f) + { + if (cap_speed > 0) + impulse.actual -= delta * (impulse.acceleration_reverse / cap_speed); + if (impulse.actual < 0.0f) + impulse.actual = 0.f; + } + if (impulse.actual < 0.0f) + { + if (cap_speed > 0) + impulse.actual += delta * (impulse.acceleration_forward / cap_speed); + if (impulse.actual > 0.0f) + impulse.actual = 0.f; + } + if (ship->current_warp > 0.0f) + { + ship->current_warp -= delta; + if (ship->current_warp < 0.0f) + ship->current_warp = 0.f; + } + ship->jump_delay -= delta * ship->getSystemEffectiveness(SYS_JumpDrive); + if (ship->jump_delay <= 0.0f) + { + ship->executeJump(ship->jump_distance); + ship->jump_delay = 0.f; + } + }else if (ship->has_warp_drive && (ship->warp_request > 0 || ship->current_warp > 0)) + { + if (impulse.actual > 0.0f) + { + if (cap_speed > 0) + impulse.actual -= delta * (impulse.acceleration_reverse / cap_speed); + if (impulse.actual < 0.0f) + impulse.actual = 0.0f; + }else if (impulse.actual < 0.0f) + { + if (cap_speed > 0) + impulse.actual += delta * (impulse.acceleration_forward / cap_speed); + if (impulse.actual > 0.0f) + impulse.actual = 0.0f; + }else{ + if (ship->current_warp < ship->warp_request) + { + ship->current_warp += delta / ship->warp_charge_time; + if (ship->current_warp > ship->warp_request) + ship->current_warp = ship->warp_request; + }else if (ship->current_warp > ship->warp_request) + { + ship->current_warp -= delta / ship->warp_decharge_time; + if (ship->current_warp < ship->warp_request) + ship->current_warp = ship->warp_request; + } + } + }else{ + if (ship->has_jump_drive) + { + float f = ship->getJumpDriveRechargeRate(); + if (f > 0) + { + if (ship->jump_drive_charge < ship->jump_drive_max_distance) + { + float extra_charge = (delta / ship->jump_drive_charge_time * ship->jump_drive_max_distance) * f; + if (ship->useEnergy(extra_charge * ship->jump_drive_energy_per_km_charge / 1000.0f)) + { + ship->jump_drive_charge += extra_charge; + if (ship->jump_drive_charge >= ship->jump_drive_max_distance) + ship->jump_drive_charge = ship->jump_drive_max_distance; + } + } + }else{ + ship->jump_drive_charge += (delta / ship->jump_drive_charge_time * ship->jump_drive_max_distance) * f; + if (ship->jump_drive_charge < 0.0f) + ship->jump_drive_charge = 0.0f; + } + } + ship->current_warp = 0.f; + if (impulse.request > 1.0f) + impulse.request = 1.0f; + if (impulse.request < -1.0f) + impulse.request = -1.0f; + if (impulse.actual < impulse.request) + { + if (cap_speed > 0) + impulse.actual += delta * (impulse.acceleration_forward / cap_speed); + if (impulse.actual > impulse.request) + impulse.actual = impulse.request; + }else if (impulse.actual > impulse.request) + { + if (cap_speed > 0) + impulse.actual -= delta * (impulse.acceleration_reverse / cap_speed); + if (impulse.actual < impulse.request) + impulse.actual = impulse.request; + } + } + + // Add heat based on warp factor. + ship->addHeat(SYS_Warp, ship->current_warp * delta * ship->heat_per_warp * ship->getSystemEffectiveness(SYS_Warp)); + + // Determine forward direction and velocity. + auto forward = vec2FromAngle(ship->getRotation()); + physics.setVelocity(forward * (impulse.actual * cap_speed * ship->getSystemEffectiveness(SYS_Impulse) + ship->current_warp * ship->warp_speed_per_warp_level * ship->getSystemEffectiveness(SYS_Warp))); + } +} diff --git a/src/systems/impulse.h b/src/systems/impulse.h new file mode 100644 index 0000000000..a195228726 --- /dev/null +++ b/src/systems/impulse.h @@ -0,0 +1,10 @@ +#pragma once + +#include "ecs/system.h" + + +class ImpulseSystem : public sp::ecs::System +{ +public: + void update(float delta) override; +}; From 67e7af253e1b88b973cb97e9df4e094042245a31 Mon Sep 17 00:00:00 2001 From: Daid Date: Thu, 10 Nov 2022 22:05:20 +0100 Subject: [PATCH 014/320] WIP --- src/systems/docking.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/systems/docking.cpp b/src/systems/docking.cpp index 07aaeb7aba..0cce1abe39 100644 --- a/src/systems/docking.cpp +++ b/src/systems/docking.cpp @@ -12,7 +12,6 @@ DockingSystem::DockingSystem() sp::CollisionSystem::addHandler(this); } -//TODO: Handle internal docking. void DockingSystem::update(float delta) { if (!game_server) return; From 78c43ef3b5585b438a3ad082e9743f2723d7fa0c Mon Sep 17 00:00:00 2001 From: Daid Date: Mon, 14 Nov 2022 13:27:08 +0100 Subject: [PATCH 015/320] Convert beamweapons to ECS --- CMakeLists.txt | 6 +- src/ai/ai.cpp | 47 ++- src/ai/evasionAI.cpp | 18 +- src/components/beamweapon.h | 39 +++ src/components/shipsystem.cpp | 59 ++++ src/components/shipsystem.h | 3 + src/gameStateLogger.cpp | 5 +- src/main.cpp | 2 + .../beamFrequencySelector.cpp | 9 +- src/screenComponents/beamTargetSelector.cpp | 9 +- src/screenComponents/frequencyCurve.cpp | 17 +- src/screenComponents/radarView.cpp | 151 +++++++++ src/screens/crew6/engineeringScreen.cpp | 13 +- src/screens/crew6/scienceScreen.cpp | 16 +- src/screens/gm/tweak.cpp | 36 +-- src/spaceObjects/playerSpaceship.cpp | 21 +- src/spaceObjects/playerSpaceship.h | 4 +- src/spaceObjects/spaceship.cpp | 219 +++---------- src/spaceObjects/spaceship.h | 83 ++--- .../spaceshipParts/beamWeapon.cpp | 291 ------------------ src/spaceObjects/spaceshipParts/beamWeapon.h | 88 ------ src/systems/beamweapon.cpp | 113 +++++++ src/systems/beamweapon.h | 10 + 23 files changed, 552 insertions(+), 707 deletions(-) create mode 100644 src/components/beamweapon.h create mode 100644 src/components/shipsystem.cpp delete mode 100644 src/spaceObjects/spaceshipParts/beamWeapon.cpp delete mode 100644 src/spaceObjects/spaceshipParts/beamWeapon.h create mode 100644 src/systems/beamweapon.cpp create mode 100644 src/systems/beamweapon.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a2c92fab2a..ee47c1d8e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -351,17 +351,20 @@ set(MAIN_SOURCES src/spaceObjects/shipTemplateBasedObject.cpp src/spaceObjects/planet.cpp src/spaceObjects/zone.cpp - src/spaceObjects/spaceshipParts/beamWeapon.cpp src/spaceObjects/spaceshipParts/weaponTube.cpp src/components/radar.h src/components/rendering.h src/components/docking.h src/components/shipsystem.h + src/components/shipsystem.cpp src/components/impulse.h + src/components/reactor.h src/systems/docking.h src/systems/docking.cpp src/systems/impulse.h src/systems/impulse.cpp + src/systems/beamweapon.h + src/systems/beamweapon.cpp src/ai/fighterAI.cpp src/ai/ai.cpp src/ai/aiFactory.cpp @@ -524,7 +527,6 @@ set(MAIN_SOURCES src/spaceObjects/shipTemplateBasedObject.h src/spaceObjects/spaceObject.h src/spaceObjects/spaceship.h - src/spaceObjects/spaceshipParts/beamWeapon.h src/spaceObjects/spaceshipParts/weaponTube.h src/spaceObjects/spaceStation.h src/spaceObjects/supplyDrop.h diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp index 8d93f28cdc..5fc855014a 100644 --- a/src/ai/ai.cpp +++ b/src/ai/ai.cpp @@ -6,6 +6,7 @@ #include "random.h" #include "components/docking.h" #include "components/impulse.h" +#include "components/beamweapon.h" #include "systems/collision.h" #include "ecs/query.h" @@ -130,15 +131,13 @@ void ShipAI::updateWeaponState(float delta) } } - for(int n=0; nbeam_weapons[n]; - if (beam.getRange() > 0) - { - int index = getDirectionIndex(beam.getDirection(), beam.getArc()); - if (index >= 0) - { - beam_strength_per_direction[index] += beam.getDamage() / beam.getCycleTime(); + auto beamsystem = owner->entity.getComponent(); + if (beamsystem) { + for(auto& mount : beamsystem->mounts) { + if (mount.range > 0.0f) { + int index = getDirectionIndex(mount.direction, mount.arc); + if (index >= 0 && mount.cycle_time > 0.0f) + beam_strength_per_direction[index] += mount.damage / mount.cycle_time; } } } @@ -164,19 +163,14 @@ void ShipAI::updateWeaponState(float delta) has_beams = best_beam_index > -1; has_missiles = best_tube_index > -1; - if (has_beams) + if (has_beams && beamsystem) { //Figure out our beam weapon range. - for(int n=0; nbeam_weapons[n]; - if (beam.getRange() > 0) - { - int index = getDirectionIndex(beam.getDirection(), beam.getArc()); - if (index == best_beam_index) - { - beam_weapon_range += beam.getRange() * (beam.getDamage() / beam.getCycleTime()) / beam_strength_per_direction[index]; - } + for(auto& mount : beamsystem->mounts) { + if (mount.range > 0.0f) { + int index = getDirectionIndex(mount.direction, mount.arc); + if (index == best_beam_index && mount.cycle_time > 0.0f) + beam_weapon_range += mount.range * (mount.damage / mount.cycle_time) / beam_strength_per_direction[index]; } } } @@ -721,12 +715,13 @@ float ShipAI::targetScore(P target) if (distance < beam_weapon_range) { - for(int n=0; nbeam_weapons[n].getRange()) - { - if (fabs(angleDifference(angle_difference, owner->beam_weapons[n].getDirection())) < owner->beam_weapons[n].getArc() / 2.0f) - score += 1000; + auto beamsystem = owner->entity.getComponent(); + if (beamsystem) { + for(auto& mount : beamsystem->mounts) { + if (distance < mount.range) { + if (fabs(angleDifference(angle_difference, mount.direction)) < mount.arc / 2.0f) + score += 1000; + } } } } diff --git a/src/ai/evasionAI.cpp b/src/ai/evasionAI.cpp index e1e7dd99a8..e9694bea41 100644 --- a/src/ai/evasionAI.cpp +++ b/src/ai/evasionAI.cpp @@ -4,6 +4,7 @@ #include "ai/aiFactory.h" #include "random.h" #include "systems/collision.h" +#include "components/beamweapon.h" REGISTER_SHIP_AI(EvasionAI, "evasion"); @@ -143,15 +144,14 @@ float EvasionAI::evasionDangerScore(P ship, float scan_radius) } } - for(int n=0; nbeam_weapons[n]; - if (beam.getRange() > 0) - { - if (beam.getRange() > enemy_max_beam_range) - enemy_max_beam_range = beam.getRange(); - if (beam.getCycleTime() > 0.0f) - enemy_beam_dps += beam.getDamage() / beam.getCycleTime(); + auto beamsystem = ship->entity.getComponent(); + if (beamsystem) { + for(auto& mount : beamsystem->mounts) { + if (mount.range > 0.0f) { + enemy_max_beam_range = std::max(enemy_max_beam_range, mount.range); + if (mount.cycle_time > 0.0f) + enemy_beam_dps += mount.damage / mount.cycle_time; + } } } diff --git a/src/components/beamweapon.h b/src/components/beamweapon.h new file mode 100644 index 0000000000..7729d1fe9e --- /dev/null +++ b/src/components/beamweapon.h @@ -0,0 +1,39 @@ +#pragma once + +#include "ecs/entity.h" +#include "shipsystem.h" +#include "spaceObjects/spaceObject.h" + + +class BeamWeaponSys : public ShipSystem { +public: + class MountPoint { + public: + glm::vec3 position;//Visual position on the 3D model where this beam is fired from. + + //Beam configuration + float arc = 0.0f; + float direction = 0.0f; + float range = 0.0f; + float turret_arc = 0.0f; + float turret_direction = 0.0f; + float turret_rotation_rate = 0.0f; + float cycle_time = 6.0f; + float damage = 1.0f;//Server side only + float energy_per_beam_fire = 3.0f;//Server side only + float heat_per_beam_fire = 0.02f;//Server side only + glm::u8vec4 arc_color{255, 0, 0, 128}; + glm::u8vec4 arc_color_fire{255, 255, 0, 128}; + EDamageType damage_type = DT_Energy; + + //Beam runtime state + float cooldown = 0.0f; + string texture; + }; + + int frequency = 0; + ESystem system_target = SYS_None; + sp::ecs::Entity target; + + MountPoint mounts[max_beam_weapons]; +}; diff --git a/src/components/shipsystem.cpp b/src/components/shipsystem.cpp new file mode 100644 index 0000000000..be3953638c --- /dev/null +++ b/src/components/shipsystem.cpp @@ -0,0 +1,59 @@ +#include "shipsystem.h" +#include "gameGlobalInfo.h" + +// Overheat subsystem damage rate +constexpr static float damage_per_second_on_overheat = 0.08f; + + +float ShipSystem::get_system_effectiveness() +{ + float power = power_level; + + // Substract the hacking from the power, making double hacked systems run at 25% efficiency. + power = std::max(0.0f, power - hacked_level * 0.75f); + + // Degrade all systems except the reactor once energy level drops below 10. + /* TODO + if (system != SYS_Reactor) + { + auto reactor = entity.getComponent(); + if (reactor) { + if (reactor->energy < 10.0f && reactor->energy > 0.0f && power > 0.0f) + power = std::min(power * reactor->energy / 10.0f, power); + else if (reactor->energy <= 0.0f || power <= 0.0f) + power = 0.0f; + } + }*/ + + // Degrade damaged systems. + if (gameGlobalInfo && gameGlobalInfo->use_system_damage) + return std::max(0.0f, power * health); + + // If a system cannot be damaged, excessive heat degrades it. + return std::max(0.0f, power * (1.0f - heat_level)); +} + +void ShipSystem::add_heat(float amount) +{ + heat_level += amount; + + if (heat_level > 1.0f) + { + float overheat = heat_level - 1.0f; + heat_level = 1.0f; + + if (gameGlobalInfo->use_system_damage) + { + // Heat damage is specified as damage per second while overheating. + // Calculate the amount of overheat back to a time, and use that to + // calculate the actual damage taken. + health -= overheat / heat_add_rate_per_second * damage_per_second_on_overheat; + + if (health < -1.0f) + health = -1.0f; + } + } + + if (heat_level < 0.0f) + heat_level = 0.0f; +} \ No newline at end of file diff --git a/src/components/shipsystem.h b/src/components/shipsystem.h index 7d5049b746..3af39d4742 100644 --- a/src/components/shipsystem.h +++ b/src/components/shipsystem.h @@ -21,4 +21,7 @@ class ShipSystem float coolant_change_rate_per_second = default_coolant_rate_per_second; float heat_add_rate_per_second = default_add_heat_rate_per_second; float power_change_rate_per_second = default_power_rate_per_second; + + float get_system_effectiveness(); + void add_heat(float amount); }; \ No newline at end of file diff --git a/src/gameStateLogger.cpp b/src/gameStateLogger.cpp index 5c53350e07..fd0038342d 100644 --- a/src/gameStateLogger.cpp +++ b/src/gameStateLogger.cpp @@ -479,7 +479,7 @@ void GameStateLogger::writeShipEntry(JSONGenerator& json, P ship) json.arrayWrite(ship->shield_max[n]); config.endArray(); } - +/* has_beam_weapons = false; for(int n=0; n ship) { config.endArray(); } + */ } + /* if (has_beam_weapons) { if (gameGlobalInfo->use_beam_shield_frequencies) @@ -510,6 +512,7 @@ void GameStateLogger::writeShipEntry(JSONGenerator& json, P ship) if (ship->beam_system_target != SYS_None) json.write("beam_system_target", getSystemName(ship->beam_system_target)); } + */ } void GameStateLogger::writeStationEntry(JSONGenerator& json, P station) diff --git a/src/main.cpp b/src/main.cpp index 482f12fee1..891fe2f70d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,6 +29,7 @@ #include "spaceObjects/spaceObject.h" #include "systems/docking.h" #include "systems/impulse.h" +#include "systems/beamweapon.h" #include "packResourceProvider.h" #include "main.h" #include "epsilonServer.h" @@ -137,6 +138,7 @@ int main(int argc, char** argv) new Engine(); engine->registerSystem(); engine->registerSystem(); + engine->registerSystem(); string configuration_path = "."; if (getenv("HOME")) configuration_path = string(getenv("HOME")) + "/.emptyepsilon"; diff --git a/src/screenComponents/beamFrequencySelector.cpp b/src/screenComponents/beamFrequencySelector.cpp index d920401267..909df29e9e 100644 --- a/src/screenComponents/beamFrequencySelector.cpp +++ b/src/screenComponents/beamFrequencySelector.cpp @@ -2,13 +2,18 @@ #include "gameGlobalInfo.h" #include "beamFrequencySelector.h" +#include "components/beamweapon.h" + GuiBeamFrequencySelector::GuiBeamFrequencySelector(GuiContainer* owner, string id) : GuiSelector(owner, id, [](int index, string value) { if (my_spaceship) my_spaceship->commandSetBeamFrequency(index); }) { for(int n=0; n<=SpaceShip::max_frequency; n++) addEntry(frequencyToString(n), frequencyToString(n)); - if (my_spaceship) - setSelectionIndex(my_spaceship->beam_frequency); + if (my_spaceship) { + auto beamweapons = my_spaceship->entity.getComponent(); + if (beamweapons) + setSelectionIndex(beamweapons->frequency); + } if (!gameGlobalInfo->use_beam_shield_frequencies) hide(); } diff --git a/src/screenComponents/beamTargetSelector.cpp b/src/screenComponents/beamTargetSelector.cpp index d7eacef922..67518392f0 100644 --- a/src/screenComponents/beamTargetSelector.cpp +++ b/src/screenComponents/beamTargetSelector.cpp @@ -3,14 +3,19 @@ #include "gameGlobalInfo.h" #include "beamTargetSelector.h" +#include "components/beamweapon.h" + GuiBeamTargetSelector::GuiBeamTargetSelector(GuiContainer* owner, string id) : GuiSelector(owner, id, [](int index, string value) { if (my_spaceship) my_spaceship->commandSetBeamSystemTarget(ESystem(index + SYS_None)); }) { addEntry(tr("target","Hull"), "-1"); for(int n=0; nbeam_system_target - SYS_None); + if (my_spaceship) { + auto beamweapons = my_spaceship->entity.getComponent(); + if (beamweapons) + setSelectionIndex(beamweapons->system_target - SYS_None); + } if (!gameGlobalInfo->use_system_damage) hide(); } diff --git a/src/screenComponents/frequencyCurve.cpp b/src/screenComponents/frequencyCurve.cpp index 4de4b89163..02532c8fea 100644 --- a/src/screenComponents/frequencyCurve.cpp +++ b/src/screenComponents/frequencyCurve.cpp @@ -2,6 +2,8 @@ #include "spaceObjects/spaceship.h" #include "spaceObjects/playerSpaceship.h" #include "playerInfo.h" +#include "components/beamweapon.h" + GuiFrequencyCurve::GuiFrequencyCurve(GuiContainer* owner, string id, bool frequency_is_beam, bool more_damage_is_positive) : GuiPanel(owner, id), frequency_is_beam(frequency_is_beam), more_damage_is_positive(more_damage_is_positive) @@ -17,6 +19,17 @@ void GuiFrequencyCurve::onDraw(sp::RenderTarget& renderer) { if (enemy_has_equipment) { float w = (rect.size.x - 40) / (SpaceShip::max_frequency + 1); + int arrow_index = -1; + if (frequency_is_beam) + { + if (my_spaceship) + arrow_index = my_spaceship->getShieldsFrequency(); + } else if (my_spaceship) { + auto beamsystem = my_spaceship->entity.getComponent(); + if (beamsystem) + arrow_index = beamsystem->frequency; + } + for(int n=0; n<=SpaceShip::max_frequency; n++) { float x = rect.position.x + 20 + w * n; @@ -33,10 +46,8 @@ void GuiFrequencyCurve::onDraw(sp::RenderTarget& renderer) else renderer.fillRect(bar_rect, glm::u8vec4(255 * f, 255 * (1.0f - f), 0, 255)); - if (my_spaceship && ((frequency_is_beam && n == my_spaceship->getShieldsFrequency()) || (!frequency_is_beam && n == my_spaceship->beam_frequency))) - { + if (n == arrow_index) renderer.drawRotatedSprite("gui/widget/IndicatorArrow.png", glm::vec2(x + w * 0.5f, rect.position.y + rect.size.y - 20 - h), w, -90); - } } int mouse_freq_nr = int((mouse_position.x - rect.position.x - 20) / w); diff --git a/src/screenComponents/radarView.cpp b/src/screenComponents/radarView.cpp index e8846abd4d..6e65c19269 100644 --- a/src/screenComponents/radarView.cpp +++ b/src/screenComponents/radarView.cpp @@ -3,6 +3,7 @@ #include "ecs/query.h" #include "systems/collision.h" #include "components/collision.h" +#include "components/beamweapon.h" #include "main.h" #include "gameGlobalInfo.h" #include "spaceObjects/nebula.h" @@ -687,6 +688,156 @@ void GuiRadarView::drawObjects(sp::RenderTarget& renderer) { draw_object(obj); } + + auto draw_arc = [&renderer](auto arc_center, auto angle0, auto arc_angle, auto arc_radius, auto color) + { + // Initialize variables from the beam's data. + float beam_arc = arc_angle; + float beam_range = arc_radius; + + // Set the beam's origin on radar to its relative position on the mesh. + float outline_thickness = std::min(20.0f, beam_range * 0.2f); + float beam_arc_curve_length = beam_range * beam_arc / 180.0f * glm::pi(); + outline_thickness = std::min(outline_thickness, beam_arc_curve_length * 0.25f); + + size_t curve_point_count = 0; + if (outline_thickness > 0.f) + curve_point_count = static_cast(beam_arc_curve_length / (outline_thickness * 0.9f)); + + struct ArcPoint { + glm::vec2 point; + glm::vec2 normal; // Direction towards the center. + }; + + //Arc points + std::vector arc_points; + arc_points.reserve(curve_point_count + 1); + + for (size_t i = 0; i < curve_point_count; i++) + { + auto angle = vec2FromAngle(angle0 + i * beam_arc / curve_point_count) * beam_range; + arc_points.emplace_back(ArcPoint{ arc_center + angle, glm::normalize(angle) }); + } + { + auto angle = vec2FromAngle(angle0 + beam_arc) * beam_range; + arc_points.emplace_back(ArcPoint{ arc_center + angle, glm::normalize(angle) }); + } + + for (size_t n = 0; n < arc_points.size() - 1; n++) + { + const auto& p0 = arc_points[n].point; + const auto& p1 = arc_points[n + 1].point; + const auto& n0 = arc_points[n].normal; + const auto& n1 = arc_points[n + 1].normal; + renderer.drawTexturedQuad("gradient.png", + p0, p0 - n0 * outline_thickness, + p1 - n1 * outline_thickness, p1, + { 0.f, 0.5f }, { 1.f, 0.5f }, { 1.f, 0.5f }, { 0.f, 0.5f }, + color); + } + + if (beam_arc < 360.f) + { + // Arc bounds. + // We use the left- and right-most edges as lines, going inwards, parallel to the center. + const auto left_edge = vec2FromAngle(angle0) * beam_range; + const auto right_edge = vec2FromAngle(angle0 + beam_arc) * beam_range; + + // Compute the half point, always going clockwise from the left edge. + // This makes sure the algorithm never takes the short road. + auto halfway_angle = vec2FromAngle(angle0 + beam_arc / 2.f) * beam_range; + auto middle = glm::normalize(halfway_angle); + + // Edge vectors. + const auto left_edge_vector = glm::normalize(left_edge); + const auto right_edge_vector = glm::normalize(right_edge); + + // Edge normals, inwards. + auto left_edge_normal = glm::vec2{ left_edge_vector.y, -left_edge_vector.x }; + const auto right_edge_normal = glm::vec2{ -right_edge_vector.y, right_edge_vector.x }; + + // Initial offset, follow along the edges' normals, inwards. + auto left_inner_offset = -left_edge_normal * outline_thickness; + auto right_inner_offset = -right_edge_normal * outline_thickness; + + if (beam_arc < 180.f) + { + // The thickness being perpendicular from the edges, + // the inner lines just crosses path on the height, + // so just use that point. + left_inner_offset = middle * outline_thickness / sinf(glm::radians(beam_arc / 2.f)); + right_inner_offset = left_inner_offset; + } + else + { + // Make it shrink nicely as it grows up to 360 deg. + // For that, we use the edge's normal against the height which will change from 0 to 90deg. + // Also flip the direction so our points stay inside the beam. + auto thickness_scale = -glm::dot(middle, right_edge_normal); + left_inner_offset *= thickness_scale; + right_inner_offset *= thickness_scale; + } + + renderer.drawTexturedQuad("gradient.png", + arc_center, arc_center + left_inner_offset, + arc_center + left_edge - left_edge_normal * outline_thickness, arc_center + left_edge, + { 0.f, 0.5f }, { 1.f, 0.5f }, { 1.f, 0.5f }, { 0.f, 0.5f }, + color); + + renderer.drawTexturedQuad("gradient.png", + arc_center, arc_center + right_inner_offset, + arc_center + right_edge - right_edge_normal * outline_thickness, arc_center + right_edge, + { 0.f, 0.5f }, { 1.f, 0.5f }, { 1.f, 0.5f }, { 0.f, 0.5f }, + color); + } + }; + + // Draw beam arcs on short-range radar only, and only for fully scanned + // ships. + if (!long_range) { + for(auto [entity, beamsystem, position, obj] : sp::ecs::Query()) { + auto object_position_on_screen = worldToScreen(position.getPosition()); + if (!obj || (my_spaceship && (obj->getScannedStateFor(my_spaceship) != SS_FullScan))) + continue; + + // For each beam ... + for(auto& mount : beamsystem.mounts) { + // Draw beam arcs only if the beam has a range. A beam with range 0 + // effectively doesn't exist; exit if that's the case. + if (mount.range == 0.0f) continue; + + // If the beam is cooling down, flash and fade the arc color. + glm::u8vec4 color = Tween::linear(std::max(0.0f, mount.cooldown), 0, mount.cycle_time, mount.arc_color, mount.arc_color_fire); + + + // Initialize variables from the beam's data. + float beam_direction = mount.direction; + float beam_arc = mount.arc; + float beam_range = mount.range; + + // Set the beam's origin on radar to its relative position on the mesh. + auto beam_offset = rotateVec2(glm::vec2(mount.position.x, mount.position.y) * scale, position.getRotation() - view_rotation); + auto arc_center = beam_offset + object_position_on_screen; + + draw_arc(arc_center, position.getRotation() - view_rotation + (beam_direction - beam_arc / 2.0f), beam_arc, beam_range * scale, color); + + + // If the beam is turreted, draw the turret's arc. Otherwise, exit. + if (mount.arc == 0.0f) + continue; + + // Initialize variables from the turret data. + float turret_arc = mount.turret_arc; + float turret_direction = mount.turret_direction; + + // Draw the turret's bounds, at half the transparency of the beam's. + // TODO: Make this color configurable. + color.a /= 4; + + draw_arc(arc_center, position.getRotation() - view_rotation + (turret_direction - turret_arc / 2.0f), turret_arc, beam_range * scale, color); + } + } + } for(auto [entity, trace, position, obj] : sp::ecs::Query()) { auto object_position_on_screen = worldToScreen(position.getPosition()); diff --git a/src/screens/crew6/engineeringScreen.cpp b/src/screens/crew6/engineeringScreen.cpp index a07f60f1dc..10cf85eb14 100644 --- a/src/screens/crew6/engineeringScreen.cpp +++ b/src/screens/crew6/engineeringScreen.cpp @@ -3,6 +3,7 @@ #include "engineeringScreen.h" #include "components/reactor.h" +#include "components/beamweapon.h" #include "screenComponents/shipInternalView.h" #include "screenComponents/selfDestructButton.h" @@ -294,12 +295,12 @@ void EngineeringScreen::onDraw(sp::RenderTarget& renderer) addSystemEffect(tr("Firing rate"), toNearbyIntString(effectiveness * 100) + "%"); // If the ship has a turret, also note that the rotation rate // is affected. - for(int n = 0; n < max_beam_weapons; n++) - { - if (my_spaceship->beam_weapons[n].getTurretArc() > 0) - { - addSystemEffect("Turret rotation rate", toNearbyIntString(effectiveness * 100) + "%"); - break; + if (auto beamweapons = my_spaceship->entity.getComponent()) { + for(int n = 0; n < max_beam_weapons; n++) { + if (beamweapons->mounts[n].turret_arc > 0) { + addSystemEffect("Turret rotation rate", toNearbyIntString(effectiveness * 100) + "%"); + break; + } } } break; diff --git a/src/screens/crew6/scienceScreen.cpp b/src/screens/crew6/scienceScreen.cpp index 21c6befd12..2724b77a27 100644 --- a/src/screens/crew6/scienceScreen.cpp +++ b/src/screens/crew6/scienceScreen.cpp @@ -7,6 +7,8 @@ #include "shipTemplate.h" #include "multiplayer_client.h" +#include "components/beamweapon.h" + #include "screenComponents/radarView.h" #include "screenComponents/rawScannerDataRadarOverlay.h" #include "screenComponents/scanTargetButton.h" @@ -402,21 +404,15 @@ void ScienceScreen::onDraw(sp::RenderTarget& renderer) if (gameGlobalInfo->use_beam_shield_frequencies) { info_shield_frequency->setFrequency(ship->shield_frequency); - info_beam_frequency->setFrequency(ship->beam_frequency); + auto beamsystem = ship->entity.getComponent(); + if (beamsystem) + info_beam_frequency->setFrequency(beamsystem->frequency); // Show on graph information that target has no shields instead of frequencies. info_shield_frequency->setEnemyHasEquipment(ship->getShieldCount() > 0); // Show on graph information that target has no beams instad of frequencies. - bool has_beams = false; - for(int n = 0; n < max_beam_weapons; n++) - { - if (ship->beam_weapons[n].getRange() > 0.0f) { - has_beams = true; - break; - } - } - info_beam_frequency->setEnemyHasEquipment(has_beams); + info_beam_frequency->setEnemyHasEquipment(beamsystem); } // Show the status of each subsystem. diff --git a/src/screens/gm/tweak.cpp b/src/screens/gm/tweak.cpp index b205b4ad62..45234d4462 100644 --- a/src/screens/gm/tweak.cpp +++ b/src/screens/gm/tweak.cpp @@ -523,25 +523,25 @@ GuiShipTweakBeamweapons::GuiShipTweakBeamweapons(GuiContainer* owner) (new GuiLabel(right_col, "", tr("beam", "Arc:"), 20))->setSize(GuiElement::GuiSizeMax, 30); arc_slider = new GuiSlider(right_col, "", 0.0, 360.0, 0.0, [this](float value) { - target->beam_weapons[beam_index].setArc(roundf(value)); + //TODO target->beam_weapons[beam_index].setArc(roundf(value)); }); arc_slider->addOverlay()->setSize(GuiElement::GuiSizeMax, 30); (new GuiLabel(right_col, "", tr("beam", "Direction:"), 20))->setSize(GuiElement::GuiSizeMax, 30); direction_slider = new GuiSlider(right_col, "", -180.0, 180.0, 0.0, [this](float value) { - target->beam_weapons[beam_index].setDirection(roundf(value)); + //TODO target->beam_weapons[beam_index].setDirection(roundf(value)); }); direction_slider->addOverlay()->setSize(GuiElement::GuiSizeMax, 30); (new GuiLabel(right_col, "", tr("beam", "Turret arc:"), 20))->setSize(GuiElement::GuiSizeMax, 30); turret_arc_slider = new GuiSlider(right_col, "", 0.0, 360.0, 0.0, [this](float value) { - target->beam_weapons[beam_index].setTurretArc(roundf(value)); + //TODO target->beam_weapons[beam_index].setTurretArc(roundf(value)); }); turret_arc_slider->addOverlay()->setSize(GuiElement::GuiSizeMax, 30); (new GuiLabel(right_col, "", tr("beam", "Turret direction:"), 20))->setSize(GuiElement::GuiSizeMax, 30); turret_direction_slider = new GuiSlider(right_col, "", -180.0, 180.0, 0.0, [this](float value) { - target->beam_weapons[beam_index].setTurretDirection(roundf(value)); + //TODO target->beam_weapons[beam_index].setTurretDirection(roundf(value)); }); turret_direction_slider->addOverlay()->setSize(GuiElement::GuiSizeMax, 30); @@ -550,10 +550,10 @@ GuiShipTweakBeamweapons::GuiShipTweakBeamweapons(GuiContainer* owner) // result in practicaly instantaneous turret rotation anyway. turret_rotation_rate_slider = new GuiSlider(right_col, "", 0.0, 250.0, 0.0, [this](float value) { // Divide a large value for granularity. - if (value > 0) + /*TODO if (value > 0) target->beam_weapons[beam_index].setTurretRotationRate(value / 10.0f); else - target->beam_weapons[beam_index].setTurretRotationRate(0.0); + target->beam_weapons[beam_index].setTurretRotationRate(0.0);*/ }); turret_rotation_rate_slider->setSize(GuiElement::GuiSizeMax, 30); // Override overlay label. @@ -562,19 +562,19 @@ GuiShipTweakBeamweapons::GuiShipTweakBeamweapons(GuiContainer* owner) (new GuiLabel(right_col, "", tr("beam", "Range:"), 20))->setSize(GuiElement::GuiSizeMax, 30); range_slider = new GuiSlider(right_col, "", 0.0, 5000.0, 0.0, [this](float value) { - target->beam_weapons[beam_index].setRange(roundf(value / 100) * 100); + //TODO target->beam_weapons[beam_index].setRange(roundf(value / 100) * 100); }); range_slider->addOverlay()->setSize(GuiElement::GuiSizeMax, 30); (new GuiLabel(right_col, "", tr("beam", "Cycle time:"), 20))->setSize(GuiElement::GuiSizeMax, 30); cycle_time_slider = new GuiSlider(right_col, "", 0.1, 20.0, 0.0, [this](float value) { - target->beam_weapons[beam_index].setCycleTime(value); + //TODO target->beam_weapons[beam_index].setCycleTime(value); }); cycle_time_slider->addOverlay()->setSize(GuiElement::GuiSizeMax, 30); (new GuiLabel(right_col, "", tr("beam", "Damage:"), 20))->setSize(GuiElement::GuiSizeMax, 30); damage_slider = new GuiSlider(right_col, "", 0.1, 50.0, 0.0, [this](float value) { - target->beam_weapons[beam_index].setDamage(value); + //TODO target->beam_weapons[beam_index].setDamage(value); }); damage_slider->addOverlay()->setSize(GuiElement::GuiSizeMax, 30); } @@ -583,15 +583,15 @@ void GuiShipTweakBeamweapons::onDraw(sp::RenderTarget& renderer) { target->drawOnRadar(renderer, glm::vec2(rect.position.x - 150.0f + rect.size.x / 2.0f, rect.position.y + rect.size.y * 0.66f), 300.0f / 5000.0f, 0, false); - arc_slider->setValue(target->beam_weapons[beam_index].getArc()); - direction_slider->setValue(angleDifference(0.0f, target->beam_weapons[beam_index].getDirection())); - range_slider->setValue(target->beam_weapons[beam_index].getRange()); - turret_arc_slider->setValue(target->beam_weapons[beam_index].getTurretArc()); - turret_direction_slider->setValue(angleDifference(0.0f, target->beam_weapons[beam_index].getTurretDirection())); - turret_rotation_rate_slider->setValue(target->beam_weapons[beam_index].getTurretRotationRate() * 10.0f); - turret_rotation_rate_overlay_label->setText(string(target->beam_weapons[beam_index].getTurretRotationRate())); - cycle_time_slider->setValue(target->beam_weapons[beam_index].getCycleTime()); - damage_slider->setValue(target->beam_weapons[beam_index].getDamage()); + //TODO arc_slider->setValue(target->beam_weapons[beam_index].getArc()); + //TODO direction_slider->setValue(angleDifference(0.0f, target->beam_weapons[beam_index].getDirection())); + //TODO range_slider->setValue(target->beam_weapons[beam_index].getRange()); + //TODO turret_arc_slider->setValue(target->beam_weapons[beam_index].getTurretArc()); + //TODO turret_direction_slider->setValue(angleDifference(0.0f, target->beam_weapons[beam_index].getTurretDirection())); + //TODO turret_rotation_rate_slider->setValue(target->beam_weapons[beam_index].getTurretRotationRate() * 10.0f); + //TODO turret_rotation_rate_overlay_label->setText(string(target->beam_weapons[beam_index].getTurretRotationRate())); + //TODO cycle_time_slider->setValue(target->beam_weapons[beam_index].getCycleTime()); + //TODO damage_slider->setValue(target->beam_weapons[beam_index].getDamage()); } void GuiShipTweakBeamweapons::open(P target) diff --git a/src/spaceObjects/playerSpaceship.cpp b/src/spaceObjects/playerSpaceship.cpp index 24b481c5ad..f8480bcb91 100644 --- a/src/spaceObjects/playerSpaceship.cpp +++ b/src/spaceObjects/playerSpaceship.cpp @@ -10,6 +10,7 @@ #include "random.h" #include "components/reactor.h" +#include "components/beamweapon.h" #include "scriptInterface.h" @@ -367,7 +368,6 @@ PlayerSpaceship::PlayerSpaceship() registerMemberReplication(&auto_repair_enabled); registerMemberReplication(&max_coolant); registerMemberReplication(&auto_coolant_enabled); - registerMemberReplication(&beam_system_target); registerMemberReplication(&comms_state); registerMemberReplication(&comms_open_delay, 1.0); registerMemberReplication(&comms_reply_message); @@ -1140,6 +1140,9 @@ bool PlayerSpaceship::getCanDock() return entity.hasComponent(); } +ESystem PlayerSpaceship::getBeamSystemTarget() { return SYS_None; /* TODO */ } +string PlayerSpaceship::getBeamSystemTargetName() { return ""; /* TODO */ } + void PlayerSpaceship::onReceiveClientCommand(int32_t client_id, sp::io::DataBuffer& packet) { // Receive a command from a client. Code in this function is executed on @@ -1429,22 +1432,18 @@ void PlayerSpaceship::onReceiveClientCommand(int32_t client_id, sp::io::DataBuff { int32_t new_frequency; packet >> new_frequency; - beam_frequency = new_frequency; - if (beam_frequency < 0) - beam_frequency = 0; - if (beam_frequency > SpaceShip::max_frequency) - beam_frequency = SpaceShip::max_frequency; + auto beamweapons = entity.getComponent(); + if (beamweapons) + beamweapons->frequency = std::clamp(new_frequency, 0, SpaceShip::max_frequency); } break; case CMD_SET_BEAM_SYSTEM_TARGET: { ESystem system; packet >> system; - beam_system_target = system; - if (beam_system_target < SYS_None) - beam_system_target = SYS_None; - if (beam_system_target > ESystem(int(SYS_COUNT) - 1)) - beam_system_target = ESystem(int(SYS_COUNT) - 1); + auto beamweapons = entity.getComponent(); + if (beamweapons) + beamweapons->system_target = (ESystem)std::clamp((int)system, 0, (int)(SYS_COUNT - 1)); } break; case CMD_SET_SHIELD_FREQUENCY: diff --git a/src/spaceObjects/playerSpaceship.h b/src/spaceObjects/playerSpaceship.h index d209aead74..6f891484c5 100644 --- a/src/spaceObjects/playerSpaceship.h +++ b/src/spaceObjects/playerSpaceship.h @@ -235,8 +235,8 @@ class PlayerSpaceship : public SpaceShip void addCustomMessageWithCallback(ECrewPosition position, string name, string caption, ScriptSimpleCallback callback); void removeCustom(string name); - ESystem getBeamSystemTarget(){ return beam_system_target; } - string getBeamSystemTargetName(){ return getSystemName(beam_system_target); } + ESystem getBeamSystemTarget(); + string getBeamSystemTargetName(); // Client command functions virtual void onReceiveClientCommand(int32_t client_id, sp::io::DataBuffer& packet) override; void commandTargetRotation(float target); diff --git a/src/spaceObjects/spaceship.cpp b/src/spaceObjects/spaceship.cpp index f0fd27b8b5..0fbe795523 100644 --- a/src/spaceObjects/spaceship.cpp +++ b/src/spaceObjects/spaceship.cpp @@ -20,6 +20,7 @@ #include "components/docking.h" #include "components/impulse.h" #include "components/reactor.h" +#include "components/beamweapon.h" #include "scriptInterface.h" @@ -200,8 +201,6 @@ SpaceShip::SpaceShip(string multiplayerClassName, float multiplayer_significant_ combat_maneuver_boost_speed = 0.0f; combat_maneuver_strafe_speed = 0.0f; target_id = -1; - beam_frequency = irandom(0, max_frequency); - beam_system_target = SYS_None; shield_frequency = irandom(0, max_frequency); turnSpeed = 0.0f; @@ -221,7 +220,6 @@ SpaceShip::SpaceShip(string multiplayerClassName, float multiplayer_significant_ registerMemberReplication(&turn_speed); registerMemberReplication(&warp_speed_per_warp_level); registerMemberReplication(&shield_frequency); - registerMemberReplication(&beam_frequency); registerMemberReplication(&combat_maneuver_charge, 0.5f); registerMemberReplication(&combat_maneuver_boost_request); registerMemberReplication(&combat_maneuver_boost_active, 0.2f); @@ -251,11 +249,6 @@ SpaceShip::SpaceShip(string multiplayerClassName, float multiplayer_significant_ registerMemberReplication(&systems[n].hacked_level, 0.1f); } - for(int n = 0; n < max_beam_weapons; n++) - { - beam_weapons[n].setParent(this); - } - for(int n = 0; n < max_weapon_tubes; n++) { weapon_tube[n].setParent(this); @@ -295,18 +288,22 @@ void SpaceShip::applyTemplateValues() { for(int n=0; nmodel_data->getBeamPosition(n)); - beam_weapons[n].setArc(ship_template->beams[n].getArc()); - beam_weapons[n].setDirection(ship_template->beams[n].getDirection()); - beam_weapons[n].setRange(ship_template->beams[n].getRange()); - beam_weapons[n].setTurretArc(ship_template->beams[n].getTurretArc()); - beam_weapons[n].setTurretDirection(ship_template->beams[n].getTurretDirection()); - beam_weapons[n].setTurretRotationRate(ship_template->beams[n].getTurretRotationRate()); - beam_weapons[n].setCycleTime(ship_template->beams[n].getCycleTime()); - beam_weapons[n].setDamage(ship_template->beams[n].getDamage()); - beam_weapons[n].setBeamTexture(ship_template->beams[n].getBeamTexture()); - beam_weapons[n].setEnergyPerFire(ship_template->beams[n].getEnergyPerFire()); - beam_weapons[n].setHeatPerFire(ship_template->beams[n].getHeatPerFire()); + if (ship_template->beams[n].getRange() > 0.0f) { + auto& beamweaponsystem = entity.getOrAddComponent(); + auto& mount = beamweaponsystem.mounts[n]; + mount.position = ship_template->model_data->getBeamPosition(n); + mount.arc = ship_template->beams[n].getArc(); + mount.direction = ship_template->beams[n].getDirection(); + mount.range = ship_template->beams[n].getRange(); + mount.turret_arc = ship_template->beams[n].getTurretArc(); + mount.turret_direction = ship_template->beams[n].getTurretDirection(); + mount.turret_rotation_rate = ship_template->beams[n].getTurretRotationRate(); + mount.cycle_time = ship_template->beams[n].getCycleTime(); + mount.damage = ship_template->beams[n].getDamage(); + mount.texture = ship_template->beams[n].getBeamTexture(); + mount.energy_per_beam_fire = ship_template->beams[n].getEnergyPerFire(); + mount.heat_per_beam_fire = ship_template->beams[n].getHeatPerFire(); + } } weapon_tube_count = ship_template->weapon_tube_count; @@ -441,151 +438,6 @@ void SpaceShip::updateDynamicRadarSignature() void SpaceShip::drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) { - // Draw beam arcs on short-range radar only, and only for fully scanned - // ships. - if (!long_range && (!my_spaceship || (getScannedStateFor(my_spaceship) == SS_FullScan))) - { - auto draw_arc = [&renderer](auto arc_center, auto angle0, auto arc_angle, auto arc_radius, auto color) - { - // Initialize variables from the beam's data. - float beam_arc = arc_angle; - float beam_range = arc_radius; - - // Set the beam's origin on radar to its relative position on the mesh. - float outline_thickness = std::min(20.0f, beam_range * 0.2f); - float beam_arc_curve_length = beam_range * beam_arc / 180.0f * glm::pi(); - outline_thickness = std::min(outline_thickness, beam_arc_curve_length * 0.25f); - - size_t curve_point_count = 0; - if (outline_thickness > 0.f) - curve_point_count = static_cast(beam_arc_curve_length / (outline_thickness * 0.9f)); - - struct ArcPoint { - glm::vec2 point; - glm::vec2 normal; // Direction towards the center. - }; - - //Arc points - std::vector arc_points; - arc_points.reserve(curve_point_count + 1); - - for (size_t i = 0; i < curve_point_count; i++) - { - auto angle = vec2FromAngle(angle0 + i * beam_arc / curve_point_count) * beam_range; - arc_points.emplace_back(ArcPoint{ arc_center + angle, glm::normalize(angle) }); - } - { - auto angle = vec2FromAngle(angle0 + beam_arc) * beam_range; - arc_points.emplace_back(ArcPoint{ arc_center + angle, glm::normalize(angle) }); - } - - for (size_t n = 0; n < arc_points.size() - 1; n++) - { - const auto& p0 = arc_points[n].point; - const auto& p1 = arc_points[n + 1].point; - const auto& n0 = arc_points[n].normal; - const auto& n1 = arc_points[n + 1].normal; - renderer.drawTexturedQuad("gradient.png", - p0, p0 - n0 * outline_thickness, - p1 - n1 * outline_thickness, p1, - { 0.f, 0.5f }, { 1.f, 0.5f }, { 1.f, 0.5f }, { 0.f, 0.5f }, - color); - } - - if (beam_arc < 360.f) - { - // Arc bounds. - // We use the left- and right-most edges as lines, going inwards, parallel to the center. - const auto left_edge = vec2FromAngle(angle0) * beam_range; - const auto right_edge = vec2FromAngle(angle0 + beam_arc) * beam_range; - - // Compute the half point, always going clockwise from the left edge. - // This makes sure the algorithm never takes the short road. - auto halfway_angle = vec2FromAngle(angle0 + beam_arc / 2.f) * beam_range; - auto middle = glm::normalize(halfway_angle); - - // Edge vectors. - const auto left_edge_vector = glm::normalize(left_edge); - const auto right_edge_vector = glm::normalize(right_edge); - - // Edge normals, inwards. - auto left_edge_normal = glm::vec2{ left_edge_vector.y, -left_edge_vector.x }; - const auto right_edge_normal = glm::vec2{ -right_edge_vector.y, right_edge_vector.x }; - - // Initial offset, follow along the edges' normals, inwards. - auto left_inner_offset = -left_edge_normal * outline_thickness; - auto right_inner_offset = -right_edge_normal * outline_thickness; - - if (beam_arc < 180.f) - { - // The thickness being perpendicular from the edges, - // the inner lines just crosses path on the height, - // so just use that point. - left_inner_offset = middle * outline_thickness / sinf(glm::radians(beam_arc / 2.f)); - right_inner_offset = left_inner_offset; - } - else - { - // Make it shrink nicely as it grows up to 360 deg. - // For that, we use the edge's normal against the height which will change from 0 to 90deg. - // Also flip the direction so our points stay inside the beam. - auto thickness_scale = -glm::dot(middle, right_edge_normal); - left_inner_offset *= thickness_scale; - right_inner_offset *= thickness_scale; - } - - renderer.drawTexturedQuad("gradient.png", - arc_center, arc_center + left_inner_offset, - arc_center + left_edge - left_edge_normal * outline_thickness, arc_center + left_edge, - { 0.f, 0.5f }, { 1.f, 0.5f }, { 1.f, 0.5f }, { 0.f, 0.5f }, - color); - - renderer.drawTexturedQuad("gradient.png", - arc_center, arc_center + right_inner_offset, - arc_center + right_edge - right_edge_normal * outline_thickness, arc_center + right_edge, - { 0.f, 0.5f }, { 1.f, 0.5f }, { 1.f, 0.5f }, { 0.f, 0.5f }, - color); - } - }; - - // For each beam ... - for(int n = 0; n < max_beam_weapons; n++) - { - // Draw beam arcs only if the beam has a range. A beam with range 0 - // effectively doesn't exist; exit if that's the case. - if (beam_weapons[n].getRange() == 0.0f) continue; - - // If the beam is cooling down, flash and fade the arc color. - glm::u8vec4 color = Tween::linear(std::max(0.0f, beam_weapons[n].getCooldown()), 0, beam_weapons[n].getCycleTime(), beam_weapons[n].getArcColor(), beam_weapons[n].getArcFireColor()); - - - // Initialize variables from the beam's data. - float beam_direction = beam_weapons[n].getDirection(); - float beam_arc = beam_weapons[n].getArc(); - float beam_range = beam_weapons[n].getRange(); - - // Set the beam's origin on radar to its relative position on the mesh. - auto beam_offset = rotateVec2(ship_template->model_data->getBeamPosition2D(n) * scale, getRotation()-rotation); - auto arc_center = beam_offset + position; - - draw_arc(arc_center, getRotation() - rotation + (beam_direction - beam_arc / 2.0f), beam_arc, beam_range * scale, color); - - - // If the beam is turreted, draw the turret's arc. Otherwise, exit. - if (beam_weapons[n].getTurretArc() == 0.0f) - continue; - - // Initialize variables from the turret data. - float turret_arc = beam_weapons[n].getTurretArc(); - float turret_direction = beam_weapons[n].getTurretDirection(); - - // Draw the turret's bounds, at half the transparency of the beam's. - // TODO: Make this color configurable. - color.a /= 4; - - draw_arc(arc_center, getRotation() - rotation + (turret_direction - turret_arc / 2.0f), turret_arc, beam_range * scale, color); - } - } // If not on long-range radar ... if (!long_range) { @@ -688,11 +540,6 @@ void SpaceShip::update(float delta) addHeat(SYS_Impulse, fabs(combat_maneuver_boost_active) * delta * heat_per_combat_maneuver_boost); addHeat(SYS_Maneuver, fabs(combat_maneuver_strafe_active) * delta * heat_per_combat_maneuver_strafe); - for(int n = 0; n < max_beam_weapons; n++) - { - beam_weapons[n].update(delta); - } - for(int n=0; nbeams[n].getArc() @@ -1423,7 +1300,7 @@ string SpaceShip::getScriptExportModificationsOnTemplate() ret += ":setBeamWeaponTurret(" + string(n) + ", " + string(beam_weapons[n].getTurretArc(), 0) + ", " + string(beam_weapons[n].getTurretDirection(), 0) + ", " + string(beam_weapons[n].getTurretRotationRate(), 0) + ")"; } } - +*/ return ret; } diff --git a/src/spaceObjects/spaceship.h b/src/spaceObjects/spaceship.h index dc6b0c17a7..a30a6c272e 100644 --- a/src/spaceObjects/spaceship.h +++ b/src/spaceObjects/spaceship.h @@ -154,13 +154,6 @@ class SpaceShip : public ShipTemplateBasedObject int8_t weapon_tube_count; WeaponTube weapon_tube[max_weapon_tubes]; - /*! - * [output] Frequency of beam weapons - */ - int beam_frequency; - ESystem beam_system_target; - BeamWeapon beam_weapons[max_beam_weapons]; - /** * Frequency setting of the shields. */ @@ -357,76 +350,36 @@ class SpaceShip : public ShipTemplateBasedObject void setJumpDriveCharge(float charge) { jump_drive_charge = charge; } float getJumpDelay() { return jump_delay; } - float getBeamWeaponArc(int index) { if (index < 0 || index >= max_beam_weapons) return 0.0; return beam_weapons[index].getArc(); } - float getBeamWeaponDirection(int index) { if (index < 0 || index >= max_beam_weapons) return 0.0; return beam_weapons[index].getDirection(); } - float getBeamWeaponRange(int index) { if (index < 0 || index >= max_beam_weapons) return 0.0; return beam_weapons[index].getRange(); } + float getBeamWeaponArc(int index); + float getBeamWeaponDirection(int index); + float getBeamWeaponRange(int index); - float getBeamWeaponTurretArc(int index) - { - if (index < 0 || index >= max_beam_weapons) - return 0.0; - return beam_weapons[index].getTurretArc(); - } + float getBeamWeaponTurretArc(int index); - float getBeamWeaponTurretDirection(int index) - { - if (index < 0 || index >= max_beam_weapons) - return 0.0; - return beam_weapons[index].getTurretDirection(); - } + float getBeamWeaponTurretDirection(int index); - float getBeamWeaponTurretRotationRate(int index) - { - if (index < 0 || index >= max_beam_weapons) - return 0.0; - return beam_weapons[index].getTurretRotationRate(); - } + float getBeamWeaponTurretRotationRate(int index); - float getBeamWeaponCycleTime(int index) { if (index < 0 || index >= max_beam_weapons) return 0.0; return beam_weapons[index].getCycleTime(); } - float getBeamWeaponDamage(int index) { if (index < 0 || index >= max_beam_weapons) return 0.0; return beam_weapons[index].getDamage(); } - float getBeamWeaponEnergyPerFire(int index) { if (index < 0 || index >= max_beam_weapons) return 0.0; return beam_weapons[index].getEnergyPerFire(); } - float getBeamWeaponHeatPerFire(int index) { if (index < 0 || index >= max_beam_weapons) return 0.0; return beam_weapons[index].getHeatPerFire(); } + float getBeamWeaponCycleTime(int index); + float getBeamWeaponDamage(int index); + float getBeamWeaponEnergyPerFire(int index); + float getBeamWeaponHeatPerFire(int index); int getShieldsFrequency(){ return shield_frequency; } void setShieldsFrequency(int freq) { if ((freq > SpaceShip::max_frequency) || (freq < 0)) return; shield_frequency = freq;} - int getBeamFrequency(){ return beam_frequency; } + int getBeamFrequency(); - void setBeamWeapon(int index, float arc, float direction, float range, float cycle_time, float damage) - { - if (index < 0 || index >= max_beam_weapons) - return; - beam_weapons[index].setArc(arc); - beam_weapons[index].setDirection(direction); - beam_weapons[index].setRange(range); - beam_weapons[index].setCycleTime(cycle_time); - beam_weapons[index].setDamage(damage); - } + void setBeamWeapon(int index, float arc, float direction, float range, float cycle_time, float damage); - void setBeamWeaponTurret(int index, float arc, float direction, float rotation_rate) - { - if (index < 0 || index >= max_beam_weapons) - return; - beam_weapons[index].setTurretArc(arc); - beam_weapons[index].setTurretDirection(direction); - beam_weapons[index].setTurretRotationRate(rotation_rate); - } + void setBeamWeaponTurret(int index, float arc, float direction, float rotation_rate); - void setBeamWeaponTexture(int index, string texture) - { - if (index < 0 || index >= max_beam_weapons) - return; - beam_weapons[index].setBeamTexture(texture); - } + void setBeamWeaponTexture(int index, string texture); - void setBeamWeaponEnergyPerFire(int index, float energy) { if (index < 0 || index >= max_beam_weapons) return; beam_weapons[index].setEnergyPerFire(energy); } - void setBeamWeaponHeatPerFire(int index, float heat) { if (index < 0 || index >= max_beam_weapons) return; beam_weapons[index].setHeatPerFire(heat); } - void setBeamWeaponArcColor(int index, float r, float g, float b, float fire_r, float fire_g, float fire_b) { - if (index < 0 || index >= max_beam_weapons) return; - beam_weapons[index].setArcColor(glm::u8vec4(r * 255, g * 255, b * 255, 128)); - beam_weapons[index].setArcFireColor(glm::u8vec4(fire_r * 255, fire_g * 255, fire_b * 255, 255)); - } - void setBeamWeaponDamageType(int index, EDamageType type) { if (index < 0 || index >= max_beam_weapons) return; beam_weapons[index].setDamageType(type); } + void setBeamWeaponEnergyPerFire(int index, float energy); + void setBeamWeaponHeatPerFire(int index, float heat); + void setBeamWeaponArcColor(int index, float r, float g, float b, float fire_r, float fire_g, float fire_b); + void setBeamWeaponDamageType(int index, EDamageType type); void setWeaponTubeCount(int amount); int getWeaponTubeCount(); diff --git a/src/spaceObjects/spaceshipParts/beamWeapon.cpp b/src/spaceObjects/spaceshipParts/beamWeapon.cpp deleted file mode 100644 index ce541dcbcb..0000000000 --- a/src/spaceObjects/spaceshipParts/beamWeapon.cpp +++ /dev/null @@ -1,291 +0,0 @@ -#include "beamWeapon.h" -#include "spaceObjects/spaceship.h" -#include "spaceObjects/beamEffect.h" -#include "spaceObjects/spaceObject.h" -#include "multiplayer_server.h" - -#include - - -BeamWeapon::BeamWeapon() -{ - arc = 0; - direction = 0; - range = 0; - turret_arc = 0.0f; - turret_direction = 0.0f; - turret_rotation_rate = 0.0f; - cycle_time = 6.0f; - cooldown = 0.0f; - damage = 1.0f; - energy_per_beam_fire = 3.0f; - heat_per_beam_fire = 0.02f; - parent = nullptr; - arc_color = {255, 0, 0, 128}; - arc_color_fire = {255, 255, 0, 128}; - damage_type = DT_Energy; -} - -void BeamWeapon::setParent(SpaceShip* parent) -{ - SDL_assert(!this->parent); - this->parent = parent; - - parent->registerMemberReplication(&arc); - parent->registerMemberReplication(&direction); - parent->registerMemberReplication(&range); - parent->registerMemberReplication(&turret_arc); - parent->registerMemberReplication(&turret_direction); - parent->registerMemberReplication(&turret_rotation_rate); - parent->registerMemberReplication(&cycle_time); - parent->registerMemberReplication(&cooldown, 0.5); - parent->registerMemberReplication(&arc_color); - parent->registerMemberReplication(&arc_color_fire); -} - -void BeamWeapon::setArc(float arc) -{ - this->arc = arc; -} - -float BeamWeapon::getArc() -{ - return arc; -} - -void BeamWeapon::setArcColor(glm::u8vec4 color) -{ - arc_color = color; -} - -glm::u8vec4 BeamWeapon::getArcColor() -{ - return arc_color; -} - -void BeamWeapon::setArcFireColor(glm::u8vec4 color) -{ - arc_color_fire = color; -} - -glm::u8vec4 BeamWeapon::getArcFireColor() -{ - return arc_color_fire; -} - -void BeamWeapon::setDamageType(EDamageType type) -{ - damage_type = type; -} - -void BeamWeapon::setDirection(float direction) -{ - this->direction = direction; -} - -float BeamWeapon::getDirection() -{ - return direction; -} - -void BeamWeapon::setRange(float range) -{ - this->range = range; -} - -float BeamWeapon::getRange() -{ - return range; -} - -void BeamWeapon::setTurretArc(float arc) -{ - this->turret_arc = arc; -} - -float BeamWeapon::getTurretArc() -{ - return turret_arc; -} - -void BeamWeapon::setTurretDirection(float direction) -{ - this->turret_direction = direction; -} - -float BeamWeapon::getTurretDirection() -{ - return turret_direction; -} - -void BeamWeapon::setTurretRotationRate(float rotation_rate) -{ - this->turret_rotation_rate = rotation_rate; -} - -float BeamWeapon::getTurretRotationRate() -{ - return turret_rotation_rate; -} - -void BeamWeapon::setCycleTime(float cycle_time) -{ - this->cycle_time = cycle_time; -} - -float BeamWeapon::getCycleTime() -{ - return cycle_time; -} - -void BeamWeapon::setDamage(float damage) -{ - this->damage = damage; -} - -float BeamWeapon::getDamage() -{ - return damage; -} - -float BeamWeapon::getEnergyPerFire() -{ - return energy_per_beam_fire; -} - -void BeamWeapon::setEnergyPerFire(float energy) -{ - energy_per_beam_fire = energy; -} - -float BeamWeapon::getHeatPerFire() -{ - return heat_per_beam_fire; -} - -void BeamWeapon::setHeatPerFire(float heat) -{ - heat_per_beam_fire = heat; -} - -void BeamWeapon::setPosition(glm::vec3 position) -{ - this->position = position; -} - -glm::vec3 BeamWeapon::getPosition() -{ - return position; -} - -void BeamWeapon::setBeamTexture(string beam_texture) -{ - this->beam_texture = beam_texture; -} - -string BeamWeapon::getBeamTexture() -{ - return beam_texture; -} - -float BeamWeapon::getCooldown() -{ - return cooldown; -} - -void BeamWeapon::update(float delta) -{ - if (cooldown > 0.0f) - cooldown -= delta * parent->getSystemEffectiveness(SYS_BeamWeapons); - - P target = parent->getTarget(); - auto docking_port = parent->entity.getComponent(); - - // Check on beam weapons only if we are on the server, have a target, and - // not paused, and if the beams are cooled down or have a turret arc. - if (game_server && range > 0.0f && target && parent->isEnemy(target) && delta > 0 && parent->current_warp == 0.0f && (!docking_port || docking_port->state == DockingPort::State::NotDocking)) - { - // Get the angle to the target. - auto diff = target->getPosition() - (parent->getPosition() + rotateVec2(glm::vec2(position.x, position.y), parent->getRotation())); - float distance = glm::length(diff) - target->getRadius() / 2.0f; - - // We also only care if the target is within no more than its - // range * 1.3, which is when we want to start rotating the turret. - // TODO: Add a manual aim override similar to weapon tubes. - if (distance < range * 1.3f) - { - float angle = vec2ToAngle(diff); - float angle_diff = angleDifference(direction + parent->getRotation(), angle); - - if (turret_arc > 0) - { - // Get the target's angle relative to the turret's direction. - float turret_angle_diff = angleDifference(turret_direction + parent->getRotation(), angle); - - // If the turret can rotate ... - if (turret_rotation_rate > 0) - { - // ... and if the target is within the turret's arc ... - if (fabsf(turret_angle_diff) < turret_arc / 2.0f) - { - // ... rotate the turret's beam toward the target. - if (fabsf(angle_diff) > 0) - { - direction += (angle_diff / fabsf(angle_diff)) * std::min(turret_rotation_rate * parent->getSystemEffectiveness(SYS_BeamWeapons), fabsf(angle_diff)); - } - // If the target is outside of the turret's arc ... - } else { - // ... rotate the turret's beam toward the turret's - // direction to reset it. - float reset_angle_diff = angleDifference(direction, turret_direction); - - if (fabsf(reset_angle_diff) > 0) - { - direction += (reset_angle_diff / fabsf(reset_angle_diff)) * std::min(turret_rotation_rate * parent->getSystemEffectiveness(SYS_BeamWeapons), fabsf(reset_angle_diff)); - } - } - } - } - - // If the target is in the beam's arc and range, the beam has cooled - // down, and the beam can consume enough energy to fire ... - if (distance < range && cooldown <= 0.0f && fabsf(angle_diff) < arc / 2.0f && parent->useEnergy(energy_per_beam_fire)) - { - // ... add heat to the beam and zap the target. - parent->addHeat(SYS_BeamWeapons, heat_per_beam_fire); - fire(target, parent->beam_system_target); - } - } - // If the beam is turreted and can move, but doesn't have a target, reset it - // if necessary. - } else if (game_server && range > 0.0f && delta > 0 && turret_arc > 0.0f && direction != turret_direction && turret_rotation_rate > 0) { - float reset_angle_diff = angleDifference(direction, turret_direction); - - if (fabsf(reset_angle_diff) > 0) - { - direction += (reset_angle_diff / fabsf(reset_angle_diff)) * std::min(turret_rotation_rate * parent->getSystemEffectiveness(SYS_BeamWeapons), fabsf(reset_angle_diff)); - } - } -} - -void BeamWeapon::fire(P target, ESystem system_target) -{ - //When we fire a beam, and we hit an enemy, check if we are not scanned yet, if we are not, and we hit something that we know is an enemy or friendly, - // we now know if this ship is an enemy or friend. - parent->didAnOffensiveAction(); - - cooldown = cycle_time; // Reset time of weapon - - auto hit_location = target->getPosition() - glm::normalize(target->getPosition() - parent->getPosition()) * target->getRadius(); - P effect = new BeamEffect(); - effect->setSource(parent, position); - effect->setTarget(target, hit_location); - effect->beam_texture = beam_texture; - effect->beam_fire_sound = "sfx/laser_fire.wav"; - effect->beam_fire_sound_power = damage / 6.0f; - - DamageInfo info(parent, damage_type, hit_location); - info.frequency = parent->beam_frequency; // Beam weapons now always use frequency of the ship. - info.system_target = system_target; - target->takeDamage(damage, info); -} diff --git a/src/spaceObjects/spaceshipParts/beamWeapon.h b/src/spaceObjects/spaceshipParts/beamWeapon.h deleted file mode 100644 index b9c7157241..0000000000 --- a/src/spaceObjects/spaceshipParts/beamWeapon.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef BEAM_WEAPON_H -#define BEAM_WEAPON_H - -#include "stringImproved.h" -#include "spaceObjects/spaceObject.h" - -class SpaceShip; - -class BeamWeapon : sp::NonCopyable -{ -public: - BeamWeapon(); - - void fire(P target, ESystem system_target); - - void setParent(SpaceShip* parent); - - void setArc(float arc); - float getArc(); - - void setArcColor(glm::u8vec4 color); - glm::u8vec4 getArcColor(); - - void setArcFireColor(glm::u8vec4 color); - glm::u8vec4 getArcFireColor(); - - void setDamageType(EDamageType type); - - void setDirection(float direction); - float getDirection(); - - void setRange(float range); - float getRange(); - - void setTurretArc(float arc); - float getTurretArc(); - - void setTurretDirection(float direction); - float getTurretDirection(); - - void setTurretRotationRate(float rotation_rate); - float getTurretRotationRate(); - - void setCycleTime(float cycle_time); - float getCycleTime(); - - void setDamage(float damage); - float getDamage(); - - float getEnergyPerFire(); - void setEnergyPerFire(float energy); - - float getHeatPerFire(); - void setHeatPerFire(float heat); - - void setPosition(glm::vec3 position); - glm::vec3 getPosition(); - - void setBeamTexture(string beam_texture); - string getBeamTexture(); - - float getCooldown(); - - void update(float delta); -protected: - glm::vec3 position;//Visual position on the 3D model where this beam is fired from. - SpaceShip* parent; //The ship that this beam weapon is attached to. - - //Beam configuration - float arc; - float direction; - float range; - float turret_arc; - float turret_direction; - float turret_rotation_rate; - float cycle_time; - float damage;//Server side only - float energy_per_beam_fire;//Server side only - float heat_per_beam_fire;//Server side only - glm::u8vec4 arc_color; - glm::u8vec4 arc_color_fire; - EDamageType damage_type; - //Beam runtime state - float cooldown; - string beam_texture; -}; - -#endif//BEAM_WEAPON_H diff --git a/src/systems/beamweapon.cpp b/src/systems/beamweapon.cpp new file mode 100644 index 0000000000..cd41b65de9 --- /dev/null +++ b/src/systems/beamweapon.cpp @@ -0,0 +1,113 @@ +#include "beamweapon.h" +#include "multiplayer_server.h" +#include "components/beamweapon.h" +#include "components/collision.h" +#include "components/docking.h" +#include "components/reactor.h" +#include "spaceObjects/spaceObject.h" +#include "spaceObjects/spaceship.h" +#include "spaceObjects/beamEffect.h" +#include "ecs/query.h" + +void BeamWeaponSystem::update(float delta) +{ + if (!game_server) return; + if (delta <= 0.0f) return; + + for(auto [entity, beamsys, position, reactor, docking_port, obj] : sp::ecs::Query, sp::ecs::optional, SpaceObject*>()) { + if (!beamsys.target) continue; + P ship = P(obj); + + for(auto& mount : beamsys.mounts) { + if (mount.cooldown > 0.0f) + mount.cooldown -= delta * beamsys.get_system_effectiveness(); + + P target = *beamsys.target.getComponent(); + + // Check on beam weapons only if we are on the server, have a target, and + // not paused, and if the beams are cooled down or have a turret arc. + if (mount.range > 0.0f && target && obj->isEnemy(target) && delta > 0.0f && (!ship || ship->current_warp == 0.0f) && (!docking_port || docking_port->state == DockingPort::State::NotDocking)) + { + // Get the angle to the target. + auto diff = target->getPosition() - (position.getPosition() + rotateVec2(glm::vec2(mount.position.x, mount.position.y), position.getRotation())); + float distance = glm::length(diff) - target->getRadius() / 2.0f; + + // We also only care if the target is within no more than its + // range * 1.3, which is when we want to start rotating the turret. + // TODO: Add a manual aim override similar to weapon tubes. + if (distance < mount.range * 1.3f) + { + float angle = vec2ToAngle(diff); + float angle_diff = angleDifference(mount.direction + position.getRotation(), angle); + + if (mount.turret_arc > 0) + { + // Get the target's angle relative to the turret's direction. + float turret_angle_diff = angleDifference(mount.turret_direction + position.getRotation(), angle); + + // If the turret can rotate ... + if (mount.turret_rotation_rate > 0) + { + // ... and if the target is within the turret's arc ... + if (fabsf(turret_angle_diff) < mount.turret_arc / 2.0f) + { + // ... rotate the turret's beam toward the target. + if (fabsf(angle_diff) > 0) + { + mount.direction += (angle_diff / fabsf(angle_diff)) * std::min(mount.turret_rotation_rate * beamsys.get_system_effectiveness(), fabsf(angle_diff)); + } + // If the target is outside of the turret's arc ... + } else { + // ... rotate the turret's beam toward the turret's + // direction to reset it. + float reset_angle_diff = angleDifference(mount.direction, mount.turret_direction); + + if (fabsf(reset_angle_diff) > 0) + { + mount.direction += (reset_angle_diff / fabsf(reset_angle_diff)) * std::min(mount.turret_rotation_rate * beamsys.get_system_effectiveness(), fabsf(reset_angle_diff)); + } + } + } + } + + // If the target is in the beam's arc and range, the beam has cooled + // down, and the beam can consume enough energy to fire ... + if (distance < mount.range && mount.cooldown <= 0.0f && fabsf(angle_diff) < mount.arc / 2.0f && (!reactor || reactor->use_energy(mount.energy_per_beam_fire))) + { + // ... add heat to the beam and zap the target. + beamsys.add_heat(mount.heat_per_beam_fire); + + //When we fire a beam, and we hit an enemy, check if we are not scanned yet, if we are not, and we hit something that we know is an enemy or friendly, + // we now know if this ship is an enemy or friend. + if (ship) + ship->didAnOffensiveAction(); + + mount.cooldown = mount.cycle_time; // Reset time of weapon + + auto hit_location = target->getPosition() - glm::normalize(target->getPosition() - position.getPosition()) * target->getRadius(); + P effect = new BeamEffect(); + effect->setSource(obj, mount.position); + effect->setTarget(target, hit_location); + effect->beam_texture = mount.texture; + effect->beam_fire_sound = "sfx/laser_fire.wav"; + effect->beam_fire_sound_power = mount.damage / 6.0f; + + DamageInfo info(obj, mount.damage_type, hit_location); + info.frequency = beamsys.frequency; + info.system_target = beamsys.system_target; + target->takeDamage(mount.damage, info); + } + } + // If the beam is turreted and can move, but doesn't have a target, reset it + // if necessary. + } else if (mount.range > 0.0f && mount.turret_arc > 0.0f && mount.direction != mount.turret_direction && mount.turret_rotation_rate > 0) { + float reset_angle_diff = angleDifference(mount.direction, mount.turret_direction); + + if (fabsf(reset_angle_diff) > 0) + { + mount.direction += (reset_angle_diff / fabsf(reset_angle_diff)) * std::min(mount.turret_rotation_rate * beamsys.get_system_effectiveness(), fabsf(reset_angle_diff)); + } + } + } + } +} \ No newline at end of file diff --git a/src/systems/beamweapon.h b/src/systems/beamweapon.h new file mode 100644 index 0000000000..84f72fa6e2 --- /dev/null +++ b/src/systems/beamweapon.h @@ -0,0 +1,10 @@ +#pragma once + +#include "ecs/system.h" + + +class BeamWeaponSystem : public sp::ecs::System +{ +public: + void update(float delta) override; +}; From ec7b75fd019f4c068dda0501155aff8c718cc7b1 Mon Sep 17 00:00:00 2001 From: Daid Date: Thu, 17 Nov 2022 17:05:14 +0100 Subject: [PATCH 016/320] Hull to ECS component. --- CMakeLists.txt | 1 + src/ai/ai.cpp | 7 ++- src/components/hull.h | 17 ++++++ src/gameStateLogger.cpp | 8 +-- src/hardware/hardwareController.cpp | 2 +- src/screenComponents/radarView.cpp | 9 ++++ src/screens/crew6/engineeringScreen.cpp | 15 ++++-- src/screens/extra/damcon.cpp | 14 +++-- src/screens/gm/tweak.cpp | 10 ++-- src/spaceObjects/playerSpaceship.cpp | 4 +- src/spaceObjects/shipTemplateBasedObject.cpp | 55 ++++++++++++-------- src/spaceObjects/shipTemplateBasedObject.h | 16 +++--- src/spaceObjects/spaceStation.cpp | 5 +- src/spaceObjects/spaceship.cpp | 27 +++++----- src/spaceObjects/spaceship.h | 1 - src/systems/docking.cpp | 10 ++-- src/threatLevelEstimate.cpp | 10 +++- 17 files changed, 136 insertions(+), 75 deletions(-) create mode 100644 src/components/hull.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ee47c1d8e3..5e5222d94e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -353,6 +353,7 @@ set(MAIN_SOURCES src/spaceObjects/zone.cpp src/spaceObjects/spaceshipParts/weaponTube.cpp src/components/radar.h + src/components/hull.h src/components/rendering.h src/components/docking.h src/components/shipsystem.h diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp index 5fc855014a..a9b902ee64 100644 --- a/src/ai/ai.cpp +++ b/src/ai/ai.cpp @@ -6,6 +6,7 @@ #include "random.h" #include "components/docking.h" #include "components/impulse.h" +#include "components/hull.h" #include "components/beamweapon.h" #include "systems/collision.h" #include "ecs/query.h" @@ -463,9 +464,11 @@ void ShipAI::runOrders() } } } - if ((bay->flags & DockingBay::Repair) && (owner->hull_strength < owner->hull_max)) + if (bay->flags & DockingBay::Repair) { - allow_undock = false; + auto hull = owner->entity.getComponent(); + if (hull && hull->current < hull->max) + allow_undock = false; } } if (allow_undock) diff --git a/src/components/hull.h b/src/components/hull.h new file mode 100644 index 0000000000..0572362f97 --- /dev/null +++ b/src/components/hull.h @@ -0,0 +1,17 @@ +#pragma once + +#include "scriptInterface.h" + + +// Component to indicate that this entity has a hull and can get hull damage. +// Usually entities are destroyed once they reach zero hull. But you can disable this to prevent player ship destruction in LARP scenarios or tutorials. +class Hull +{ +public: + float current = 100.0f; + float max = 100.0f; + bool allow_destruction = true; + + ScriptSimpleCallback on_destruction; + ScriptSimpleCallback on_taking_damage; +}; diff --git a/src/gameStateLogger.cpp b/src/gameStateLogger.cpp index fd0038342d..0216e4f5cf 100644 --- a/src/gameStateLogger.cpp +++ b/src/gameStateLogger.cpp @@ -311,7 +311,7 @@ void GameStateLogger::writeShipEntry(JSONGenerator& json, P ship) json.write("faction", ship->getFaction()); json.write("ship_type", ship->type_name); //json.write("energy_level", ship->energy_level); - json.write("hull", ship->hull_strength); + //json.write("hull", ship->hull_strength); if (ship->target_id > -1) json.write("target", ship->target_id); /* @@ -440,7 +440,7 @@ void GameStateLogger::writeShipEntry(JSONGenerator& json, P ship) //config.write("impulse_acceleration", ship->impulse_acceleration); //config.write("impulse_reverse_speed", ship->impulse_max_reverse_speed); //config.write("impulse_reverse_acceleration", ship->impulse_reverse_acceleration); - config.write("hull", ship->hull_max); + //config.write("hull", ship->hull_max); if (ship->has_warp_drive) config.write("warp", ship->warp_speed_per_warp_level); if (ship->combat_maneuver_boost_speed > 0) @@ -520,7 +520,7 @@ void GameStateLogger::writeStationEntry(JSONGenerator& json, P sta json.write("callsign", station->getCallSign()); json.write("faction", station->getFaction()); json.write("station_type", station->type_name); - json.write("hull", station->hull_strength); + //json.write("hull", station->hull_strength); if (station->shield_count > 0) { json.startArray("shields"); @@ -530,7 +530,7 @@ void GameStateLogger::writeStationEntry(JSONGenerator& json, P sta } { JSONGenerator config = json.createDict("config"); - config.write("hull", station->hull_max); + //config.write("hull", station->hull_max); if (station->shield_count > 0) { config.startArray("shields"); diff --git a/src/hardware/hardwareController.cpp b/src/hardware/hardwareController.cpp index b821035d4a..5049628346 100644 --- a/src/hardware/hardwareController.cpp +++ b/src/hardware/hardwareController.cpp @@ -358,7 +358,7 @@ bool HardwareController::getVariableValue(string variable_name, float& value) value = bool(ship) ? 1.0f : 0.0f; return true; } - SHIP_VARIABLE("Hull", 100.0f * ship->hull_strength / ship->hull_max); + //SHIP_VARIABLE("Hull", 100.0f * ship->hull_strength / ship->hull_max); SHIP_VARIABLE("FrontShield", ship->getShieldPercentage(0)); SHIP_VARIABLE("RearShield", ship->getShieldPercentage(1)); SHIP_VARIABLE("Shield0", ship->getShieldPercentage(0)); diff --git a/src/screenComponents/radarView.cpp b/src/screenComponents/radarView.cpp index 6e65c19269..a7adc47ce2 100644 --- a/src/screenComponents/radarView.cpp +++ b/src/screenComponents/radarView.cpp @@ -4,6 +4,7 @@ #include "systems/collision.h" #include "components/collision.h" #include "components/beamweapon.h" +#include "components/hull.h" #include "main.h" #include "gameGlobalInfo.h" #include "spaceObjects/nebula.h" @@ -898,6 +899,14 @@ void GuiRadarView::drawObjectsGM(sp::RenderTarget& renderer) { obj->drawOnGMRadar(renderer, object_position_on_screen, scale, view_rotation, long_range); } + + if (!long_range) + { + auto hull = obj->entity.getComponent(); + if (hull) { + renderer.fillRect(sp::Rect(object_position_on_screen.x - 30, object_position_on_screen.y - 30, 60 * hull->current / hull->max, 5), glm::u8vec4(128, 255, 128, 128)); + } + } } } diff --git a/src/screens/crew6/engineeringScreen.cpp b/src/screens/crew6/engineeringScreen.cpp index 10cf85eb14..22647fc46e 100644 --- a/src/screens/crew6/engineeringScreen.cpp +++ b/src/screens/crew6/engineeringScreen.cpp @@ -4,6 +4,7 @@ #include "components/reactor.h" #include "components/beamweapon.h" +#include "components/hull.h" #include "screenComponents/shipInternalView.h" #include "screenComponents/selfDestructButton.h" @@ -202,11 +203,15 @@ void EngineeringScreen::onDraw(sp::RenderTarget& renderer) else energy_display->setColor(glm::u8vec4{255,255,255,255}); } - hull_display->setValue(toNearbyIntString(100.0f * my_spaceship->hull_strength / my_spaceship->hull_max) + "%"); - if (my_spaceship->hull_strength < my_spaceship->hull_max / 4.0f) - hull_display->setColor(glm::u8vec4(255, 0, 0, 255)); - else - hull_display->setColor(glm::u8vec4{255,255,255,255}); + + auto hull = my_spaceship->entity.getComponent(); + if (hull) { + hull_display->setValue(toNearbyIntString(100.0f * hull->current / hull->max) + "%"); + if (hull->current < hull->max / 4.0f) + hull_display->setColor(glm::u8vec4(255, 0, 0, 255)); + else + hull_display->setColor(glm::u8vec4{255,255,255,255}); + } front_shield_display->setValue(string(my_spaceship->getShieldPercentage(0)) + "%"); if (my_spaceship->hasSystem(SYS_FrontShield)) { diff --git a/src/screens/extra/damcon.cpp b/src/screens/extra/damcon.cpp index 58f143a3fb..6b0a55c5db 100644 --- a/src/screens/extra/damcon.cpp +++ b/src/screens/extra/damcon.cpp @@ -5,6 +5,7 @@ #include "screenComponents/shieldFreqencySelect.h" #include "screenComponents/shipInternalView.h" #include "screenComponents/customShipFunctions.h" +#include "components/hull.h" #include "gui/gui2_keyvaluedisplay.h" @@ -35,11 +36,14 @@ void DamageControlScreen::onDraw(sp::RenderTarget& renderer) if (my_spaceship) { - hull_display->setValue(string(int(100 * my_spaceship->hull_strength / my_spaceship->hull_max)) + "%"); - if (my_spaceship->hull_strength < my_spaceship->hull_max / 4.0f) - hull_display->setColor(glm::u8vec4(255, 0, 0, 255)); - else - hull_display->setColor(glm::u8vec4{255,255,255,255}); + auto hull = my_spaceship->entity.getComponent(); + if (hull) { + hull_display->setValue(string(int(100 * hull->current / hull->max)) + "%"); + if (hull->current < hull->max / 4.0f) + hull_display->setColor(glm::u8vec4(255, 0, 0, 255)); + else + hull_display->setColor(glm::u8vec4{255,255,255,255}); + } for(unsigned int n=0; nsetSize(GuiElement::GuiSizeMax, 50); hull_max_slider = new GuiSlider(right_col, "", 0.0, 500, 0.0, [this](float value) { - target->hull_max = round(value); - target->hull_strength = std::min(target->hull_strength, target->hull_max); + //target->hull_max = round(value); + //target->hull_strength = std::min(target->hull_strength, target->hull_max); }); hull_max_slider->addOverlay()->setSize(GuiElement::GuiSizeMax, 40); (new GuiLabel(right_col, "", tr("Hull current:"), 30))->setSize(GuiElement::GuiSizeMax, 50); hull_slider = new GuiSlider(right_col, "", 0.0, 500, 0.0, [this](float value) { - target->hull_strength = std::min(roundf(value), target->hull_max); + //target->hull_strength = std::min(roundf(value), target->hull_max); }); hull_slider->addOverlay()->setSize(GuiElement::GuiSizeMax, 40); @@ -217,7 +217,7 @@ GuiTweakShip::GuiTweakShip(GuiContainer* owner) void GuiTweakShip::onDraw(sp::RenderTarget& renderer) { - hull_slider->setValue(target->hull_strength); + //TODO: hull_slider->setValue(target->hull_strength); jump_charge_slider->setValue(target->getJumpDriveCharge()); jump_min_distance_slider->setValue(target->jump_drive_min_distance); jump_max_distance_slider->setValue(target->jump_drive_max_distance); @@ -227,7 +227,7 @@ void GuiTweakShip::onDraw(sp::RenderTarget& renderer) //TODO: impulse_speed_slider->setValue(target->impulse_max_speed); //TODO: impulse_reverse_speed_slider->setValue(target->impulse_max_reverse_speed); turn_speed_slider->setValue(target->turn_speed); - hull_max_slider->setValue(target->hull_max); + //TODO: hull_max_slider->setValue(target->hull_max); can_be_destroyed_toggle->setValue(target->getCanBeDestroyed()); short_range_radar_slider->setValue(target->getShortRangeRadarRange()); long_range_radar_slider->setValue(target->getLongRangeRadarRange()); diff --git a/src/spaceObjects/playerSpaceship.cpp b/src/spaceObjects/playerSpaceship.cpp index f8480bcb91..a7161ffb08 100644 --- a/src/spaceObjects/playerSpaceship.cpp +++ b/src/spaceObjects/playerSpaceship.cpp @@ -4,6 +4,7 @@ #include "explosionEffect.h" #include "gameGlobalInfo.h" #include "components/impulse.h" +#include "components/hull.h" #include "main.h" #include "preferenceManager.h" #include "soundManager.h" @@ -587,7 +588,8 @@ void PlayerSpaceship::update(float delta) // If reactor health is worse than -90% and overheating, it explodes, // destroying the ship and damaging a 0.5U radius. - if (can_be_destroyed && systems[SYS_Reactor].health < -0.9f && systems[SYS_Reactor].heat_level == 1.0f) + auto hull = entity.getComponent(); + if (hull && hull->allow_destruction && systems[SYS_Reactor].health < -0.9f && systems[SYS_Reactor].heat_level == 1.0f) { ExplosionEffect* e = new ExplosionEffect(); e->setSize(1000.0f); diff --git a/src/spaceObjects/shipTemplateBasedObject.cpp b/src/spaceObjects/shipTemplateBasedObject.cpp index 29cdd12ecc..0b577f4d7a 100644 --- a/src/spaceObjects/shipTemplateBasedObject.cpp +++ b/src/spaceObjects/shipTemplateBasedObject.cpp @@ -4,6 +4,7 @@ #include "components/collision.h" #include "components/docking.h" #include "components/impulse.h" +#include "components/hull.h" #include "tween.h" #include "i18n.h" @@ -120,7 +121,6 @@ ShipTemplateBasedObject::ShipTemplateBasedObject(float collision_range, string m shield_max[n] = 0.0; shield_hit_effect[n] = 0.0; } - hull_strength = hull_max = 100.0; long_range_radar_range = 30000.0f; short_range_radar_range = 5000.0f; @@ -134,15 +134,10 @@ ShipTemplateBasedObject::ShipTemplateBasedObject(float collision_range, string m registerMemberReplication(&shield_max[n]); registerMemberReplication(&shield_hit_effect[n], 0.5); } - registerMemberReplication(&hull_strength, 0.5); - registerMemberReplication(&hull_max); registerMemberReplication(&long_range_radar_range, 0.5); registerMemberReplication(&short_range_radar_range, 0.5); callsign = "[" + string(getMultiplayerId()) + "]"; - - can_be_destroyed = true; - registerMemberReplication(&can_be_destroyed); } void ShipTemplateBasedObject::drawShieldsOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, float sprite_scale, bool show_levels) @@ -262,7 +257,7 @@ std::unordered_map ShipTemplateBasedObject::getGMInfo() std::unordered_map ret; ret[trMark("gm_info", "CallSign")] = callsign; ret[trMark("gm_info", "Type")] = type_name; - ret[trMark("gm_info", "Hull")] = string(hull_strength) + "/" + string(hull_max); + //ret[trMark("gm_info", "Hull")] = string(hull_strength) + "/" + string(hull_max); for(int n=0; n 0) + auto hull = entity.getComponent(); + if (hull && hull->current > 0) { - if (on_taking_damage.isSet()) + if (hull->on_taking_damage.isSet()) { if (info.instigator) { - on_taking_damage.call(P(this), P(info.instigator)); + hull->on_taking_damage.call(P(this), P(info.instigator)); } else { - on_taking_damage.call(P(this)); + hull->on_taking_damage.call(P(this)); } } } @@ -329,21 +325,24 @@ void ShipTemplateBasedObject::takeDamage(float damage_amount, DamageInfo info) void ShipTemplateBasedObject::takeHullDamage(float damage_amount, DamageInfo& info) { - hull_strength -= damage_amount; - if (hull_strength <= 0.0f && !can_be_destroyed) + auto hull = entity.getComponent(); + if (!hull) + return; + hull->current -= damage_amount; + if (hull->current <= 0.0f && !hull->allow_destruction) { - hull_strength = 1; + hull->current = 1; } - if (hull_strength <= 0.0f) + if (hull->current <= 0.0f) { destroyedByDamage(info); - if (on_destruction.isSet()) + if (hull->on_destruction.isSet()) { if (info.instigator) { - on_destruction.call(P(this), P(info.instigator)); + hull->on_destruction.call(P(this), P(info.instigator)); } else { - on_destruction.call(P(this)); + hull->on_destruction.call(P(this)); } } destroy(); @@ -360,6 +359,14 @@ float ShipTemplateBasedObject::getShieldRechargeRate(int shield_index) return 0.3; } +void ShipTemplateBasedObject::setCanBeDestroyed(bool enabled) { /*TODO*/ } +bool ShipTemplateBasedObject::getCanBeDestroyed() { return true; } + +float ShipTemplateBasedObject::getHull() { return 0.0f; /*TODO*/ } +float ShipTemplateBasedObject::getHullMax() { return 0.0f; /*TODO*/ } +void ShipTemplateBasedObject::setHull(float amount) { /*TODO*/ } +void ShipTemplateBasedObject::setHullMax(float amount) { /*TODO*/ } + void ShipTemplateBasedObject::setTemplate(string template_name) { P new_ship_template = ShipTemplate::getTemplate(template_name); @@ -367,7 +374,6 @@ void ShipTemplateBasedObject::setTemplate(string template_name) ship_template = new_ship_template; type_name = template_name; - hull_strength = hull_max = ship_template->hull; shield_count = ship_template->shield_count; for(int n=0; nshield_level[n]; @@ -377,6 +383,9 @@ void ShipTemplateBasedObject::setTemplate(string template_name) short_range_radar_range = ship_template->short_range_radar_range; if (entity) { + auto hull = entity.getOrAddComponent(); + hull.current = hull.max = ship_template->hull; + auto& trace = entity.getOrAddComponent(); trace.radius = ship_template->model_data->getRadius() * 0.8f; trace.icon = ship_template->radar_trace; @@ -474,12 +483,16 @@ void ShipTemplateBasedObject::setRestocksMissilesDocked(bool enabled) { /*TODO*/ void ShipTemplateBasedObject::onTakingDamage(ScriptSimpleCallback callback) { - this->on_taking_damage = callback; + auto hull = entity.getComponent(); + if (hull) + hull->on_taking_damage = callback; } void ShipTemplateBasedObject::onDestruction(ScriptSimpleCallback callback) { - this->on_destruction = callback; + auto hull = entity.getComponent(); + if (hull) + hull->on_destruction = callback; } string ShipTemplateBasedObject::getShieldDataString() diff --git a/src/spaceObjects/shipTemplateBasedObject.h b/src/spaceObjects/shipTemplateBasedObject.h index 34198fac71..2a851858b5 100644 --- a/src/spaceObjects/shipTemplateBasedObject.h +++ b/src/spaceObjects/shipTemplateBasedObject.h @@ -25,12 +25,8 @@ class ShipTemplateBasedObject : public SpaceObject, public Updatable int shield_count; float shield_level[max_shield_count]; float shield_max[max_shield_count]; - float hull_strength, hull_max; float shield_hit_effect[max_shield_count]; - bool can_be_destroyed; - ScriptSimpleCallback on_destruction; - ScriptSimpleCallback on_taking_damage; public: ShipTemplateBasedObject(float collision_range, string multiplayer_name, float multiplayer_significant_range=-1); @@ -47,8 +43,8 @@ class ShipTemplateBasedObject : public SpaceObject, public Updatable virtual void destroyedByDamage(DamageInfo& info) = 0; virtual float getShieldDamageFactor(DamageInfo& info, int shield_index); - void setCanBeDestroyed(bool enabled) { can_be_destroyed = enabled; } - bool getCanBeDestroyed(){ return can_be_destroyed; } + void setCanBeDestroyed(bool enabled); + bool getCanBeDestroyed(); virtual void applyTemplateValues() = 0; virtual float getShieldRechargeRate(int shield_index); @@ -58,10 +54,10 @@ class ShipTemplateBasedObject : public SpaceObject, public Updatable void setTypeName(string type_name) { this->type_name = type_name; } string getTypeName() { return type_name; } - float getHull() { return hull_strength; } - float getHullMax() { return hull_max; } - void setHull(float amount) { if (amount < 0) return; hull_strength = amount; } - void setHullMax(float amount) { if (amount < 0) return; hull_max = amount; hull_strength = std::max(hull_strength, hull_max); } + float getHull(); + float getHullMax(); + void setHull(float amount); + void setHullMax(float amount); virtual bool getShieldsActive() { return true; } ///Shield script binding functions diff --git a/src/spaceObjects/spaceStation.cpp b/src/spaceObjects/spaceStation.cpp index f75c45eae3..0e564f614f 100644 --- a/src/spaceObjects/spaceStation.cpp +++ b/src/spaceObjects/spaceStation.cpp @@ -3,6 +3,7 @@ #include "spaceObjects/spaceship.h" #include "spaceObjects/playerSpaceship.h" #include "components/collision.h" +#include "components/hull.h" #include "shipTemplate.h" #include "playerInfo.h" #include "factionInfo.h" @@ -66,7 +67,9 @@ void SpaceStation::destroyedByDamage(DamageInfo& info) } points /= shield_count; } - points += hull_max * 0.1f; + auto hull = entity.getComponent(); + if (hull) + points += hull->max * 0.1f; if (isEnemy(info.instigator)) info.instigator->addReputationPoints(points); else diff --git a/src/spaceObjects/spaceship.cpp b/src/spaceObjects/spaceship.cpp index 0fbe795523..64e76ea1ff 100644 --- a/src/spaceObjects/spaceship.cpp +++ b/src/spaceObjects/spaceship.cpp @@ -21,6 +21,7 @@ #include "components/impulse.h" #include "components/reactor.h" #include "components/beamweapon.h" +#include "components/hull.h" #include "scriptInterface.h" @@ -456,10 +457,6 @@ void SpaceShip::drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, floa void SpaceShip::drawOnGMRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) { - if (!long_range) - { - renderer.fillRect(sp::Rect(position.x - 30, position.y - 30, 60 * hull_strength / hull_max, 5), glm::u8vec4(128, 255, 128, 128)); - } } void SpaceShip::update(float delta) @@ -848,12 +845,13 @@ void SpaceShip::didAnOffensiveAction() void SpaceShip::takeHullDamage(float damage_amount, DamageInfo& info) { - if (gameGlobalInfo->use_system_damage) + auto hull = entity.getComponent(); + if (gameGlobalInfo->use_system_damage && hull) { if (info.system_target != SYS_None) { //Target specific system - float system_damage = (damage_amount / hull_max) * 2.0f; + float system_damage = (damage_amount / hull->max) * 2.0f; if (info.type == DT_Energy) system_damage *= 3.0f; //Beam weapons do more system damage, as they penetrate the hull easier. systems[info.system_target].health -= system_damage; @@ -864,7 +862,7 @@ void SpaceShip::takeHullDamage(float damage_amount, DamageInfo& info) { ESystem random_system = ESystem(irandom(0, SYS_COUNT - 1)); //Damage the system compared to the amount of hull damage you would do. If we have less hull strength you get more system damage. - float system_damage = (damage_amount / hull_max) * 1.0f; + float system_damage = (damage_amount / hull->max) * 1.0f; systems[random_system].health -= system_damage; if (systems[random_system].health < -1.0f) systems[random_system].health = -1.0f; @@ -877,7 +875,7 @@ void SpaceShip::takeHullDamage(float damage_amount, DamageInfo& info) }else{ ESystem random_system = ESystem(irandom(0, SYS_COUNT - 1)); //Damage the system compared to the amount of hull damage you would do. If we have less hull strength you get more system damage. - float system_damage = (damage_amount / hull_max) * 3.0f; + float system_damage = (damage_amount / hull->max) * 3.0f; if (info.type == DT_Energy) system_damage *= 2.5f; //Beam weapons do more system damage, as they penetrate the hull easier. systems[random_system].health -= system_damage; @@ -898,7 +896,10 @@ void SpaceShip::destroyedByDamage(DamageInfo& info) if (info.instigator) { - float points = hull_max * 0.1f; + float points = 0.0f; + auto hull = entity.getComponent(); + if (hull) + points += hull->max * 0.1f; for(int n=0; ngetName()) ret += ":setTypeName(\"" + getTypeName() + "\")"; - if (hull_max != ship_template->hull) - ret += ":setHullMax(" + string(hull_max, 0) + ")"; - if (hull_strength != ship_template->hull) - ret += ":setHull(" + string(hull_strength, 0) + ")"; + //if (hull_max != ship_template->hull) + // ret += ":setHullMax(" + string(hull_max, 0) + ")"; + //if (hull_strength != ship_template->hull) + // ret += ":setHull(" + string(hull_strength, 0) + ")"; //if (impulse_max_speed != ship_template->impulse_speed) // ret += ":setImpulseMaxSpeed(" + string(impulse_max_speed, 1) + ")"; //if (impulse_max_reverse_speed != ship_template->impulse_reverse_speed) diff --git a/src/spaceObjects/spaceship.h b/src/spaceObjects/spaceship.h index a30a6c272e..e6dec265c5 100644 --- a/src/spaceObjects/spaceship.h +++ b/src/spaceObjects/spaceship.h @@ -7,7 +7,6 @@ #include "shipTemplateBasedObject.h" #include "spaceStation.h" -#include "spaceshipParts/beamWeapon.h" #include "spaceshipParts/weaponTube.h" #include "tween.h" #include "components/docking.h" diff --git a/src/systems/docking.cpp b/src/systems/docking.cpp index 278a0c5352..93b257231f 100644 --- a/src/systems/docking.cpp +++ b/src/systems/docking.cpp @@ -3,6 +3,7 @@ #include "components/collision.h" #include "components/impulse.h" #include "components/reactor.h" +#include "components/hull.h" #include "spaceObjects/spaceship.h" #include "spaceObjects/playerSpaceship.h" #include "spaceObjects/cpuShip.h" @@ -56,11 +57,12 @@ void DockingSystem::update(float delta) auto bay = docking_port.target.getComponent(); if (bay && (bay->flags & DockingBay::Repair)) //Check if what we are docked to allows hull repairs, and if so, do it. { - if (ship->hull_strength < ship->hull_max) + auto hull = entity.getComponent(); + if (hull && hull->current < hull->max) { - ship->hull_strength += delta; - if (ship->hull_strength > ship->hull_max) - ship->hull_strength = ship->hull_max; + hull->current += delta; + if (hull->current > hull->max) + hull->current = hull->max; } } diff --git a/src/threatLevelEstimate.cpp b/src/threatLevelEstimate.cpp index df389e6052..6d25691dcd 100644 --- a/src/threatLevelEstimate.cpp +++ b/src/threatLevelEstimate.cpp @@ -3,6 +3,7 @@ #include "spaceObjects/spaceship.h" #include "spaceObjects/beamEffect.h" #include "spaceObjects/missiles/missileWeapon.h" +#include "components/hull.h" #include "systems/collision.h" @@ -53,7 +54,9 @@ float ThreatLevelEstimate::getThreatFor(P ship) for(int n=0; nshield_count; n++) threat += ship->shield_max[n] - ship->shield_level[n]; - threat += ship->hull_max - ship->hull_strength; + auto hull = ship->entity.getComponent(); + if (hull) + threat += hull->max - hull->current; float radius = 7000.0; @@ -74,7 +77,10 @@ float ThreatLevelEstimate::getThreatFor(P ship) } bool is_being_attacked = false; - float score = 200.0f + other_ship->hull_max; + hull = entity.getComponent(); + float score = 200.0f; + if (hull) + score += hull->max; for(int n=0; nshield_count; n++) { score += other_ship->shield_max[n] * 2.0f / float(other_ship->shield_count); From 26b19a3593e703248f08f551e92a86d4e8e40ea0 Mon Sep 17 00:00:00 2001 From: Daid Date: Fri, 25 Nov 2022 18:39:05 +0100 Subject: [PATCH 017/320] Warp and jump to ECS components, this is finally starting to take shape --- CMakeLists.txt | 6 + src/ai/ai.cpp | 44 +++-- src/components/jumpdrive.h | 21 +++ src/components/warpdrive.h | 21 +++ src/gameStateLogger.cpp | 22 +-- src/hardware/hardwareController.cpp | 4 +- src/main.cpp | 2 + src/screenComponents/dockingButton.cpp | 3 +- src/screenComponents/indicatorOverlays.cpp | 12 +- src/screenComponents/jumpControls.cpp | 20 +- src/screenComponents/jumpIndicator.cpp | 12 +- src/screenComponents/missileTubeControls.cpp | 4 +- src/screenComponents/warpControls.cpp | 27 ++- src/screens/crew1/singlePilotScreen.cpp | 6 +- src/screens/crew4/tacticalScreen.cpp | 6 +- src/screens/crew6/helmsScreen.cpp | 6 +- src/screens/gm/tweak.cpp | 12 +- src/spaceObjects/playerSpaceship.cpp | 50 +++-- src/spaceObjects/playerSpaceship.h | 7 +- src/spaceObjects/spaceship.cpp | 178 +++++------------- src/spaceObjects/spaceship.h | 96 +--------- .../spaceshipParts/weaponTube.cpp | 4 +- src/systems/beamweapon.cpp | 4 +- src/systems/docking.cpp | 83 +++++++- src/systems/docking.h | 5 + src/systems/impulse.cpp | 119 ++---------- src/systems/jumpsystem.cpp | 93 +++++++++ src/systems/jumpsystem.h | 13 ++ src/systems/warpsystem.cpp | 66 +++++++ src/systems/warpsystem.h | 10 + 30 files changed, 528 insertions(+), 428 deletions(-) create mode 100644 src/components/jumpdrive.h create mode 100644 src/components/warpdrive.h create mode 100644 src/systems/jumpsystem.cpp create mode 100644 src/systems/jumpsystem.h create mode 100644 src/systems/warpsystem.cpp create mode 100644 src/systems/warpsystem.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e5222d94e..8fc62f586a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -359,6 +359,8 @@ set(MAIN_SOURCES src/components/shipsystem.h src/components/shipsystem.cpp src/components/impulse.h + src/components/warpdrive.h + src/components/jumpdrive.h src/components/reactor.h src/systems/docking.h src/systems/docking.cpp @@ -366,6 +368,10 @@ set(MAIN_SOURCES src/systems/impulse.cpp src/systems/beamweapon.h src/systems/beamweapon.cpp + src/systems/warpsystem.h + src/systems/warpsystem.cpp + src/systems/jumpsystem.h + src/systems/jumpsystem.cpp src/ai/fighterAI.cpp src/ai/ai.cpp src/ai/aiFactory.cpp diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp index a9b902ee64..686e87d9f9 100644 --- a/src/ai/ai.cpp +++ b/src/ai/ai.cpp @@ -6,9 +6,13 @@ #include "random.h" #include "components/docking.h" #include "components/impulse.h" +#include "components/warpdrive.h" +#include "components/jumpdrive.h" #include "components/hull.h" #include "components/beamweapon.h" #include "systems/collision.h" +#include "systems/jumpsystem.h" +#include "systems/docking.h" #include "ecs/query.h" @@ -58,10 +62,12 @@ void ShipAI::drawOnGMRadar(sp::RenderTarget& renderer, glm::vec2 draw_position, void ShipAI::run(float delta) { owner->target_rotation = owner->getRotation(); - owner->warp_request = 0.0; auto impulse = owner->entity.getComponent(); if (impulse) impulse->request = 0.0f; + auto warp = owner->entity.getComponent(); + if (warp) + warp->request = 0; updateWeaponState(delta); if (update_target_delay > 0.0f) @@ -494,7 +500,7 @@ void ShipAI::runOrders() float dist = glm::length(diff); if (dist < 600 + owner->getOrderTarget()->getRadius()) { - owner->requestDock(owner->getOrderTarget()); + DockingSystem::requestDock(owner->entity, owner->getOrderTarget()->entity); }else{ target_position += (diff / dist) * 500.0f; flyTowards(target_position); @@ -565,7 +571,7 @@ void ShipAI::flyTowards(glm::vec2 target, float keep_distance) { auto docking_port = owner->entity.getComponent(); if (docking_port && docking_port->state == DockingPort::State::Docked) - owner->requestUndock(); + DockingSystem::requestUndock(owner->entity); auto diff = pathPlanner.route[0] - owner->getPosition(); float distance = glm::length(diff); @@ -574,33 +580,35 @@ void ShipAI::flyTowards(glm::vec2 target, float keep_distance) owner->target_rotation = vec2ToAngle(diff); float rotation_diff = fabs(angleDifference(owner->target_rotation, owner->getRotation())); - if (owner->has_warp_drive && rotation_diff < 30.0f && distance > 2000.0f) + auto warp = owner->entity.getComponent(); + if (warp && rotation_diff < 30.0f && distance > 2000.0f) { - owner->warp_request = 1.0; + warp->request = 1.0; }else{ - owner->warp_request = 0.0; + warp->request = 0.0; } - if (distance > 10000 && owner->has_jump_drive && owner->jump_delay <= 0.0f && owner->jump_drive_charge >= owner->jump_drive_max_distance) + auto jump = owner->entity.getComponent(); + if (distance > 10000 && jump && jump->delay <= 0.0f && jump->charge >= jump->max_distance) { if (rotation_diff < 1.0f) { - float jump = distance; + float jump_distance = distance; if (pathPlanner.route.size() < 2) { - jump -= 3000; + jump_distance -= 3000; if (has_missiles) - jump -= 5000; + jump_distance -= 5000; } - if (owner->jump_drive_max_distance == 50000) + if (jump->max_distance == 50000) { //If the ship has the default max jump drive distance of 50k, then limit our jumps to 15k, else we limit ourselves to whatever the ship layout is with a bit margin. - if (jump > 15000) - jump = 15000; + if (jump_distance > 15000) + jump_distance = 15000; }else{ - if (jump > owner->jump_drive_max_distance - 2000) - jump = owner->jump_drive_max_distance - 2000; + if (jump_distance > jump->max_distance - 2000) + jump_distance = jump->max_distance - 2000; } - jump += random(-1500, 1500); - owner->initializeJump(jump); + jump_distance += random(-1500, 1500); + JumpSystem::initializeJump(owner->entity, jump_distance); } } if (pathPlanner.route.size() > 1) @@ -632,7 +640,7 @@ void ShipAI::flyFormation(P target, glm::vec2 offset) { auto docking_port = owner->entity.getComponent(); if (docking_port && docking_port->state == DockingPort::State::Docked) - owner->requestUndock(); + DockingSystem::requestUndock(owner->entity); auto diff = target_position - owner->getPosition(); float distance = glm::length(diff); diff --git a/src/components/jumpdrive.h b/src/components/jumpdrive.h new file mode 100644 index 0000000000..e1093135a3 --- /dev/null +++ b/src/components/jumpdrive.h @@ -0,0 +1,21 @@ +#pragma once + +#include "stringImproved.h" +#include "shipsystem.h" + +// Impulse engine component, indicate that this entity can move under impulse control. +class JumpDrive : public ShipSystem { +public: + constexpr static float charge_time = 90.0f; /* obj) void GameStateLogger::writeShipEntry(JSONGenerator& json, P ship) { - bool has_beam_weapons = false; + //bool has_beam_weapons = false; json.write("callsign", ship->getCallSign()); json.write("faction", ship->getFaction()); @@ -403,8 +403,8 @@ void GameStateLogger::writeShipEntry(JSONGenerator& json, P ship) JSONGenerator input = json.createDict("input"); input.write("rotation", ship->target_rotation); //input.write("impulse", ship->impulse_request); - if (ship->has_warp_drive) - input.write("warp", ship->warp_request); + //if (ship->has_warp_drive) + // input.write("warp", ship->warp_request); if (ship->combat_maneuver_boost_speed > 0) input.write("combat_maneuver_boost", ship->combat_maneuver_boost_request); if (ship->combat_maneuver_strafe_speed > 0) @@ -413,15 +413,15 @@ void GameStateLogger::writeShipEntry(JSONGenerator& json, P ship) { JSONGenerator output = json.createDict("output"); //output.write("impulse", ship->current_impulse); - if (ship->has_warp_drive) - output.write("warp", ship->current_warp); + //if (ship->has_warp_drive) + // output.write("warp", ship->current_warp); if (ship->combat_maneuver_boost_speed > 0 || ship->combat_maneuver_strafe_speed > 0) output.write("combat_maneuver_charge", ship->combat_maneuver_charge); if (ship->combat_maneuver_boost_speed > 0) output.write("combat_maneuver_boost", ship->combat_maneuver_boost_active); if (ship->combat_maneuver_strafe_speed > 0) output.write("combat_maneuver_strafe", ship->combat_maneuver_strafe_active); - if (ship->has_jump_drive) + /*if (ship->has_jump_drive) { JSONGenerator jump = output.createDict("jump"); if (ship->jump_delay > 0) @@ -431,7 +431,7 @@ void GameStateLogger::writeShipEntry(JSONGenerator& json, P ship) }else{ jump.write("charge", ship->jump_drive_charge); } - } + }*/ } { JSONGenerator config = json.createDict("config"); @@ -441,14 +441,14 @@ void GameStateLogger::writeShipEntry(JSONGenerator& json, P ship) //config.write("impulse_reverse_speed", ship->impulse_max_reverse_speed); //config.write("impulse_reverse_acceleration", ship->impulse_reverse_acceleration); //config.write("hull", ship->hull_max); - if (ship->has_warp_drive) - config.write("warp", ship->warp_speed_per_warp_level); + //if (ship->has_warp_drive) + // config.write("warp", ship->warp_speed_per_warp_level); if (ship->combat_maneuver_boost_speed > 0) config.write("combat_maneuver_boost", ship->combat_maneuver_boost_speed); if (ship->combat_maneuver_strafe_speed > 0) config.write("combat_maneuver_strafe", ship->combat_maneuver_strafe_speed); - if (ship->has_jump_drive) - config.write("jumpdrive", true); + //if (ship->has_jump_drive) + // config.write("jumpdrive", true); if (ship->weapon_tube_count > 0) { JSONGenerator missiles = config.createDict("missiles"); diff --git a/src/hardware/hardwareController.cpp b/src/hardware/hardwareController.cpp index 5049628346..7e572c463d 100644 --- a/src/hardware/hardwareController.cpp +++ b/src/hardware/hardwareController.cpp @@ -372,12 +372,12 @@ bool HardwareController::getVariableValue(string variable_name, float& value) //SHIP_VARIABLE("Energy", ship->energy_level * 100 / ship->max_energy_level); SHIP_VARIABLE("ShieldsUp", ship->shields_active ? 1.0f : 0.0f); //SHIP_VARIABLE("Impulse", ship->current_impulse * ship->getSystemEffectiveness(SYS_Impulse)); - SHIP_VARIABLE("Warp", ship->current_warp * ship->getSystemEffectiveness(SYS_Warp)); + //SHIP_VARIABLE("Warp", ship->current_warp * ship->getSystemEffectiveness(SYS_Warp)); //SHIP_VARIABLE("Docking", ship->docking_state == DS_Docking ? 1.0f : 0.0f); //SHIP_VARIABLE("Docked", ship->docking_state == DS_Docked ? 1.0f : 0.0f); SHIP_VARIABLE("InNebula", Nebula::inNebula(ship->getPosition()) ? 1.0f : 0.0f); SHIP_VARIABLE("IsJammed", WarpJammer::isWarpJammed(ship->getPosition()) ? 1.0f : 0.0f); - SHIP_VARIABLE("Jumping", ship->jump_delay > 0.0f ? 1.0f : 0.0f); + //SHIP_VARIABLE("Jumping", ship->jump_delay > 0.0f ? 1.0f : 0.0f); SHIP_VARIABLE("Jumped", ship->jump_indicator > 0.0f ? 1.0f : 0.0f); SHIP_VARIABLE("Alert", ship->getAlertLevel() != AL_Normal ? 1.0f : 0.0f); SHIP_VARIABLE("YellowAlert", ship->getAlertLevel() == AL_YellowAlert ? 1.0f : 0.0f); diff --git a/src/main.cpp b/src/main.cpp index 891fe2f70d..30cfb7e70a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,6 +29,7 @@ #include "spaceObjects/spaceObject.h" #include "systems/docking.h" #include "systems/impulse.h" +#include "systems/warpsystem.h" #include "systems/beamweapon.h" #include "packResourceProvider.h" #include "main.h" @@ -138,6 +139,7 @@ int main(int argc, char** argv) new Engine(); engine->registerSystem(); engine->registerSystem(); + engine->registerSystem(); engine->registerSystem(); string configuration_path = "."; if (getenv("HOME")) diff --git a/src/screenComponents/dockingButton.cpp b/src/screenComponents/dockingButton.cpp index bea30542e0..45587a8bc1 100644 --- a/src/screenComponents/dockingButton.cpp +++ b/src/screenComponents/dockingButton.cpp @@ -3,6 +3,7 @@ #include "spaceObjects/playerSpaceship.h" #include "dockingButton.h" #include "systems/collision.h" +#include "systems/docking.h" #include "components/collision.h" #include "ecs/query.h" @@ -75,7 +76,7 @@ void GuiDockingButton::onDraw(sp::RenderTarget& renderer) { case DockingPort::State::NotDocking: setText(tr("Request Dock")); - if (my_spaceship->canStartDocking() && findDockingTarget()) + if (DockingSystem::canStartDocking(my_spaceship->entity) && findDockingTarget()) { enable(); }else{ diff --git a/src/screenComponents/indicatorOverlays.cpp b/src/screenComponents/indicatorOverlays.cpp index d2357db076..72c8f9aba7 100644 --- a/src/screenComponents/indicatorOverlays.cpp +++ b/src/screenComponents/indicatorOverlays.cpp @@ -5,6 +5,8 @@ #include "main.h" #include "random.h" #include "preferenceManager.h" +#include "components/warpdrive.h" +#include "components/jumpdrive.h" #include "gui/gui2_overlay.h" #include "gui/gui2_label.h" @@ -88,14 +90,16 @@ void GuiIndicatorOverlays::onDraw(sp::RenderTarget& renderer) }else{ glitchPostProcessor->enabled = false; } - if (my_spaceship->current_warp > 0.0f && PreferencesManager::get("warp_post_processor_disable").toInt() != 1) + auto warp = my_spaceship->entity.getComponent(); + auto jump = my_spaceship->entity.getComponent(); + if (warp && warp->current > 0.0f && PreferencesManager::get("warp_post_processor_disable").toInt() != 1) { warpPostProcessor->enabled = true; - warpPostProcessor->setUniform("amount", my_spaceship->current_warp * 0.01f); - }else if (my_spaceship->jump_delay > 0.0f && my_spaceship->jump_delay < 2.0f && PreferencesManager::get("warp_post_processor_disable").toInt() != 1) + warpPostProcessor->setUniform("amount", warp->current * 0.01f); + }else if (jump && jump->delay > 0.0f && jump->delay < 2.0f && PreferencesManager::get("warp_post_processor_disable").toInt() != 1) { warpPostProcessor->enabled = true; - warpPostProcessor->setUniform("amount", (2.0f - my_spaceship->jump_delay) * 0.1f); + warpPostProcessor->setUniform("amount", (2.0f - jump->delay) * 0.1f); }else{ warpPostProcessor->enabled = false; } diff --git a/src/screenComponents/jumpControls.cpp b/src/screenComponents/jumpControls.cpp index de0327bbaa..99a5888da9 100644 --- a/src/screenComponents/jumpControls.cpp +++ b/src/screenComponents/jumpControls.cpp @@ -3,6 +3,7 @@ #include "spaceObjects/playerSpaceship.h" #include "jumpControls.h" #include "powerDamageIndicator.h" +#include "components/jumpdrive.h" #include "gui/gui2_slider.h" #include "gui/gui2_keyvaluedisplay.h" @@ -34,26 +35,33 @@ void GuiJumpControls::onDraw(sp::RenderTarget& target) { if (my_spaceship) { - if (my_spaceship->jump_delay > 0.0f) + auto jump = my_spaceship->entity.getComponent(); + if (!jump) { + label->setKey(""); + label->setValue(""); + slider->disable(); + button->disable(); + charge_bar->hide(); + } else if (jump->delay > 0.0f) { label->setKey(tr("jumpcontrol","Jump in")); - label->setValue(string(int(ceilf(my_spaceship->jump_delay)))); + label->setValue(string(int(ceilf(jump->delay)))); slider->disable(); button->disable(); charge_bar->hide(); - }else if (my_spaceship->jump_drive_charge < my_spaceship->jump_drive_max_distance) + }else if (jump->charge < jump->max_distance) { label->setKey(tr("jumpcontrol", "Charging")); label->setValue("..."); slider->hide(); button->disable(); - charge_bar->setRange(0.0, my_spaceship->jump_drive_max_distance); - charge_bar->setValue(my_spaceship->jump_drive_charge)->show(); + charge_bar->setRange(0.0, jump->max_distance); + charge_bar->setValue(jump->charge)->show(); }else{ label->setKey(tr("jumpcontrol", "Distance")); label->setValue(string(slider->getValue() / 1000.0f, 1) + DISTANCE_UNIT_1K); slider->enable()->show(); - slider->setRange(my_spaceship->jump_drive_max_distance, my_spaceship->jump_drive_min_distance); + slider->setRange(jump->max_distance, jump->min_distance); button->enable(); charge_bar->hide(); } diff --git a/src/screenComponents/jumpIndicator.cpp b/src/screenComponents/jumpIndicator.cpp index 9076862e65..c3c2a17797 100644 --- a/src/screenComponents/jumpIndicator.cpp +++ b/src/screenComponents/jumpIndicator.cpp @@ -1,6 +1,7 @@ #include "playerInfo.h" #include "spaceObjects/playerSpaceship.h" #include "jumpIndicator.h" +#include "components/jumpdrive.h" #include "gui/gui2_panel.h" #include "gui/gui2_label.h" @@ -18,10 +19,15 @@ GuiJumpIndicator::GuiJumpIndicator(GuiContainer* owner) void GuiJumpIndicator::onDraw(sp::RenderTarget& target) { - if (my_spaceship && my_spaceship->jump_delay > 0.0f) + if (my_spaceship) { - box->show(); - label->setText(tr("Jump in: {delay}").format({{"delay", string(int(ceilf(my_spaceship->jump_delay)))}})); + auto jump = my_spaceship->entity.getComponent(); + if (jump && jump->delay > 0.0f) { + box->show(); + label->setText(tr("Jump in: {delay}").format({{"delay", string(int(ceilf(jump->delay)))}})); + } else { + box->hide(); + } }else{ box->hide(); } diff --git a/src/screenComponents/missileTubeControls.cpp b/src/screenComponents/missileTubeControls.cpp index 433b51e91f..14eed67e45 100644 --- a/src/screenComponents/missileTubeControls.cpp +++ b/src/screenComponents/missileTubeControls.cpp @@ -2,6 +2,7 @@ #include "spaceObjects/playerSpaceship.h" #include "missileTubeControls.h" #include "powerDamageIndicator.h" +#include "components/warpdrive.h" #include "gui/gui2_button.h" #include "gui/gui2_progressbar.h" @@ -144,7 +145,8 @@ void GuiMissileTubeControls::onUpdate() rows[n].loading_bar->hide(); } - if (my_spaceship->current_warp > 0.0f) + auto warp = my_spaceship->entity.getComponent(); + if (warp && warp->current > 0.0f) { rows[n].fire_button->disable(); } diff --git a/src/screenComponents/warpControls.cpp b/src/screenComponents/warpControls.cpp index 65c12ca397..5df629f578 100644 --- a/src/screenComponents/warpControls.cpp +++ b/src/screenComponents/warpControls.cpp @@ -3,6 +3,7 @@ #include "playerInfo.h" #include "spaceObjects/playerSpaceship.h" #include "powerDamageIndicator.h" +#include "components/warpdrive.h" #include "gui/gui2_slider.h" #include "gui/gui2_keyvaluedisplay.h" @@ -33,8 +34,10 @@ GuiWarpControls::GuiWarpControls(GuiContainer* owner, string id) if (my_spaceship) { + auto warp = my_spaceship->entity.getComponent(); // Set the slider's value to the current warp request. - slider->setValue(my_spaceship->warp_request); + if (warp) + slider->setValue(warp->request); } // Label the warp slider. @@ -49,8 +52,11 @@ void GuiWarpControls::onDraw(sp::RenderTarget& target) { // Update the label with the current warp factor. if (my_spaceship) { - label->setValue(string(my_spaceship->current_warp, 1)); - slider->setValue(my_spaceship->warp_request); + auto warp = my_spaceship->entity.getComponent(); + if (warp) { + label->setValue(string(warp->current, 1)); + slider->setValue(warp->request); + } } } @@ -59,6 +65,9 @@ void GuiWarpControls::onUpdate() // Handle hotkey input. Warp is a HELMS-category shortcut. if (my_spaceship && isVisible()) { + auto warp = my_spaceship->entity.getComponent(); + if (!warp) + return; if (keys.helms_warp0.getDown()) { my_spaceship->commandWarp(0); @@ -86,16 +95,16 @@ void GuiWarpControls::onUpdate() } if (keys.helms_increase_warp.getDown()) { - if (my_spaceship->warp_request < 4) { - my_spaceship->commandWarp(my_spaceship->warp_request+1); - slider->setValue(my_spaceship->warp_request+1); + if (warp->request < 4) { + my_spaceship->commandWarp(warp->request+1); + slider->setValue(warp->request+1); } } else if (keys.helms_decrease_warp.getDown()) { - if (my_spaceship->warp_request > 0) { - my_spaceship->commandWarp(my_spaceship->warp_request-1); - slider->setValue(my_spaceship->warp_request-1); + if (warp->request > 0) { + my_spaceship->commandWarp(warp->request-1); + slider->setValue(warp->request-1); } } } diff --git a/src/screens/crew1/singlePilotScreen.cpp b/src/screens/crew1/singlePilotScreen.cpp index 572f8477f5..9938e5d22f 100644 --- a/src/screens/crew1/singlePilotScreen.cpp +++ b/src/screens/crew1/singlePilotScreen.cpp @@ -5,6 +5,8 @@ #include "preferenceManager.h" #include "components/reactor.h" +#include "components/warpdrive.h" +#include "components/jumpdrive.h" #include "screenComponents/viewport3d.h" @@ -124,8 +126,8 @@ void SinglePilotScreen::onDraw(sp::RenderTarget& renderer) float velocity = glm::length(my_spaceship->getVelocity()) / 1000 * 60; velocity_display->setValue(tr("{value} {unit}/min").format({{"value", string(velocity, 1)}, {"unit", DISTANCE_UNIT_1K}})); - warp_controls->setVisible(my_spaceship->has_warp_drive); - jump_controls->setVisible(my_spaceship->has_jump_drive); + warp_controls->setVisible(my_spaceship->entity.hasComponent()); + jump_controls->setVisible(my_spaceship->entity.hasComponent()); string shields_value = string(my_spaceship->getShieldPercentage(0)) + "%"; if (my_spaceship->hasSystem(SYS_RearShield)) diff --git a/src/screens/crew4/tacticalScreen.cpp b/src/screens/crew4/tacticalScreen.cpp index be81c69c49..7af0f24185 100644 --- a/src/screens/crew4/tacticalScreen.cpp +++ b/src/screens/crew4/tacticalScreen.cpp @@ -5,6 +5,8 @@ #include "preferenceManager.h" #include "components/reactor.h" +#include "components/warpdrive.h" +#include "components/jumpdrive.h" #include "screenComponents/combatManeuver.h" #include "screenComponents/radarView.h" @@ -125,8 +127,8 @@ void TacticalScreen::onDraw(sp::RenderTarget& renderer) float velocity = glm::length(my_spaceship->getVelocity()) / 1000 * 60; velocity_display->setValue(tr("{value} {unit}/min").format({{"value", string(velocity, 1)}, {"unit", DISTANCE_UNIT_1K}})); - warp_controls->setVisible(my_spaceship->has_warp_drive); - jump_controls->setVisible(my_spaceship->has_jump_drive); + warp_controls->setVisible(my_spaceship->entity.hasComponent()); + jump_controls->setVisible(my_spaceship->entity.hasComponent()); string shields_value = string(my_spaceship->getShieldPercentage(0)) + "%"; if (my_spaceship->hasSystem(SYS_RearShield)) diff --git a/src/screens/crew6/helmsScreen.cpp b/src/screens/crew6/helmsScreen.cpp index 93865e8fdc..fc88c485cd 100644 --- a/src/screens/crew6/helmsScreen.cpp +++ b/src/screens/crew6/helmsScreen.cpp @@ -5,6 +5,8 @@ #include "preferenceManager.h" #include "components/reactor.h" +#include "components/warpdrive.h" +#include "components/jumpdrive.h" #include "screenComponents/combatManeuver.h" #include "screenComponents/radarView.h" @@ -103,8 +105,8 @@ void HelmsScreen::onDraw(sp::RenderTarget& renderer) float velocity = glm::length(my_spaceship->getVelocity()) / 1000 * 60; velocity_display->setValue(tr("{value} {unit}/min").format({{"value", string(velocity, 1)}, {"unit", DISTANCE_UNIT_1K}})); - warp_controls->setVisible(my_spaceship->has_warp_drive); - jump_controls->setVisible(my_spaceship->has_jump_drive); + warp_controls->setVisible(my_spaceship->entity.hasComponent()); + jump_controls->setVisible(my_spaceship->entity.hasComponent()); } GuiOverlay::onDraw(renderer); } diff --git a/src/screens/gm/tweak.cpp b/src/screens/gm/tweak.cpp index eaa70a5782..95dd46ae8e 100644 --- a/src/screens/gm/tweak.cpp +++ b/src/screens/gm/tweak.cpp @@ -152,13 +152,13 @@ GuiTweakShip::GuiTweakShip(GuiContainer* owner) (new GuiLabel(left_col, "", tr("Jump Min Distance:"), 30))->setSize(GuiElement::GuiSizeMax, 50); jump_min_distance_slider= new GuiSlider(left_col, "", 0.0, 100000, 0.0, [this](float value) { - target->setJumpDriveRange(value,target->jump_drive_max_distance); + //target->setJumpDriveRange(value,target->jump_drive_max_distance); }); jump_min_distance_slider->addOverlay()->setSize(GuiElement::GuiSizeMax, 40); (new GuiLabel(left_col, "", tr("Jump Max Distance:"), 30))->setSize(GuiElement::GuiSizeMax, 50); jump_max_distance_slider= new GuiSlider(left_col, "", 0.0, 100000, 0.0, [this](float value) { - target->setJumpDriveRange(target->jump_drive_min_distance,value); + //target->setJumpDriveRange(target->jump_drive_min_distance,value); }); jump_max_distance_slider->addOverlay()->setSize(GuiElement::GuiSizeMax, 40); @@ -219,11 +219,11 @@ void GuiTweakShip::onDraw(sp::RenderTarget& renderer) { //TODO: hull_slider->setValue(target->hull_strength); jump_charge_slider->setValue(target->getJumpDriveCharge()); - jump_min_distance_slider->setValue(target->jump_drive_min_distance); - jump_max_distance_slider->setValue(target->jump_drive_max_distance); + //jump_min_distance_slider->setValue(target->jump_drive_min_distance); + //jump_max_distance_slider->setValue(target->jump_drive_max_distance); type_name->setText(target->getTypeName()); - warp_toggle->setValue(target->has_warp_drive); - jump_toggle->setValue(target->hasJumpDrive());\ + //warp_toggle->setValue(target->has_warp_drive); + jump_toggle->setValue(target->hasJumpDrive()); //TODO: impulse_speed_slider->setValue(target->impulse_max_speed); //TODO: impulse_reverse_speed_slider->setValue(target->impulse_max_reverse_speed); turn_speed_slider->setValue(target->turn_speed); diff --git a/src/spaceObjects/playerSpaceship.cpp b/src/spaceObjects/playerSpaceship.cpp index a7161ffb08..c48041c3ef 100644 --- a/src/spaceObjects/playerSpaceship.cpp +++ b/src/spaceObjects/playerSpaceship.cpp @@ -12,6 +12,10 @@ #include "components/reactor.h" #include "components/beamweapon.h" +#include "components/warpdrive.h" +#include "components/jumpdrive.h" +#include "systems/jumpsystem.h" +#include "systems/docking.h" #include "scriptInterface.h" @@ -357,7 +361,6 @@ PlayerSpaceship::PlayerSpaceship() registerMemberReplication(&can_launch_probe); registerMemberReplication(&hull_damage_indicator, 0.5); registerMemberReplication(&jump_indicator, 0.5); - registerMemberReplication(&energy_warp_per_second, .5f); registerMemberReplication(&energy_shield_use_per_second, .5f); registerMemberReplication(&main_screen_setting); registerMemberReplication(&main_screen_overlay); @@ -609,16 +612,6 @@ void PlayerSpaceship::update(float delta) shields_active = false; } - // If a ship is jumping or warping, consume additional energy. - if (has_warp_drive && warp_request > 0 && !(has_jump_drive && jump_delay > 0)) - { - // If warping, consume energy at a rate of 120% the warp request. - // If shields are up, that rate is increased by an additional 50%. - if (!useEnergy(getEnergyWarpPerSecond() * delta * getSystemEffectiveness(SYS_Warp) * powf(current_warp, 1.3f) * (shields_active ? 1.7f : 1.0f))) - // If there's not enough energy, fall out of warp. - warp_request = 0; - } - if (scanning_target) { // If the scan setting or a target's scan complexity is none/0, @@ -720,13 +713,6 @@ void PlayerSpaceship::applyTemplateValues() } } -void PlayerSpaceship::executeJump(float distance) -{ - // When jumping, reset the jump effect and move the ship. - jump_indicator = 2.0; - SpaceShip::executeJump(distance); -} - void PlayerSpaceship::takeHullDamage(float damage_amount, DamageInfo& info) { // If taking non-EMP damage, light up the hull damage overlay. @@ -1171,14 +1157,20 @@ void PlayerSpaceship::onReceiveClientCommand(int32_t client_id, sp::io::DataBuff packet >> f; } } break; - case CMD_WARP: - packet >> warp_request; - break; + case CMD_WARP:{ + auto warp = entity.getComponent(); + if (warp) + packet >> warp->request; + else { + uint8_t i; + packet >> i; + } + } break; case CMD_JUMP: { float distance; packet >> distance; - initializeJump(distance); + JumpSystem::initializeJump(my_spaceship->entity, distance); } break; case CMD_SET_TARGET: @@ -1293,14 +1285,16 @@ void PlayerSpaceship::onReceiveClientCommand(int32_t client_id, sp::io::DataBuff { int32_t id; packet >> id; - requestDock(game_server->getObjectById(id)); + P obj = game_server->getObjectById(id); + if (obj) + DockingSystem::requestDock(entity, obj->entity); } break; case CMD_UNDOCK: - requestUndock(); + DockingSystem::requestUndock(entity); break; case CMD_ABORT_DOCK: - abortDock(); + DockingSystem::abortDock(entity); break; case CMD_OPEN_TEXT_COMM: if (comms_state == CS_Inactive || comms_state == CS_BeingHailed || comms_state == CS_BeingHailedByGM || comms_state == CS_ChannelClosed) @@ -2074,10 +2068,8 @@ string PlayerSpaceship::getExportLine() result += ":setEnergyShieldUsePerSecond(" + string(getEnergyShieldUsePerSecond(), 2) + ")"; } - if (std::fabs(getEnergyWarpPerSecond() - default_energy_warp_per_second) > std::numeric_limits::epsilon()) - { - result += ":setEnergyWarpPerSecond(" + string(getEnergyWarpPerSecond(), 2) + ")"; - } + //if (std::fabs(getEnergyWarpPerSecond() - default_energy_warp_per_second) > std::numeric_limits::epsilon()) + // result += ":setEnergyWarpPerSecond(" + string(getEnergyWarpPerSecond(), 2) + ")"; return result; } diff --git a/src/spaceObjects/playerSpaceship.h b/src/spaceObjects/playerSpaceship.h index 6f891484c5..18d6e28a6f 100644 --- a/src/spaceObjects/playerSpaceship.h +++ b/src/spaceObjects/playerSpaceship.h @@ -36,7 +36,6 @@ class PlayerSpaceship : public SpaceShip public: // Power consumption and generation base rates constexpr static float default_energy_shield_use_per_second = 1.5f; - constexpr static float default_energy_warp_per_second = 1.7f; // Total coolant constexpr static float max_coolant_per_system = 10.0f; float max_coolant; @@ -113,7 +112,6 @@ class PlayerSpaceship : public SpaceShip // Ship's log container std::vector ships_log; float energy_shield_use_per_second = default_energy_shield_use_per_second; - float energy_warp_per_second = default_energy_warp_per_second; public: std::vector custom_functions; @@ -290,7 +288,6 @@ class PlayerSpaceship : public SpaceShip virtual void applyTemplateValues() override; // Ship status functions - virtual void executeJump(float distance) override; virtual void takeHullDamage(float damage_amount, DamageInfo& info) override; void setSystemCoolantRequest(ESystem system, float request); void setMaxCoolant(float coolant); @@ -303,8 +300,8 @@ class PlayerSpaceship : public SpaceShip // Flow rate controls. float getEnergyShieldUsePerSecond() const { return energy_shield_use_per_second; } void setEnergyShieldUsePerSecond(float rate) { energy_shield_use_per_second = rate; } - float getEnergyWarpPerSecond() const { return energy_warp_per_second; } - void setEnergyWarpPerSecond(float rate) { energy_warp_per_second = rate; } + float getEnergyWarpPerSecond() const { return 0.0f; } //TODO + void setEnergyWarpPerSecond(float rate) {} //TODO // Ship update functions virtual void update(float delta) override; diff --git a/src/spaceObjects/spaceship.cpp b/src/spaceObjects/spaceship.cpp index 64e76ea1ff..89eae7134d 100644 --- a/src/spaceObjects/spaceship.cpp +++ b/src/spaceObjects/spaceship.cpp @@ -19,6 +19,8 @@ #include "components/collision.h" #include "components/docking.h" #include "components/impulse.h" +#include "components/warpdrive.h" +#include "components/jumpdrive.h" #include "components/reactor.h" #include "components/beamweapon.h" #include "components/hull.h" @@ -181,16 +183,6 @@ SpaceShip::SpaceShip(string multiplayerClassName, float multiplayer_significant_ : ShipTemplateBasedObject(50, multiplayerClassName, multiplayer_significant_range) { target_rotation = getRotation(); - has_warp_drive = true; - warp_request = 0; - current_warp = 0; - warp_speed_per_warp_level = 1000.f; - has_jump_drive = true; - jump_drive_min_distance = 5000.f; - jump_drive_max_distance = 50000.f; - jump_drive_charge = jump_drive_max_distance; - jump_distance = 0.f; - jump_delay = 0.f; wormhole_alpha = 0.f; weapon_tube_count = 0; turn_speed = 10.f; @@ -207,19 +199,10 @@ SpaceShip::SpaceShip(string multiplayerClassName, float multiplayer_significant_ registerMemberReplication(&target_rotation, 1.5f); registerMemberReplication(&turnSpeed, 0.1f); - registerMemberReplication(&has_warp_drive); - registerMemberReplication(&warp_request, 0.1f); - registerMemberReplication(¤t_warp, 0.1f); - registerMemberReplication(&has_jump_drive); - registerMemberReplication(&jump_drive_charge, 0.5f); - registerMemberReplication(&jump_delay, 0.5f); - registerMemberReplication(&jump_drive_min_distance); - registerMemberReplication(&jump_drive_max_distance); registerMemberReplication(&wormhole_alpha, 0.5f); registerMemberReplication(&weapon_tube_count); registerMemberReplication(&target_id); registerMemberReplication(&turn_speed); - registerMemberReplication(&warp_speed_per_warp_level); registerMemberReplication(&shield_frequency); registerMemberReplication(&combat_maneuver_charge, 0.5f); registerMemberReplication(&combat_maneuver_boost_request); @@ -326,11 +309,16 @@ void SpaceShip::applyTemplateValues() turn_speed = ship_template->turn_speed; combat_maneuver_boost_speed = ship_template->combat_maneuver_boost_speed; combat_maneuver_strafe_speed = ship_template->combat_maneuver_strafe_speed; - has_warp_drive = ship_template->warp_speed > 0.0f; - warp_speed_per_warp_level = ship_template->warp_speed; - has_jump_drive = ship_template->has_jump_drive; - jump_drive_min_distance = ship_template->jump_drive_min_distance; - jump_drive_max_distance = ship_template->jump_drive_max_distance; + + if (ship_template->warp_speed > 0.0f) { + auto& warp = entity.getOrAddComponent(); + warp.speed_per_level = ship_template->warp_speed; + } + if (ship_template->has_jump_drive) { + auto& jump = entity.getOrAddComponent(); + jump.min_distance = ship_template->jump_drive_min_distance; + jump.max_distance = ship_template->jump_drive_max_distance; + } for(int n=0; nweapon_tube[n].load_time); @@ -357,10 +345,11 @@ void SpaceShip::draw3DTransparent() if (!ship_template) return; ShipTemplateBasedObject::draw3DTransparent(); - if ((has_jump_drive && jump_delay > 0.0f) || + auto jump = entity.getComponent(); + if ((jump && jump->delay > 0.0f) || (wormhole_alpha > 0.0f)) { - float delay = jump_delay; + float delay = jump ? jump->delay : 0.0f; if (wormhole_alpha > 0.0f) delay = wormhole_alpha; float alpha = 1.0f - (delay / 10.0f); @@ -389,19 +378,14 @@ void SpaceShip::updateDynamicRadarSignature() ) ); - // ... adjust the electrical band if system power allocation is not - // 100%. - if (ship_system == SYS_JumpDrive && jump_drive_charge < jump_drive_max_distance) + // ... adjust the electrical band if system power allocation is not 100%. + if (ship_system == SYS_JumpDrive) { - // ... elevate electrical after a jump, since recharging jump - // consumes energy. - signature_delta.electrical += std::max( - 0.0f, - std::min( - 1.0f, - getSystemPower(ship_system) * (jump_drive_charge + 0.01f / jump_drive_max_distance) - ) - ); + auto jump = entity.getComponent(); + if (jump && jump->charge < jump->max_distance) { + // ... elevate electrical after a jump, since recharging jump consumes energy. + signature_delta.electrical += std::clamp(getSystemPower(ship_system) * (jump->charge + 0.01f / jump->max_distance), 0.0f, 1.0f); + } } else if (getSystemPower(ship_system) != 1.0f) { // For non-Jump systems, allow underpowered systems to reduce the @@ -418,18 +402,15 @@ void SpaceShip::updateDynamicRadarSignature() // Increase the gravitational band if the ship is about to jump, or is // actively warping. - if (jump_delay > 0.0f) + auto jump = entity.getComponent(); + if (jump && jump->delay > 0.0f) { - signature_delta.gravity += std::max( - 0.0f, - std::min( - (1.0f / jump_delay + 0.01f) + 0.25f, - 10.0f - ) - ); - } else if (current_warp > 0.0f) + signature_delta.gravity += std::clamp((1.0f / jump->delay + 0.01f) + 0.25f, 0.0f, 1.0f); + } + auto warp = entity.getComponent(); + if (warp && warp->current > 0.0f) { - signature_delta.gravity += current_warp; + signature_delta.gravity += warp->current; } // Update the signature by adding the delta to its baseline. @@ -553,8 +534,10 @@ void SpaceShip::update(float delta) if (impulse) model_info.engine_scale = std::max(model_info.engine_scale, std::abs(impulse->actual)); model_info.engine_scale = std::min(1.0f, model_info.engine_scale); - if (has_jump_drive && jump_delay > 0.0f) - model_info.warp_scale = (10.0f - jump_delay) / 10.0f; + + auto jump = entity.getComponent(); + if (jump && jump->delay > 0.0f) + model_info.warp_scale = (10.0f - jump->delay) / 10.0f; else model_info.warp_scale = 0.f; @@ -582,79 +565,10 @@ P SpaceShip::getTarget() return game_client->getObjectById(target_id); } -void SpaceShip::executeJump(float distance) -{ - float f = systems[SYS_JumpDrive].health; - if (f <= 0.0f) - return; - - distance = (distance * f) + (distance * (1.0f - f) * random(0.5, 1.5)); - auto target_position = getPosition() + vec2FromAngle(getRotation()) * distance; - target_position = WarpJammer::getFirstNoneJammedPosition(getPosition(), target_position); - setPosition(target_position); - addHeat(SYS_JumpDrive, jump_drive_heat_per_jump); -} - void SpaceShip::collide(SpaceObject* other, float force) { } -void SpaceShip::initializeJump(float distance) -{ - auto docking_port = entity.getComponent(); - if (docking_port && docking_port->state != DockingPort::State::NotDocking) return; - if (jump_drive_charge < jump_drive_max_distance) // You can only jump when the drive is fully charged - return; - if (jump_delay <= 0.0f) - { - jump_distance = distance; - jump_delay = 10.f; - jump_drive_charge -= distance; - } -} - -void SpaceShip::requestDock(P target) -{ - auto docking_port = entity.getComponent(); - if (!docking_port || docking_port->state != DockingPort::State::NotDocking) return; - if (!target) - return; - auto bay = target->entity.getComponent(); - if (!bay || docking_port->canDockOn(*bay) == DockingStyle::None) return; - - if (glm::length(getPosition() - target->getPosition()) > 1000 + target->getRadius()) - return; - if (!canStartDocking()) - return; - - docking_port->state = DockingPort::State::Docking; - docking_port->target = target->entity; - warp_request = 0; -} - -void SpaceShip::requestUndock() -{ - auto docking_port = entity.getComponent(); - if (!docking_port || docking_port->state != DockingPort::State::Docked) return; - if (getSystemEffectiveness(SYS_Impulse) < 0.1f) return; - - docking_port->state = DockingPort::State::NotDocking; - auto engine = entity.getComponent(); - if (engine) engine->request = 0.5; -} - -void SpaceShip::abortDock() -{ - auto docking_port = entity.getComponent(); - if (!docking_port || docking_port->state != DockingPort::State::Docking) return; - - docking_port->state = DockingPort::State::NotDocking; - auto engine = entity.getComponent(); - if (engine) engine->request = 0.f; - warp_request = 0; - target_rotation = getRotation(); -} - bool SpaceShip::useEnergy(float amount) { // Try to consume an amount of energy. If it works, return true. @@ -917,9 +831,9 @@ bool SpaceShip::hasSystem(ESystem system) case SYS_COUNT: return false; case SYS_Warp: - return has_warp_drive; + return entity.hasComponent(); case SYS_JumpDrive: - return has_jump_drive; + return entity.hasComponent(); case SYS_MissileSystem: return weapon_tube_count > 0; case SYS_FrontShield: @@ -927,9 +841,9 @@ bool SpaceShip::hasSystem(ESystem system) case SYS_RearShield: return shield_count > 1; case SYS_Reactor: - return true; + return entity.hasComponent(); case SYS_BeamWeapons: - return true; + return entity.hasComponent(); case SYS_Maneuver: return turn_speed > 0.0f; case SYS_Impulse: @@ -1198,15 +1112,15 @@ string SpaceShip::getScriptExportModificationsOnTemplate() // ret += ":setImpulseMaxReverseSpeed(" + string(impulse_max_reverse_speed, 1) + ")"; if (turn_speed != ship_template->turn_speed) ret += ":setRotationMaxSpeed(" + string(turn_speed, 1) + ")"; - if (has_jump_drive != ship_template->has_jump_drive) - ret += ":setJumpDrive(" + string(has_jump_drive ? "true" : "false") + ")"; - if (jump_drive_min_distance != ship_template->jump_drive_min_distance - || jump_drive_max_distance != ship_template->jump_drive_max_distance) - ret += ":setJumpDriveRange(" + string(jump_drive_min_distance) + ", " + string(jump_drive_max_distance) + ")"; - if (has_warp_drive != (ship_template->warp_speed > 0)) - ret += ":setWarpDrive(" + string(has_warp_drive ? "true" : "false") + ")"; - if (warp_speed_per_warp_level != ship_template->warp_speed) - ret += ":setWarpSpeed(" + string(warp_speed_per_warp_level) + ")"; + //if (has_jump_drive != ship_template->has_jump_drive) + // ret += ":setJumpDrive(" + string(has_jump_drive ? "true" : "false") + ")"; + //if (jump_drive_min_distance != ship_template->jump_drive_min_distance + // || jump_drive_max_distance != ship_template->jump_drive_max_distance) + // ret += ":setJumpDriveRange(" + string(jump_drive_min_distance) + ", " + string(jump_drive_max_distance) + ")"; + //if (has_warp_drive != (ship_template->warp_speed > 0)) + // ret += ":setWarpDrive(" + string(has_warp_drive ? "true" : "false") + ")"; + //if (warp_speed_per_warp_level != ship_template->warp_speed) + // ret += ":setWarpSpeed(" + string(warp_speed_per_warp_level) + ")"; // Shield data // Determine whether to export shield data. diff --git a/src/spaceObjects/spaceship.h b/src/spaceObjects/spaceship.h index e6dec265c5..e22611f89d 100644 --- a/src/spaceObjects/spaceship.h +++ b/src/spaceObjects/spaceship.h @@ -77,14 +77,8 @@ class SpaceShip : public ShipTemplateBasedObject constexpr static float combat_maneuver_charge_time = 20.0f; /*< Amount of time it takes to fully charge the combat maneuver system */ constexpr static float combat_maneuver_boost_max_time = 3.0f; /*< Amount of time we can boost with a fully charged combat maneuver system */ constexpr static float combat_maneuver_strafe_max_time = 3.0f; /*< Amount of time we can strafe with a fully charged combat maneuver system */ - constexpr static float warp_charge_time = 4.0f; - constexpr static float warp_decharge_time = 2.0f; - constexpr static float jump_drive_charge_time = 90.0f; /* target); - - /*! - * Request undock with current docked object - */ - void requestUndock(); - - /*! - * Abort the current dock request - */ - void abortDock(); - /// Function to use energy. Only player ships currently model energy use. bool useEnergy(float amount); @@ -283,7 +225,6 @@ class SpaceShip : public ShipTemplateBasedObject bool isDocked(P target); P getDockedWith(); DockingPort::State getDockingState(); - bool canStartDocking() { return current_warp <= 0.0f && (!has_jump_drive || jump_delay <= 0.0f); } int getWeaponStorage(EMissileWeapons weapon) { if (weapon == MW_None) return 0; return weapon_storage[weapon]; } int getWeaponStorageMax(EMissileWeapons weapon) { if (weapon == MW_None) return 0; return weapon_storage_max[weapon]; } void setWeaponStorage(EMissileWeapons weapon, int amount) { if (weapon == MW_None) return; weapon_storage[weapon] = amount; } @@ -321,33 +262,16 @@ class SpaceShip : public ShipTemplateBasedObject Speeds getAcceleration(); void setAcceleration(float acceleration, std::optional reverse_acceleration); void setCombatManeuver(float boost, float strafe) { combat_maneuver_boost_speed = boost; combat_maneuver_strafe_speed = strafe; } - bool hasJumpDrive() { return has_jump_drive; } - void setJumpDrive(bool has_jump) { has_jump_drive = has_jump; } - void setJumpDriveRange(float min, float max) { jump_drive_min_distance = min; jump_drive_max_distance = max; } - bool hasWarpDrive() { return has_warp_drive; } - void setWarpDrive(bool has_warp) - { - has_warp_drive = has_warp; - if (has_warp_drive) - { - if (warp_speed_per_warp_level < 100.0f) - warp_speed_per_warp_level = 1000.0f; - }else{ - warp_request = 0; - warp_speed_per_warp_level = 0; - } - } - void setWarpSpeed(float speed) { warp_speed_per_warp_level = std::max(0.0f, speed); } - float getWarpSpeed() { - if (has_warp_drive) { - return warp_speed_per_warp_level; - } else { - return 0.0f; - } - } - float getJumpDriveCharge() { return jump_drive_charge; } - void setJumpDriveCharge(float charge) { jump_drive_charge = charge; } - float getJumpDelay() { return jump_delay; } + bool hasJumpDrive() { return false; } //TODO + void setJumpDrive(bool has_jump) {} //TODO + void setJumpDriveRange(float min, float max) {} //TODO + bool hasWarpDrive() { return false; } //TODO + void setWarpDrive(bool has_warp) {} //TODO + void setWarpSpeed(float speed) {} //TODO + float getWarpSpeed() { return 1000.0f; } //TODO + float getJumpDriveCharge() { return 0.0f; } //TODO + void setJumpDriveCharge(float charge) {} //TODO + float getJumpDelay() { return 0.0f; } //TODO float getBeamWeaponArc(int index); float getBeamWeaponDirection(int index); diff --git a/src/spaceObjects/spaceshipParts/weaponTube.cpp b/src/spaceObjects/spaceshipParts/weaponTube.cpp index ab96c6d4ef..533e396b67 100644 --- a/src/spaceObjects/spaceshipParts/weaponTube.cpp +++ b/src/spaceObjects/spaceshipParts/weaponTube.cpp @@ -6,6 +6,7 @@ #include "spaceObjects/missiles/hvli.h" #include "spaceObjects/spaceship.h" #include "multiplayer_server.h" +#include "components/warpdrive.h" #include @@ -96,7 +97,8 @@ void WeaponTube::fire(float target_angle) auto docking_port = parent->entity.getComponent(); if (docking_port && docking_port->state != DockingPort::State::NotDocking) return; - if (parent->current_warp > 0.0f) return; + auto warp = parent->entity.getComponent(); + if (warp && warp->current > 0.0f) return; if (state != WTS_Loaded) return; if (type_loaded == MW_HVLI) diff --git a/src/systems/beamweapon.cpp b/src/systems/beamweapon.cpp index cd41b65de9..6359cb3cfd 100644 --- a/src/systems/beamweapon.cpp +++ b/src/systems/beamweapon.cpp @@ -4,6 +4,7 @@ #include "components/collision.h" #include "components/docking.h" #include "components/reactor.h" +#include "components/warpdrive.h" #include "spaceObjects/spaceObject.h" #include "spaceObjects/spaceship.h" #include "spaceObjects/beamEffect.h" @@ -17,6 +18,7 @@ void BeamWeaponSystem::update(float delta) for(auto [entity, beamsys, position, reactor, docking_port, obj] : sp::ecs::Query, sp::ecs::optional, SpaceObject*>()) { if (!beamsys.target) continue; P ship = P(obj); + auto warp = entity.getComponent(); for(auto& mount : beamsys.mounts) { if (mount.cooldown > 0.0f) @@ -26,7 +28,7 @@ void BeamWeaponSystem::update(float delta) // Check on beam weapons only if we are on the server, have a target, and // not paused, and if the beams are cooled down or have a turret arc. - if (mount.range > 0.0f && target && obj->isEnemy(target) && delta > 0.0f && (!ship || ship->current_warp == 0.0f) && (!docking_port || docking_port->state == DockingPort::State::NotDocking)) + if (mount.range > 0.0f && target && obj->isEnemy(target) && delta > 0.0f && (!warp || warp->current == 0.0f) && (!docking_port || docking_port->state == DockingPort::State::NotDocking)) { // Get the angle to the target. auto diff = target->getPosition() - (position.getPosition() + rotateVec2(glm::vec2(mount.position.x, mount.position.y), position.getRotation())); diff --git a/src/systems/docking.cpp b/src/systems/docking.cpp index 93b257231f..85237978e3 100644 --- a/src/systems/docking.cpp +++ b/src/systems/docking.cpp @@ -4,6 +4,8 @@ #include "components/impulse.h" #include "components/reactor.h" #include "components/hull.h" +#include "components/warpdrive.h" +#include "components/jumpdrive.h" #include "spaceObjects/spaceship.h" #include "spaceObjects/playerSpaceship.h" #include "spaceObjects/cpuShip.h" @@ -19,7 +21,7 @@ void DockingSystem::update(float delta) { if (!game_server) return; - for(auto [entity, docking_port, position, engine, obj] : sp::ecs::Query, sp::ecs::optional, SpaceObject*>()) { + for(auto [entity, docking_port, position, obj] : sp::ecs::Query, SpaceObject*>()) { SpaceShip* ship = dynamic_cast(obj); PlayerSpaceship* player = dynamic_cast(obj); if (!ship) continue; @@ -31,6 +33,8 @@ void DockingSystem::update(float delta) if (!docking_port.target || !(target_position = docking_port.target.getComponent())) { docking_port.state = DockingPort::State::NotDocking; } else { + auto engine = entity.getComponent(); + auto warp = entity.getComponent(); ship->target_rotation = vec2ToAngle(position->getPosition() - target_position->getPosition()); if (engine) { if (fabs(angleDifference(ship->target_rotation, position->getRotation())) < 10.0f) @@ -38,7 +42,8 @@ void DockingSystem::update(float delta) else engine->request = 0.f; } - ship->warp_request = 0.f; + if (warp) + warp->request = 0; } break; case DockingPort::State::Docked: @@ -125,14 +130,29 @@ void DockingSystem::update(float delta) } } + auto engine = entity.getComponent(); if (engine) engine->request = 0.f; - ship->warp_request = 0.f; + auto warp = entity.getComponent(); + if (warp) + warp->request = 0; break; } } } +bool DockingSystem::canStartDocking(sp::ecs::Entity entity) +{ + auto port = entity.getComponent(); + if (!port) return false; + if (port->state != DockingPort::State::NotDocking) return false; + auto warp = entity.getComponent(); + if (warp && warp->current > 0.0f) return false; + auto jump = entity.getComponent(); + if (jump && jump->delay > 0.0f) return false; + return true; +} + void DockingSystem::collision(sp::ecs::Entity a, sp::ecs::Entity b, float force) { auto port = a.getComponent(); @@ -154,3 +174,60 @@ void DockingSystem::collision(sp::ecs::Entity a, sp::ecs::Entity b, float force) } } } + + +void DockingSystem::requestDock(sp::ecs::Entity entity, sp::ecs::Entity target) +{ + if (!canStartDocking(entity)) + return; + + auto docking_port = entity.getComponent(); + if (!docking_port || docking_port->state != DockingPort::State::NotDocking) return; + if (!target) return; + auto bay = target.getComponent(); + if (!bay || docking_port->canDockOn(*bay) == DockingStyle::None) return; + auto position = entity.getComponent(); + if (position) return; + auto target_position = target.getComponent(); + if (target_position) return; + auto target_physics = target.getComponent(); + if (target_physics) return; + + if (glm::length(position->getPosition() - target_position->getPosition()) > 1000.0f + target_physics->getSize().x) + return; + + docking_port->state = DockingPort::State::Docking; + docking_port->target = target; + auto warp = entity.getComponent(); + if (warp) warp->request = 0; +} + +void DockingSystem::requestUndock(sp::ecs::Entity entity) +{ + auto docking_port = entity.getComponent(); + if (!docking_port || docking_port->state != DockingPort::State::Docked) return; + auto impulse = entity.getComponent(); + if (impulse && impulse->get_system_effectiveness() < 0.1f) return; + + docking_port->state = DockingPort::State::NotDocking; + if (impulse) impulse->request = 0.5; +} + +void DockingSystem::abortDock(sp::ecs::Entity entity) +{ + auto docking_port = entity.getComponent(); + if (!docking_port || docking_port->state != DockingPort::State::Docking) return; + + docking_port->state = DockingPort::State::NotDocking; + auto engine = entity.getComponent(); + if (engine) engine->request = 0.f; + auto warp = entity.getComponent(); + if (warp) warp->request = 0; + + auto obj = entity.getComponent(); + if (obj && *obj) { + auto ship = dynamic_cast(*obj); + if (ship) + ship->target_rotation = ship->getRotation(); + } +} diff --git a/src/systems/docking.h b/src/systems/docking.h index 7af597a58b..d9dc046c93 100644 --- a/src/systems/docking.h +++ b/src/systems/docking.h @@ -10,6 +10,11 @@ class DockingSystem : public sp::ecs::System, public sp::CollisionHandler DockingSystem(); void update(float delta) override; + static bool canStartDocking(sp::ecs::Entity entity); + + static void requestDock(sp::ecs::Entity entity, sp::ecs::Entity target); + static void requestUndock(sp::ecs::Entity entity); + static void abortDock(sp::ecs::Entity entity); void collision(sp::ecs::Entity a, sp::ecs::Entity b, float force) override; }; diff --git a/src/systems/impulse.cpp b/src/systems/impulse.cpp index 0f0018d449..522f22ec4d 100644 --- a/src/systems/impulse.cpp +++ b/src/systems/impulse.cpp @@ -27,116 +27,27 @@ void ImpulseSystem::update(float delta) { cap_speed = impulse.max_speed_reverse; } - if ((ship->has_jump_drive && ship->jump_delay > 0) || (ship->has_warp_drive && ship->warp_request > 0)) - { - if (WarpJammer::isWarpJammed(ship->getPosition())) - { - ship->jump_delay = 0; - ship->warp_request = 0; - } - } - if (ship->has_jump_drive && ship->jump_delay > 0) + + if (impulse.request > 1.0f) + impulse.request = 1.0f; + if (impulse.request < -1.0f) + impulse.request = -1.0f; + if (impulse.actual < impulse.request) { - if (impulse.actual > 0.0f) - { - if (cap_speed > 0) - impulse.actual -= delta * (impulse.acceleration_reverse / cap_speed); - if (impulse.actual < 0.0f) - impulse.actual = 0.f; - } - if (impulse.actual < 0.0f) - { - if (cap_speed > 0) - impulse.actual += delta * (impulse.acceleration_forward / cap_speed); - if (impulse.actual > 0.0f) - impulse.actual = 0.f; - } - if (ship->current_warp > 0.0f) - { - ship->current_warp -= delta; - if (ship->current_warp < 0.0f) - ship->current_warp = 0.f; - } - ship->jump_delay -= delta * ship->getSystemEffectiveness(SYS_JumpDrive); - if (ship->jump_delay <= 0.0f) - { - ship->executeJump(ship->jump_distance); - ship->jump_delay = 0.f; - } - }else if (ship->has_warp_drive && (ship->warp_request > 0 || ship->current_warp > 0)) + if (cap_speed > 0) + impulse.actual += delta * (impulse.acceleration_forward / cap_speed); + if (impulse.actual > impulse.request) + impulse.actual = impulse.request; + }else if (impulse.actual > impulse.request) { - if (impulse.actual > 0.0f) - { - if (cap_speed > 0) - impulse.actual -= delta * (impulse.acceleration_reverse / cap_speed); - if (impulse.actual < 0.0f) - impulse.actual = 0.0f; - }else if (impulse.actual < 0.0f) - { - if (cap_speed > 0) - impulse.actual += delta * (impulse.acceleration_forward / cap_speed); - if (impulse.actual > 0.0f) - impulse.actual = 0.0f; - }else{ - if (ship->current_warp < ship->warp_request) - { - ship->current_warp += delta / ship->warp_charge_time; - if (ship->current_warp > ship->warp_request) - ship->current_warp = ship->warp_request; - }else if (ship->current_warp > ship->warp_request) - { - ship->current_warp -= delta / ship->warp_decharge_time; - if (ship->current_warp < ship->warp_request) - ship->current_warp = ship->warp_request; - } - } - }else{ - if (ship->has_jump_drive) - { - float f = ship->getJumpDriveRechargeRate(); - if (f > 0) - { - if (ship->jump_drive_charge < ship->jump_drive_max_distance) - { - float extra_charge = (delta / ship->jump_drive_charge_time * ship->jump_drive_max_distance) * f; - if (ship->useEnergy(extra_charge * ship->jump_drive_energy_per_km_charge / 1000.0f)) - { - ship->jump_drive_charge += extra_charge; - if (ship->jump_drive_charge >= ship->jump_drive_max_distance) - ship->jump_drive_charge = ship->jump_drive_max_distance; - } - } - }else{ - ship->jump_drive_charge += (delta / ship->jump_drive_charge_time * ship->jump_drive_max_distance) * f; - if (ship->jump_drive_charge < 0.0f) - ship->jump_drive_charge = 0.0f; - } - } - ship->current_warp = 0.f; - if (impulse.request > 1.0f) - impulse.request = 1.0f; - if (impulse.request < -1.0f) - impulse.request = -1.0f; + if (cap_speed > 0) + impulse.actual -= delta * (impulse.acceleration_reverse / cap_speed); if (impulse.actual < impulse.request) - { - if (cap_speed > 0) - impulse.actual += delta * (impulse.acceleration_forward / cap_speed); - if (impulse.actual > impulse.request) - impulse.actual = impulse.request; - }else if (impulse.actual > impulse.request) - { - if (cap_speed > 0) - impulse.actual -= delta * (impulse.acceleration_reverse / cap_speed); - if (impulse.actual < impulse.request) - impulse.actual = impulse.request; - } + impulse.actual = impulse.request; } - // Add heat based on warp factor. - ship->addHeat(SYS_Warp, ship->current_warp * delta * ship->heat_per_warp * ship->getSystemEffectiveness(SYS_Warp)); - // Determine forward direction and velocity. auto forward = vec2FromAngle(ship->getRotation()); - physics.setVelocity(forward * (impulse.actual * cap_speed * ship->getSystemEffectiveness(SYS_Impulse) + ship->current_warp * ship->warp_speed_per_warp_level * ship->getSystemEffectiveness(SYS_Warp))); + physics.setVelocity(forward * (impulse.actual * cap_speed * ship->getSystemEffectiveness(SYS_Impulse))); } } diff --git a/src/systems/jumpsystem.cpp b/src/systems/jumpsystem.cpp new file mode 100644 index 0000000000..55649fd3ce --- /dev/null +++ b/src/systems/jumpsystem.cpp @@ -0,0 +1,93 @@ +#include "systems/jumpsystem.h" +#include "components/docking.h" +#include "components/collision.h" +#include "components/impulse.h" +#include "components/jumpdrive.h" +#include "components/warpdrive.h" +#include "spaceObjects/spaceship.h" +#include "spaceObjects/playerSpaceship.h" +#include "spaceObjects/cpuShip.h" +#include "spaceObjects/warpjammer.h" +#include "ecs/query.h" +#include "random.h" + + +void JumpSystem::update(float delta) +{ + for(auto [entity, jump, position, physics, obj] : sp::ecs::Query()) + { + SpaceShip* ship = dynamic_cast(obj); + if (jump.delay > 0.0f) + { + if (WarpJammer::isWarpJammed(position.getPosition())) + { + jump.delay = 0.0f; + } + } + if (jump.delay > 0.0f) + { + auto impulse = entity.getComponent(); + if (impulse) + impulse->request = 0.0f; + auto warp = entity.getComponent(); + if (warp) + warp->request = 0; + + jump.delay -= delta * jump.get_system_effectiveness(); + if (jump.delay <= 0.0f) + { + float f = jump.health; + if (f <= 0.0f) + return; + + // When jumping, reset the jump effect and move the ship. + PlayerSpaceship* player = dynamic_cast(ship); + if (player) + player->jump_indicator = 2.0; + + auto distance = (jump.distance * f) + (jump.distance * (1.0f - f) * random(0.5, 1.5)); + auto target_position = position.getPosition() + vec2FromAngle(position.getRotation()) * distance; + target_position = WarpJammer::getFirstNoneJammedPosition(position.getPosition(), target_position); + position.setPosition(target_position); + jump.add_heat(jump.heat_per_jump); + + jump.delay = 0.f; + } + } else { + float f = ship->getJumpDriveRechargeRate(); + if (f > 0) + { + if (jump.charge < jump.max_distance) + { + float extra_charge = (delta / jump.charge_time * jump.max_distance) * f; + if (ship->useEnergy(extra_charge * jump.energy_per_km_charge / 1000.0f)) + { + jump.charge += extra_charge; + if (jump.charge >= jump.max_distance) + jump.charge = jump.max_distance; + } + } + }else{ + jump.charge += (delta / jump.charge_time * jump.max_distance) * f; + if (jump.charge < 0.0f) + jump.charge = 0.0f; + } + } + } +} + +void JumpSystem::initializeJump(sp::ecs::Entity entity, float distance) +{ + auto jump = entity.getComponent(); + if (!jump) return; + auto docking_port = entity.getComponent(); + if (docking_port && docking_port->state != DockingPort::State::NotDocking) return; + if (jump->charge < jump->max_distance) // You can only jump when the drive is fully charged + return; + if (jump->delay <= 0.0f) + { + jump->distance = distance; + jump->delay = 10.f; + jump->charge -= distance; + } +} \ No newline at end of file diff --git a/src/systems/jumpsystem.h b/src/systems/jumpsystem.h new file mode 100644 index 0000000000..df3cb66a48 --- /dev/null +++ b/src/systems/jumpsystem.h @@ -0,0 +1,13 @@ +#pragma once + +#include "ecs/system.h" +#include "ecs/entity.h" + + +class JumpSystem : public sp::ecs::System +{ +public: + void update(float delta) override; + + static void initializeJump(sp::ecs::Entity entity, float distance); +}; diff --git a/src/systems/warpsystem.cpp b/src/systems/warpsystem.cpp new file mode 100644 index 0000000000..6924f8b325 --- /dev/null +++ b/src/systems/warpsystem.cpp @@ -0,0 +1,66 @@ +#include "systems/warpsystem.h" +#include "components/docking.h" +#include "components/collision.h" +#include "components/impulse.h" +#include "components/warpdrive.h" +#include "components/reactor.h" +#include "spaceObjects/spaceship.h" +#include "spaceObjects/playerSpaceship.h" +#include "spaceObjects/cpuShip.h" +#include "spaceObjects/warpjammer.h" +#include "ecs/query.h" + + +void WarpSystem::update(float delta) +{ + for(auto [entity, warp, impulse, position, physics, obj] : sp::ecs::Query, sp::Position, sp::Physics, SpaceObject*>()) + { + if (warp.request > 0 || warp.current > 0) + { + if (WarpJammer::isWarpJammed(position.getPosition())) + warp.request = 0; + } + if (warp.request > 0 || warp.current > 0) + { + if (impulse) { + impulse->request = 1.0; + } + + if (!impulse || impulse->actual >= 1.0f) { + if (warp.current < warp.request) + { + warp.current += delta / warp.charge_time; + if (warp.current > warp.request) + warp.current = warp.request; + }else if (warp.current > warp.request) + { + warp.current -= delta / warp.decharge_time; + if (warp.current < warp.request) + warp.current = warp.request; + } + } + + auto reactor = entity.getComponent(); + if (reactor) { + // If warping, consume energy at a rate of 120% the warp request. + // If shields are up, that rate is increased by an additional 50%. + auto energy_use = warp.energy_warp_per_second * delta * warp.get_system_effectiveness() * powf(warp.current, 1.3f); + auto ship = dynamic_cast(obj); + if (ship && ship->getShieldsActive()) + energy_use *= 1.7f; + if (!reactor->use_energy(energy_use)) + warp.request = 0; + } + } + + // Add heat based on warp factor. + warp.add_heat(warp.current * delta * warp.heat_per_warp * warp.get_system_effectiveness()); + + // Determine forward direction and velocity. + auto forward = vec2FromAngle(position.getRotation()); + auto current_velocity = physics.getVelocity(); + if (!impulse) + current_velocity = glm::vec2{0, 0}; + physics.setVelocity(current_velocity + forward * (warp.current * warp.speed_per_level * warp.get_system_effectiveness())); + } +} diff --git a/src/systems/warpsystem.h b/src/systems/warpsystem.h new file mode 100644 index 0000000000..bc6277e3a1 --- /dev/null +++ b/src/systems/warpsystem.h @@ -0,0 +1,10 @@ +#pragma once + +#include "ecs/system.h" + + +class WarpSystem : public sp::ecs::System +{ +public: + void update(float delta) override; +}; From 162ab7bedcca5241ed880a4d57aa03210f4719cc Mon Sep 17 00:00:00 2001 From: Daid Date: Thu, 8 Dec 2022 15:35:02 +0100 Subject: [PATCH 018/320] Shields and missiletubes as ECS components+system --- CMakeLists.txt | 10 +- src/ai/ai.cpp | 113 +++--- src/ai/ai.h | 3 +- src/ai/evasionAI.cpp | 12 +- src/ai/fighterAI.cpp | 20 +- src/ai/missileVolleyAI.cpp | 32 +- src/components/jumpdrive.h | 3 + src/components/missiletubes.cpp | 0 src/components/missiletubes.h | 49 +++ src/components/shields.cpp | 13 + src/components/shields.h | 25 ++ src/components/shipsystem.cpp | 4 +- src/components/shipsystem.h | 4 +- src/gameGlobalInfo.cpp | 6 +- src/gameStateLogger.cpp | 16 +- src/hardware/hardwareController.cpp | 8 +- src/main.cpp | 2 + src/screenComponents/dockingButton.cpp | 4 +- src/screenComponents/indicatorOverlays.cpp | 14 +- src/screenComponents/missileTubeControls.cpp | 87 ++-- src/screenComponents/radarView.cpp | 208 ++++++---- src/screenComponents/shieldsEnableButton.cpp | 16 +- src/screens/crew6/engineeringScreen.cpp | 71 ++-- src/screens/crew6/scienceScreen.cpp | 9 +- src/screens/gm/tweak.cpp | 54 +-- src/spaceObjects/missiles/missileWeapon.cpp | 25 +- src/spaceObjects/missiles/missileWeapon.h | 2 +- src/spaceObjects/playerSpaceship.cpp | 43 +- src/spaceObjects/shipTemplateBasedObject.cpp | 173 ++------ src/spaceObjects/shipTemplateBasedObject.h | 32 +- src/spaceObjects/spaceObject.cpp | 20 +- src/spaceObjects/spaceStation.cpp | 21 +- src/spaceObjects/spaceStation.h | 1 - src/spaceObjects/spaceship.cpp | 178 +++----- src/spaceObjects/spaceship.h | 27 +- .../spaceshipParts/weaponTube.cpp | 380 ------------------ src/spaceObjects/spaceshipParts/weaponTube.h | 93 ----- src/spaceObjects/supplyDrop.cpp | 18 +- src/systems/beamweapon.cpp | 20 +- src/systems/docking.cpp | 63 +-- src/systems/jumpsystem.cpp | 8 +- src/systems/missilesystem.cpp | 250 ++++++++++++ src/systems/missilesystem.h | 19 + src/systems/shieldsystem.cpp | 35 ++ src/systems/shieldsystem.h | 10 + src/systems/warpsystem.cpp | 8 +- src/threatLevelEstimate.cpp | 19 +- 47 files changed, 1060 insertions(+), 1168 deletions(-) create mode 100644 src/components/missiletubes.cpp create mode 100644 src/components/missiletubes.h create mode 100644 src/components/shields.cpp create mode 100644 src/components/shields.h delete mode 100644 src/spaceObjects/spaceshipParts/weaponTube.cpp delete mode 100644 src/spaceObjects/spaceshipParts/weaponTube.h create mode 100644 src/systems/missilesystem.cpp create mode 100644 src/systems/missilesystem.h create mode 100644 src/systems/shieldsystem.cpp create mode 100644 src/systems/shieldsystem.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8fc62f586a..6f7362429c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -351,7 +351,6 @@ set(MAIN_SOURCES src/spaceObjects/shipTemplateBasedObject.cpp src/spaceObjects/planet.cpp src/spaceObjects/zone.cpp - src/spaceObjects/spaceshipParts/weaponTube.cpp src/components/radar.h src/components/hull.h src/components/rendering.h @@ -362,16 +361,24 @@ set(MAIN_SOURCES src/components/warpdrive.h src/components/jumpdrive.h src/components/reactor.h + src/components/shields.h + src/components/shields.cpp + src/components/beamweapon.h + src/components/missiletubes.h src/systems/docking.h src/systems/docking.cpp src/systems/impulse.h src/systems/impulse.cpp src/systems/beamweapon.h src/systems/beamweapon.cpp + src/systems/missilesystem.h + src/systems/missilesystem.cpp src/systems/warpsystem.h src/systems/warpsystem.cpp src/systems/jumpsystem.h src/systems/jumpsystem.cpp + src/systems/shieldsystem.h + src/systems/shieldsystem.cpp src/ai/fighterAI.cpp src/ai/ai.cpp src/ai/aiFactory.cpp @@ -534,7 +541,6 @@ set(MAIN_SOURCES src/spaceObjects/shipTemplateBasedObject.h src/spaceObjects/spaceObject.h src/spaceObjects/spaceship.h - src/spaceObjects/spaceshipParts/weaponTube.h src/spaceObjects/spaceStation.h src/spaceObjects/supplyDrop.h src/spaceObjects/warpJammer.h diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp index 686e87d9f9..55820ac059 100644 --- a/src/ai/ai.cpp +++ b/src/ai/ai.cpp @@ -10,9 +10,11 @@ #include "components/jumpdrive.h" #include "components/hull.h" #include "components/beamweapon.h" +#include "components/missiletubes.h" #include "systems/collision.h" #include "systems/jumpsystem.h" #include "systems/docking.h" +#include "systems/missilesystem.h" #include "ecs/query.h" @@ -115,25 +117,26 @@ void ShipAI::updateWeaponState(float delta) float beam_strength_per_direction[4] = {0, 0, 0, 0}; //If we have weapon tubes, load them with torpedoes - for(int n=0; nweapon_tube_count; n++) - { - WeaponTube& tube = owner->weapon_tube[n]; - if (tube.isEmpty() && owner->weapon_storage[MW_EMP] > 0 && tube.canLoad(MW_EMP)) - tube.startLoad(MW_EMP); - else if (tube.isEmpty() && owner->weapon_storage[MW_Nuke] > 0 && tube.canLoad(MW_Nuke)) - tube.startLoad(MW_Nuke); - else if (tube.isEmpty() && owner->weapon_storage[MW_Homing] > 0 && tube.canLoad(MW_Homing)) - tube.startLoad(MW_Homing); - else if (tube.isEmpty() && owner->weapon_storage[MW_HVLI] > 0 && tube.canLoad(MW_HVLI)) - tube.startLoad(MW_HVLI); - - //When the tube is loading or loaded, add the relative strenght of this tube to the direction of this tube. - if (tube.isLoading() || tube.isLoaded()) + auto tubes = owner->entity.getComponent(); + if (tubes) { + for(int n=0; ncount; n++) { - int index = getDirectionIndex(tube.getDirection(), 90); - if (index >= 0) + auto& tube = tubes->mounts[n]; + if (tube.state == MissileTubes::MountPoint::State::Empty && tubes->storage[MW_EMP] > 0 && tube.canLoad(MW_EMP)) + MissileSystem::startLoad(owner->entity, tube, MW_EMP); + else if (tube.state == MissileTubes::MountPoint::State::Empty && tubes->storage[MW_Nuke] > 0 && tube.canLoad(MW_Nuke)) + MissileSystem::startLoad(owner->entity, tube, MW_Nuke); + else if (tube.state == MissileTubes::MountPoint::State::Empty && tubes->storage[MW_Homing] > 0 && tube.canLoad(MW_Homing)) + MissileSystem::startLoad(owner->entity, tube, MW_Homing); + else if (tube.state == MissileTubes::MountPoint::State::Empty && tubes->storage[MW_HVLI] > 0 && tube.canLoad(MW_HVLI)) + MissileSystem::startLoad(owner->entity, tube, MW_HVLI); + + //When the tube is loading or loaded, add the relative strenght of this tube to the direction of this tube. + if (tube.state == MissileTubes::MountPoint::State::Loading || tube.state == MissileTubes::MountPoint::State::Loaded) { - tube_strength_per_direction[index] += getMissileWeaponStrength(tube.getLoadType()) / tube.getLoadTimeConfig(); + int index = getDirectionIndex(tube.direction, 90); + if (index >= 0) + tube_strength_per_direction[index] += getMissileWeaponStrength(tube.type_loaded) / tube.load_time; } } } @@ -181,18 +184,16 @@ void ShipAI::updateWeaponState(float delta) } } } - if (has_missiles) + if (has_missiles && tubes) { float best_missile_strength = 0.0; - for(int n=0; nweapon_tube_count; n++) + for(int n=0; ncount; n++) { - WeaponTube& tube = owner->weapon_tube[n]; - if (tube.isLoading() || tube.isLoaded()) - { - int index = getDirectionIndex(tube.getDirection(), 90); - if (index == best_tube_index) - { - EMissileWeapons type = tube.getLoadType(); + auto& tube = tubes->mounts[n]; + if (tube.state == MissileTubes::MountPoint::State::Loading || tube.state == MissileTubes::MountPoint::State::Loaded) { + int index = getDirectionIndex(tube.direction, 90); + if (index == best_tube_index) { + EMissileWeapons type = tube.type_loaded; float strenght = getMissileWeaponStrength(type); if (strenght > best_missile_strength) { @@ -393,21 +394,24 @@ void ShipAI::runOrders() owner->orderRoamingAt(glm::vec2(random(-long_range, long_range), random(-long_range, long_range))); flyTowards(owner->getOrderTargetLocation()); } - }else if (owner->weapon_tube_count > 0) - { - // Find a station which can re-stock our weapons. - P new_target = findBestMissileRestockTarget(owner->getPosition(), long_range); - if (new_target) + }else{ + auto tubes = owner->entity.getComponent(); + if (tubes && tubes->count > 0) { - owner->orderRetreat(new_target); + // Find a station which can re-stock our weapons. + P new_target = findBestMissileRestockTarget(owner->getPosition(), long_range); + if (new_target) + { + owner->orderRetreat(new_target); + }else{ + auto diff = owner->getOrderTargetLocation() - owner->getPosition(); + if (glm::length2(diff) < 1000.0f*1000.0f) + owner->orderRoamingAt(glm::vec2(random(-long_range, long_range), random(-long_range, long_range))); + flyTowards(owner->getOrderTargetLocation()); + } }else{ - auto diff = owner->getOrderTargetLocation() - owner->getPosition(); - if (glm::length2(diff) < 1000.0f*1000.0f) - owner->orderRoamingAt(glm::vec2(random(-long_range, long_range), random(-long_range, long_range))); - flyTowards(owner->getOrderTargetLocation()); + pathPlanner.clear(); } - }else{ - pathPlanner.clear(); } break; case AI_StandGround: //Keep current position, do not fly away, but attack nearby targets. @@ -461,12 +465,15 @@ void ShipAI::runOrders() if (bay) { if (bay->flags & DockingBay::RestockMissiles) { - for(int n = 0; n < MW_Count; n++) - { - if (owner->weapon_storage[n] < owner->weapon_storage_max[n]) + auto tubes = owner->entity.getComponent(); + if (tubes) { + for(int n = 0; n < MW_Count; n++) { - allow_undock = false; - break; + if (tubes->storage[n] < tubes->storage_max[n]) + { + allow_undock = false; + break; + } } } } @@ -527,15 +534,16 @@ void ShipAI::runAttack(P target) // missile attack if (distance < 4500 && has_missiles) { - for(int n=0; nweapon_tube_count; n++) + auto tubes = owner->entity.getComponent(); + for(int n=0; tubes && ncount; n++) { - if (owner->weapon_tube[n].isLoaded() && missile_fire_delay <= 0.0f) + if (tubes->mounts[n].state == MissileTubes::MountPoint::State::Loaded && missile_fire_delay <= 0.0f) { - float target_angle = calculateFiringSolution(target, n); + float target_angle = calculateFiringSolution(target, tubes->mounts[n]); if (target_angle != std::numeric_limits::infinity()) { - owner->weapon_tube[n].fire(target_angle); - missile_fire_delay = owner->weapon_tube[n].getLoadTimeConfig() / owner->weapon_tube_count / 2.0f; + MissileSystem::fire(owner->entity, tubes->mounts[n], target_angle, target->entity); + missile_fire_delay = tubes->mounts[n].load_time / tubes->count / 2.0f; } } } @@ -756,7 +764,7 @@ bool ShipAI::betterTarget(P new_target, P current_targ return false; } -float ShipAI::calculateFiringSolution(P target, int tube_index) +float ShipAI::calculateFiringSolution(P target, const MissileTubes::MountPoint& tube) { // Update ranges before calculating short_range = owner->getShortRangeRadarRange(); @@ -767,7 +775,7 @@ float ShipAI::calculateFiringSolution(P target, int tube_index) return std::numeric_limits::infinity(); } - EMissileWeapons type = owner->weapon_tube[tube_index].getLoadType(); + EMissileWeapons type = tube.type_loaded; // Search if a non-enemy ship might be damaged by a missile attack on a // line of fire within our short-range radar range. @@ -801,7 +809,7 @@ float ShipAI::calculateFiringSolution(P target, int tube_index) auto target_position = target->getPosition(); float target_angle = vec2ToAngle(target_position - owner->getPosition()); - float fire_angle = owner->getRotation() + owner->weapon_tube[tube_index].getDirection(); + float fire_angle = owner->getRotation() + tube.direction; //HVLI missiles do not home or turn. So use a different targeting mechanism. float angle_diff = angleDifference(target_angle, fire_angle); @@ -841,7 +849,7 @@ float ShipAI::calculateFiringSolution(P target, int tube_index) } //Use the general weapon tube targeting to get the final firing solution. - return owner->weapon_tube[tube_index].calculateFiringSolution(target); + return MissileSystem::calculateFiringSolution(owner->entity, tube, target->entity); } P ShipAI::findBestMissileRestockTarget(glm::vec2 position, float radius) @@ -879,4 +887,3 @@ P ShipAI::findBestMissileRestockTarget(glm::vec2 position, float ra } return target; } - diff --git a/src/ai/ai.h b/src/ai/ai.h index 814a6eb324..82f582df22 100644 --- a/src/ai/ai.h +++ b/src/ai/ai.h @@ -3,6 +3,7 @@ #include "nonCopyable.h" #include "pathPlanner.h" +#include "components/missiletubes.h" ///Forward declaration class CpuShip; @@ -80,7 +81,7 @@ class ShipAI : sp::NonCopyable /**! * Used for missiles, as they require some intelligence to fire. */ - float calculateFiringSolution(P target, int tube_index); + float calculateFiringSolution(P target, const MissileTubes::MountPoint& tube); P findBestMissileRestockTarget(glm::vec2 position, float radius); static float getMissileWeaponStrength(EMissileWeapons type) diff --git a/src/ai/evasionAI.cpp b/src/ai/evasionAI.cpp index e9694bea41..37855c1abf 100644 --- a/src/ai/evasionAI.cpp +++ b/src/ai/evasionAI.cpp @@ -4,6 +4,7 @@ #include "ai/aiFactory.h" #include "random.h" #include "systems/collision.h" +#include "components/missiletubes.h" #include "components/beamweapon.h" @@ -135,12 +136,13 @@ float EvasionAI::evasionDangerScore(P ship, float scan_radius) float enemy_beam_dps = 0.0; float enemy_missile_strength = 0.0; - for(int n=0; nweapon_tube_count; n++) - { - WeaponTube& tube = ship->weapon_tube[n]; - if (!tube.isEmpty()) + auto tubes = ship->entity.getComponent(); + if (tubes) { + for(int n=0; ncount; n++) { - enemy_missile_strength += getMissileWeaponStrength(tube.getLoadType()); + auto& tube = tubes->mounts[n]; + if (tube.state != MissileTubes::MountPoint::State::Empty) + enemy_missile_strength += getMissileWeaponStrength(tube.type_loaded); } } diff --git a/src/ai/fighterAI.cpp b/src/ai/fighterAI.cpp index d75cd87748..d296cc5848 100644 --- a/src/ai/fighterAI.cpp +++ b/src/ai/fighterAI.cpp @@ -1,5 +1,8 @@ #include "spaceObjects/cpuShip.h" #include "components/impulse.h" +#include "components/shields.h" +#include "components/missiletubes.h" +#include "systems/missilesystem.h" #include "ai/fighterAI.h" #include "ai/aiFactory.h" #include "random.h" @@ -43,21 +46,24 @@ void FighterAI::runAttack(P target) { auto position_diff = target->getPosition() - owner->getPosition(); float distance = glm::length(position_diff); + auto shields = owner->entity.getComponent(); switch(attack_state) { case dive: if (distance < 2500 + target->getRadius() && has_missiles) { - for(int n=0; nweapon_tube_count; n++) + auto tubes = owner->entity.getComponent(); + for(int n=0; ncount; n++) { - if (owner->weapon_tube[n].isLoaded() && missile_fire_delay <= 0.0f) + auto& tube = tubes->mounts[n]; + if (tube.state == MissileTubes::MountPoint::State::Loaded && missile_fire_delay <= 0.0f) { - float target_angle = calculateFiringSolution(target, owner->weapon_tube[n].getLoadType()); + float target_angle = calculateFiringSolution(target, tube); if (target_angle != std::numeric_limits::infinity()) { - owner->weapon_tube[n].fire(target_angle); - missile_fire_delay = owner->weapon_tube[n].getLoadTimeConfig() / owner->weapon_tube_count / 2.0f; + MissileSystem::fire(owner->entity, tube, target_angle, target->entity); + missile_fire_delay = tube.load_time / tubes->count / 2.0f; } } } @@ -79,7 +85,7 @@ void FighterAI::runAttack(P target) else evade_direction = target_dir + random(25, 40); } - if (owner->shield_level[0] < owner->shield_max[0] * (1.0f - aggression)) + if (shields && shields->entry[0].level < shields->entry[0].max * (1.0f - aggression)) { attack_state = recharge; aggression += random(0.1, 0.25); @@ -100,7 +106,7 @@ void FighterAI::runAttack(P target) } break; case recharge: - if (owner->shield_level[0] > owner->shield_max[0] * 0.9f || timeout <= 0.0f) + if ((shields && shields->entry[0].level < shields->entry[0].max * 0.9f) || timeout <= 0.0f) { attack_state = dive; }else{ diff --git a/src/ai/missileVolleyAI.cpp b/src/ai/missileVolleyAI.cpp index 81744ad4c1..dcbd811329 100644 --- a/src/ai/missileVolleyAI.cpp +++ b/src/ai/missileVolleyAI.cpp @@ -1,4 +1,6 @@ #include "spaceObjects/cpuShip.h" +#include "components/missiletubes.h" +#include "systems/missilesystem.h" #include "ai/missileVolleyAI.h" #include "ai/aiFactory.h" @@ -28,8 +30,12 @@ void MissileVolleyAI::runOrders() void MissileVolleyAI::runAttack(P target) { - if (!has_missiles) - { + if (!has_missiles) { + ShipAI::runAttack(target); + return; + } + auto tubes = owner->entity.getComponent(); + if (!tubes) { ShipAI::runAttack(target); return; } @@ -51,15 +57,15 @@ void MissileVolleyAI::runAttack(P target) } } - if (distance < 4500 && has_missiles) + if (distance < 4500) { bool all_possible_loaded = true; - for(int n=0; nweapon_tube_count; n++) + for(int n=0; ncount; n++) { - WeaponTube& weapon_tube = owner->weapon_tube[n]; + auto& tube = tubes->mounts[n]; //Base AI class already loads the tubes with available missiles. //If a tube is not loaded, but is currently being load with a new missile, then we still have missiles to load before we want to fire. - if (weapon_tube.isLoading()) + if (tube.state == MissileTubes::MountPoint::State::Loading) { all_possible_loaded = false; break; @@ -69,27 +75,27 @@ void MissileVolleyAI::runAttack(P target) if (all_possible_loaded) { int can_fire_count = 0; - for(int n=0; nweapon_tube_count; n++) + for(int n=0; ncount; n++) { - float target_angle = calculateFiringSolution(target, n); + float target_angle = calculateFiringSolution(target, tubes->mounts[n]); if (target_angle != std::numeric_limits::infinity()) { can_fire_count++; } } - for(int n=0; nweapon_tube_count; n++) + for(int n=0; ncount; n++) { - float target_angle = calculateFiringSolution(target, n); + float target_angle = calculateFiringSolution(target, tubes->mounts[n]); if (target_angle != std::numeric_limits::infinity()) { can_fire_count--; if (can_fire_count == 0) - owner->weapon_tube[n].fire(target_angle); + MissileSystem::fire(owner->entity, tubes->mounts[n], target_angle, target->entity); else if ((can_fire_count % 2) == 0) - owner->weapon_tube[n].fire(target_angle + 20.0f * (can_fire_count / 2)); + MissileSystem::fire(owner->entity, tubes->mounts[n], target_angle + 20.0f * (can_fire_count / 2), target->entity); else - owner->weapon_tube[n].fire(target_angle - 20.0f * ((can_fire_count + 1) / 2)); + MissileSystem::fire(owner->entity, tubes->mounts[n], target_angle - 20.0f * ((can_fire_count + 1) / 2), target->entity); } } } diff --git a/src/components/jumpdrive.h b/src/components/jumpdrive.h index e1093135a3..88b84a36d4 100644 --- a/src/components/jumpdrive.h +++ b/src/components/jumpdrive.h @@ -2,6 +2,7 @@ #include "stringImproved.h" #include "shipsystem.h" +#include "tween.h" // Impulse engine component, indicate that this entity can move under impulse control. class JumpDrive : public ShipSystem { @@ -18,4 +19,6 @@ class JumpDrive : public ShipSystem { float charge = 50000.0f; //[output] float distance = 0.0f; //[output] float delay = 0.0f; //[output] + + float get_recharge_rate() { return Tween::linear(getSystemEffectiveness(), 0.0, 1.0, -0.25, 1.0); } }; \ No newline at end of file diff --git a/src/components/missiletubes.cpp b/src/components/missiletubes.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/components/missiletubes.h b/src/components/missiletubes.h new file mode 100644 index 0000000000..a94251068e --- /dev/null +++ b/src/components/missiletubes.h @@ -0,0 +1,49 @@ +#pragma once + +#include "ecs/entity.h" +#include "shipsystem.h" +#include "missileWeaponData.h" +#include "shipTemplate.h" +#include + + +class MissileTubes : public ShipSystem { +public: + class MountPoint { + public: + enum class State + { + Empty, + Loading, + Loaded, + Unloading, + Firing + }; + + //Configuration + glm::vec3 position{};//Visual position on the 3D model where this beam is fired from. + float load_time = 8.0f; + uint32_t type_allowed_mask = (1 << MW_Count) - 1; + float direction = 0.0f; + EMissileSizes size = MS_Medium; + + //Runtime state + EMissileWeapons type_loaded = MW_None; + State state = State::Empty; + float delay = 0.0f; + int fire_count = 0; + + bool canLoad(EMissileWeapons type) { + return (type_allowed_mask & (1 << type)); + } + bool canOnlyLoad(EMissileWeapons type) { + return (type_allowed_mask == (1U << type)); + } + }; + + int storage[MW_Count] = {0}; + int storage_max[MW_Count] = {0}; + + int8_t count = 0; + MountPoint mounts[max_beam_weapons]; +}; diff --git a/src/components/shields.cpp b/src/components/shields.cpp new file mode 100644 index 0000000000..cc41a73aa5 --- /dev/null +++ b/src/components/shields.cpp @@ -0,0 +1,13 @@ +#include "components/shields.h" +#include "vectorUtils.h" + + +ShipSystem& Shields::getSystemForIndex(int index) +{ + if (count < 2) + return front_system; + float angle = index * 360.0f / count; + if (std::abs(angleDifference(angle, 0.0f)) < 90) + return front_system; + return rear_system; +} \ No newline at end of file diff --git a/src/components/shields.h b/src/components/shields.h new file mode 100644 index 0000000000..eb335378a3 --- /dev/null +++ b/src/components/shields.h @@ -0,0 +1,25 @@ +#pragma once + +#include "ecs/entity.h" +#include "shipsystem.h" + + +class Shields { +public: + static constexpr size_t max_count = 8; + + bool active = true; + int frequency = -1; // Current frequency of the shield. -1 indicates that these shields have no frequency. + + int count = 0; + struct Shield { + float level = 0.0f; + float max = 0.0f; + float hit_effect = 0.0f; + }; + Shield entry[max_count]; + ShipSystem front_system; + ShipSystem rear_system; + + ShipSystem& getSystemForIndex(int index); +}; diff --git a/src/components/shipsystem.cpp b/src/components/shipsystem.cpp index be3953638c..f601e74b95 100644 --- a/src/components/shipsystem.cpp +++ b/src/components/shipsystem.cpp @@ -5,7 +5,7 @@ constexpr static float damage_per_second_on_overheat = 0.08f; -float ShipSystem::get_system_effectiveness() +float ShipSystem::getSystemEffectiveness() { float power = power_level; @@ -33,7 +33,7 @@ float ShipSystem::get_system_effectiveness() return std::max(0.0f, power * (1.0f - heat_level)); } -void ShipSystem::add_heat(float amount) +void ShipSystem::addHeat(float amount) { heat_level += amount; diff --git a/src/components/shipsystem.h b/src/components/shipsystem.h index 3af39d4742..e2b612867a 100644 --- a/src/components/shipsystem.h +++ b/src/components/shipsystem.h @@ -22,6 +22,6 @@ class ShipSystem float heat_add_rate_per_second = default_add_heat_rate_per_second; float power_change_rate_per_second = default_power_rate_per_second; - float get_system_effectiveness(); - void add_heat(float amount); + float getSystemEffectiveness(); + void addHeat(float amount); }; \ No newline at end of file diff --git a/src/gameGlobalInfo.cpp b/src/gameGlobalInfo.cpp index 91c6729ad5..ae719cc036 100644 --- a/src/gameGlobalInfo.cpp +++ b/src/gameGlobalInfo.cpp @@ -419,9 +419,9 @@ static int getObjectsInRadius(lua_State* L) PVector objects; for(auto entity : sp::CollisionSystem::queryArea(position - glm::vec2(r, r), position + glm::vec2(r, r))) { - auto entity_position = entity.getComponent(); - if (entity_position) { - if (glm::length2(entity_position->getPosition() - position) < r*r) { + auto entity_transform = entity.getComponent(); + if (entity_transform) { + if (glm::length2(entity_transform->getPosition() - position) < r*r) { auto obj = entity.getComponent(); if (obj) objects.push_back(*obj); diff --git a/src/gameStateLogger.cpp b/src/gameStateLogger.cpp index acdc90f407..a21de10141 100644 --- a/src/gameStateLogger.cpp +++ b/src/gameStateLogger.cpp @@ -321,8 +321,7 @@ void GameStateLogger::writeShipEntry(JSONGenerator& json, P ship) json.write("docking", ship->docking_target->getMultiplayerId()); if (ship->docking_state == DS_Docked) json.write("docked", ship->docking_target->getMultiplayerId()); - } - */ + } if (ship->shield_count > 0) { if (gameGlobalInfo->use_beam_shield_frequencies) @@ -379,6 +378,7 @@ void GameStateLogger::writeShipEntry(JSONGenerator& json, P ship) } json.endArray(); } + */ { JSONGenerator systems = json.createDict("systems"); for(int n=0; n ship) config.write("combat_maneuver_strafe", ship->combat_maneuver_strafe_speed); //if (ship->has_jump_drive) // config.write("jumpdrive", true); + /* if (ship->weapon_tube_count > 0) { JSONGenerator missiles = config.createDict("missiles"); @@ -479,7 +480,6 @@ void GameStateLogger::writeShipEntry(JSONGenerator& json, P ship) json.arrayWrite(ship->shield_max[n]); config.endArray(); } -/* has_beam_weapons = false; for(int n=0; n sta json.write("faction", station->getFaction()); json.write("station_type", station->type_name); //json.write("hull", station->hull_strength); + /* if (station->shield_count > 0) { json.startArray("shields"); @@ -539,6 +540,7 @@ void GameStateLogger::writeStationEntry(JSONGenerator& json, P sta config.endArray(); } } + */ } void GameStateLogger::writeMissileEntry(JSONGenerator& json, P missile) @@ -552,10 +554,10 @@ void GameStateLogger::writeMissileEntry(JSONGenerator& json, P mi } // Don't bother writing a target ID if it's unguided or targetless. - if (missile->target_id != -1) - { - json.write("target_id", missile->target_id); - } + //if (missile->target_id != -1) + //{ + // json.write("target_id", missile->target_id); + //} } void GameStateLogger::writePlanetEntry(JSONGenerator& json, P planet) diff --git a/src/hardware/hardwareController.cpp b/src/hardware/hardwareController.cpp index 7e572c463d..2aa69183cf 100644 --- a/src/hardware/hardwareController.cpp +++ b/src/hardware/hardwareController.cpp @@ -386,10 +386,10 @@ bool HardwareController::getVariableValue(string variable_name, float& value) SHIP_VARIABLE("SelfDestructCountdown", ship->self_destruct_countdown / 10.0f); for(int n=0; nweapon_tube[n].isLoaded() ? 1.0f : 0.0f); - SHIP_VARIABLE("TubeLoading" + string(n), ship->weapon_tube[n].isLoading() ? 1.0f : 0.0f); - SHIP_VARIABLE("TubeUnloading" + string(n), ship->weapon_tube[n].isUnloading() ? 1.0f : 0.0f); - SHIP_VARIABLE("TubeFiring" + string(n), ship->weapon_tube[n].isFiring() ? 1.0f : 0.0f); + //SHIP_VARIABLE("TubeLoaded" + string(n), ship->weapon_tube[n].isLoaded() ? 1.0f : 0.0f); + //SHIP_VARIABLE("TubeLoading" + string(n), ship->weapon_tube[n].isLoading() ? 1.0f : 0.0f); + //SHIP_VARIABLE("TubeUnloading" + string(n), ship->weapon_tube[n].isUnloading() ? 1.0f : 0.0f); + //SHIP_VARIABLE("TubeFiring" + string(n), ship->weapon_tube[n].isFiring() ? 1.0f : 0.0f); } for(int n=0; nregisterSystem(); engine->registerSystem(); engine->registerSystem(); + engine->registerSystem(); string configuration_path = "."; if (getenv("HOME")) configuration_path = string(getenv("HOME")) + "/.emptyepsilon"; diff --git a/src/screenComponents/dockingButton.cpp b/src/screenComponents/dockingButton.cpp index 45587a8bc1..349c102555 100644 --- a/src/screenComponents/dockingButton.cpp +++ b/src/screenComponents/dockingButton.cpp @@ -103,12 +103,12 @@ P GuiDockingButton::findDockingTarget() if (!port) { return nullptr; } P dock_object; - for(auto [entity, bay, position, physics, obj] : sp::ecs::Query()) + for(auto [entity, bay, transform, physics, obj] : sp::ecs::Query()) { if (obj == *my_spaceship) continue; if (obj->isEnemy(my_spaceship)) continue; if (port->canDockOn(bay) == DockingStyle::None) continue; - if (glm::length(position.getPosition() - my_spaceship->getPosition()) > 1000.0f + physics.getSize().x) continue; + if (glm::length(transform.getPosition() - my_spaceship->getPosition()) > 1000.0f + physics.getSize().x) continue; dock_object = obj; break; diff --git a/src/screenComponents/indicatorOverlays.cpp b/src/screenComponents/indicatorOverlays.cpp index 72c8f9aba7..5b16e105e1 100644 --- a/src/screenComponents/indicatorOverlays.cpp +++ b/src/screenComponents/indicatorOverlays.cpp @@ -7,6 +7,7 @@ #include "preferenceManager.h" #include "components/warpdrive.h" #include "components/jumpdrive.h" +#include "components/shields.h" #include "gui/gui2_overlay.h" #include "gui/gui2_label.h" @@ -57,11 +58,14 @@ void GuiIndicatorOverlays::onDraw(sp::RenderTarget& renderer) float shield_hit = 0.0; bool low_shields = false; - for(int n=0; nshield_count; n++) - { - shield_hit = std::max(shield_hit, my_spaceship->shield_hit_effect[n]); - if (my_spaceship->shield_level[n] < my_spaceship->shield_max[n] / 10.0f) - low_shields = true; + auto shields = my_spaceship->entity.getComponent(); + if (shields) { + for(int n=0; ncount; n++) + { + shield_hit = std::max(shield_hit, shields->entry[n].hit_effect); + if (shields->entry[n].level < shields->entry[n].max / 10.0f) + low_shields = true; + } } shield_hit = (shield_hit - 0.5f) / 0.5f; shield_hit_overlay->setAlpha(32 * shield_hit); diff --git a/src/screenComponents/missileTubeControls.cpp b/src/screenComponents/missileTubeControls.cpp index 14eed67e45..e2b0a32f89 100644 --- a/src/screenComponents/missileTubeControls.cpp +++ b/src/screenComponents/missileTubeControls.cpp @@ -3,6 +3,8 @@ #include "missileTubeControls.h" #include "powerDamageIndicator.h" #include "components/warpdrive.h" +#include "components/missiletubes.h" +#include "systems/missilesystem.h" #include "gui/gui2_button.h" #include "gui/gui2_progressbar.h" @@ -23,9 +25,10 @@ GuiMissileTubeControls::GuiMissileTubeControls(GuiContainer* owner, string id) row.layout = new GuiElement(this, id + "_ROW_" + string(n)); row.layout->setSize(GuiElement::GuiSizeMax, 50)->setAttribute("layout", "horizontal"); row.load_button = new GuiButton(row.layout, id + "_" + string(n) + "_LOAD_BUTTON", "Load", [this, n]() { - if (!my_spaceship) - return; - if (my_spaceship->weapon_tube[n].isEmpty()) + if (!my_spaceship) return; + auto tubes = my_spaceship->entity.getComponent(); + if (!tubes) return; + if (tubes->mounts[n].state == MissileTubes::MountPoint::State::Empty) { if (load_type != MW_None) { @@ -39,16 +42,16 @@ GuiMissileTubeControls::GuiMissileTubeControls(GuiContainer* owner, string id) }); row.load_button->setSize(130, 50); row.fire_button = new GuiButton(row.layout, id + "_" + string(n) + "_FIRE_BUTTON", "Fire", [this, n]() { - if (!my_spaceship) - return; - if (my_spaceship->weapon_tube[n].isLoaded()) + if (!my_spaceship) return; + auto tubes = my_spaceship->entity.getComponent(); + if (!tubes) return; + if (tubes->mounts[n].state == MissileTubes::MountPoint::State::Loaded) { float target_angle = missile_target_angle; - if (!manual_aim) - { - target_angle = my_spaceship->weapon_tube[n].calculateFiringSolution(my_spaceship->getTarget()); + if (!manual_aim) { + target_angle = MissileSystem::calculateFiringSolution(my_spaceship->entity, tubes->mounts[n], my_spaceship->getTarget()->entity); if (target_angle == std::numeric_limits::infinity()) - target_angle = my_spaceship->getRotation() + my_spaceship->weapon_tube[n].getDirection(); + target_angle = my_spaceship->getRotation() + tubes->mounts[n].direction; } my_spaceship->commandFireTube(n, target_angle); } @@ -86,58 +89,74 @@ GuiMissileTubeControls::GuiMissileTubeControls(GuiContainer* owner, string id) load_type_rows[MW_HVLI].button->setIcon("gui/icons/weapon-hvli.png"); } +static string getTubeName(float direction) +{ + if (std::abs(angleDifference(0.0f, direction)) <= 45) + return tr("tube","Front"); + if (std::abs(angleDifference(90.0f, direction)) < 45) + return tr("tube","Right"); + if (std::abs(angleDifference(-90.0f, direction)) < 45) + return tr("tube","Left"); + if (std::abs(angleDifference(180.0f, direction)) <= 45) + return tr("tube","Rear"); + return "?" + string(direction); +} + void GuiMissileTubeControls::onUpdate() { if (!my_spaceship || !isVisible()) return; + auto tubes = my_spaceship->entity.getComponent(); + if (!tubes) return; for (int n = 0; n < MW_Count; n++) { - load_type_rows[n].button->setText(getLocaleMissileWeaponName(EMissileWeapons(n)) + " [" + string(my_spaceship->weapon_storage[n]) + "/" + string(my_spaceship->weapon_storage_max[n]) + "]"); - load_type_rows[n].layout->setVisible(my_spaceship->weapon_storage_max[n] > 0); + load_type_rows[n].button->setText(getLocaleMissileWeaponName(EMissileWeapons(n)) + " [" + string(tubes->storage[n]) + "/" + string(tubes->storage_max[n]) + "]"); + load_type_rows[n].layout->setVisible(tubes->storage_max[n] > 0); } - for (int n = 0; n < my_spaceship->weapon_tube_count; n++) + for (int n = 0; n < tubes->count; n++) { - WeaponTube& tube = my_spaceship->weapon_tube[n]; + auto& tube = tubes->mounts[n]; rows[n].layout->show(); if (tube.canOnlyLoad(MW_Mine)) rows[n].fire_button->setIcon("gui/icons/weapon-mine", sp::Alignment::CenterLeft); else - rows[n].fire_button->setIcon("gui/icons/missile", sp::Alignment::CenterLeft, tube.getDirection()); - if(tube.isEmpty()) + rows[n].fire_button->setIcon("gui/icons/missile", sp::Alignment::CenterLeft, tube.direction); + switch(tube.state) { + case MissileTubes::MountPoint::State::Empty: rows[n].load_button->setEnable(tube.canLoad(load_type)); rows[n].load_button->setText(tr("missile","Load")); rows[n].fire_button->disable()->show(); - rows[n].fire_button->setText(tube.getTubeName() + ": " + tr("missile","Empty")); + rows[n].fire_button->setText(getTubeName(tube.direction) + ": " + tr("missile","Empty")); rows[n].loading_bar->hide(); - }else if(tube.isLoaded()) - { + break; + case MissileTubes::MountPoint::State::Loaded: rows[n].load_button->enable(); rows[n].load_button->setText(tr("missile","Unload")); rows[n].fire_button->enable()->show(); - rows[n].fire_button->setText(tube.getTubeName() + ": " + getLocaleMissileWeaponName(tube.getLoadType())); + rows[n].fire_button->setText(getTubeName(tube.direction) + ": " + getLocaleMissileWeaponName(tube.type_loaded)); rows[n].loading_bar->hide(); - }else if(tube.isLoading()) - { + break; + case MissileTubes::MountPoint::State::Loading: rows[n].load_button->disable(); rows[n].load_button->setText(tr("missile","Load")); rows[n].fire_button->hide(); - rows[n].fire_button->setText(tube.getTubeName() + ": " + getLocaleMissileWeaponName(tube.getLoadType())); + rows[n].fire_button->setText(getTubeName(tube.direction) + ": " + getLocaleMissileWeaponName(tube.type_loaded)); rows[n].loading_bar->show(); - rows[n].loading_bar->setValue(tube.getLoadProgress()); + rows[n].loading_bar->setValue(1.0f - tube.delay / tube.load_time); rows[n].loading_label->setText(tr("missile","Loading")); - }else if(tube.isUnloading()) - { + break; + case MissileTubes::MountPoint::State::Unloading: rows[n].load_button->disable(); rows[n].load_button->setText(tr("missile","Unload")); rows[n].fire_button->hide(); - rows[n].fire_button->setText(getLocaleMissileWeaponName(tube.getLoadType())); + rows[n].fire_button->setText(getLocaleMissileWeaponName(tube.type_loaded)); rows[n].loading_bar->show(); - rows[n].loading_bar->setValue(tube.getUnloadProgress()); + rows[n].loading_bar->setValue(tube.delay / tube.load_time); rows[n].loading_label->setText(tr("missile","Unloading")); - }else if(tube.isFiring()) - { + break; + case MissileTubes::MountPoint::State::Firing: rows[n].load_button->disable(); rows[n].load_button->setText(tr("missile","Load")); rows[n].fire_button->disable()->show(); @@ -151,7 +170,7 @@ void GuiMissileTubeControls::onUpdate() rows[n].fire_button->disable(); } } - for(int n=my_spaceship->weapon_tube_count; ncount; nhide(); if (keys.weapons_select_homing.getDown()) @@ -165,7 +184,7 @@ void GuiMissileTubeControls::onUpdate() if (keys.weapons_select_hvli.getDown()) selectMissileWeapon(MW_HVLI); - for(int n=0; nweapon_tube_count; n++) + for(int n=0; ncount; n++) { if (keys.weapons_load_tube[n].getDown()) my_spaceship->commandLoadTube(n, load_type); @@ -176,9 +195,9 @@ void GuiMissileTubeControls::onUpdate() float target_angle = missile_target_angle; if (!manual_aim) { - target_angle = my_spaceship->weapon_tube[n].calculateFiringSolution(my_spaceship->getTarget()); + target_angle = MissileSystem::calculateFiringSolution(my_spaceship->entity, tubes->mounts[n], my_spaceship->getTarget()->entity); if (target_angle == std::numeric_limits::infinity()) - target_angle = my_spaceship->getRotation() + my_spaceship->weapon_tube[n].getDirection(); + target_angle = my_spaceship->getRotation() + tubes->mounts[n].direction; } my_spaceship->commandFireTube(n, target_angle); } diff --git a/src/screenComponents/radarView.cpp b/src/screenComponents/radarView.cpp index a7adc47ce2..7e69dcebc7 100644 --- a/src/screenComponents/radarView.cpp +++ b/src/screenComponents/radarView.cpp @@ -5,6 +5,9 @@ #include "components/collision.h" #include "components/beamweapon.h" #include "components/hull.h" +#include "components/shields.h" +#include "components/missiletubes.h" +#include "systems/missilesystem.h" #include "main.h" #include "gameGlobalInfo.h" #include "spaceObjects/nebula.h" @@ -462,72 +465,75 @@ void GuiRadarView::drawTargetProjections(sp::RenderTarget& renderer) const float seconds_per_distance_tick = 5.0f; float scale = std::min(rect.size.x, rect.size.y) / 2.0f / distance; - if (my_spaceship && missile_tube_controls) - { - for(int n=0; nweapon_tube_count; n++) - { - if (!my_spaceship->weapon_tube[n].isLoaded()) - continue; - auto fire_position = my_spaceship->getPosition() + rotateVec2(my_spaceship->ship_template->model_data->getTubePosition2D(n), my_spaceship->getRotation()); - - const MissileWeaponData& data = MissileWeaponData::getDataFor(my_spaceship->weapon_tube[n].getLoadType()); - float fire_angle = my_spaceship->weapon_tube[n].getDirection() + (my_spaceship->getRotation()); - float missile_target_angle = fire_angle; - if (data.turnrate > 0.0f) + if (my_spaceship && missile_tube_controls) { + auto tubes = my_spaceship->entity.getComponent(); + if (tubes) { + for(int n=0; ncount; n++) { - if (missile_tube_controls->getManualAim()) + if (tubes->mounts[n].state != MissileTubes::MountPoint::State::Loaded) + continue; + auto& mount = tubes->mounts[n]; + auto fire_position = my_spaceship->getPosition() + rotateVec2(my_spaceship->ship_template->model_data->getTubePosition2D(n), my_spaceship->getRotation()); + + const MissileWeaponData& data = MissileWeaponData::getDataFor(mount.type_loaded); + float fire_angle = mount.direction + (my_spaceship->getRotation()); + float missile_target_angle = fire_angle; + if (data.turnrate > 0.0f) { - missile_target_angle = missile_tube_controls->getMissileTargetAngle(); - }else{ - float firing_solution = my_spaceship->weapon_tube[n].calculateFiringSolution(my_spaceship->getTarget()); - if (firing_solution != std::numeric_limits::infinity()) - missile_target_angle = firing_solution; + if (missile_tube_controls->getManualAim()) + { + missile_target_angle = missile_tube_controls->getMissileTargetAngle(); + }else if (my_spaceship->getTarget()) { + float firing_solution = MissileSystem::calculateFiringSolution(my_spaceship->entity, mount, my_spaceship->getTarget()->entity); + if (firing_solution != std::numeric_limits::infinity()) + missile_target_angle = firing_solution; + } } - } - float angle_diff = angleDifference(missile_target_angle, fire_angle); - float turn_radius = ((360.0f / data.turnrate) * data.speed) / (2.0f * float(M_PI)); - if (data.turnrate == 0.0f) - turn_radius = 0.0f; + float angle_diff = angleDifference(missile_target_angle, fire_angle); + float turn_radius = ((360.0f / data.turnrate) * data.speed) / (2.0f * float(M_PI)); + if (data.turnrate == 0.0f) + turn_radius = 0.0f; - float left_or_right = 90; - if (angle_diff > 0) - left_or_right = -90; + float left_or_right = 90; + if (angle_diff > 0) + left_or_right = -90; - auto turn_center = vec2FromAngle(fire_angle + left_or_right) * turn_radius; - auto turn_exit = turn_center + vec2FromAngle(missile_target_angle - left_or_right) * turn_radius; + auto turn_center = vec2FromAngle(fire_angle + left_or_right) * turn_radius; + auto turn_exit = turn_center + vec2FromAngle(missile_target_angle - left_or_right) * turn_radius; - float turn_distance = fabs(angle_diff) / 360.0f * (turn_radius * 2.0f * float(M_PI)); - float lifetime_after_turn = data.lifetime - turn_distance / data.speed; - float length_after_turn = data.speed * lifetime_after_turn; + float turn_distance = fabs(angle_diff) / 360.0f * (turn_radius * 2.0f * float(M_PI)); + float lifetime_after_turn = data.lifetime - turn_distance / data.speed; + float length_after_turn = data.speed * lifetime_after_turn; - std::vector missile_path; - missile_path.push_back(worldToScreen(fire_position)); - for(int cnt=0; cnt<10; cnt++) - missile_path.push_back(worldToScreen(fire_position + (turn_center + vec2FromAngle(fire_angle - angle_diff / 10.0f * cnt - left_or_right) * turn_radius))); - missile_path.push_back(worldToScreen(fire_position + turn_exit)); - missile_path.push_back(worldToScreen(fire_position + (turn_exit + vec2FromAngle(missile_target_angle) * length_after_turn))); - renderer.drawLine(missile_path, glm::u8vec4(255, 255, 255, 128)); + std::vector missile_path; + missile_path.push_back(worldToScreen(fire_position)); + for(int cnt=0; cnt<10; cnt++) + missile_path.push_back(worldToScreen(fire_position + (turn_center + vec2FromAngle(fire_angle - angle_diff / 10.0f * cnt - left_or_right) * turn_radius))); + missile_path.push_back(worldToScreen(fire_position + turn_exit)); + missile_path.push_back(worldToScreen(fire_position + (turn_exit + vec2FromAngle(missile_target_angle) * length_after_turn))); + renderer.drawLine(missile_path, glm::u8vec4(255, 255, 255, 128)); - float offset = seconds_per_distance_tick * data.speed; - for(int cnt=0; cntentity.getComponent(); + if (!tubes) return; + for(int n=0; ncount; n++) { - for(int n=0; nweapon_tube_count; n++) - { - auto fire_position = my_spaceship->getPosition() + rotateVec2(my_spaceship->ship_template->model_data->getTubePosition2D(n), my_spaceship->getRotation()); - auto fire_draw_position = worldToScreen(fire_position); + auto fire_position = my_spaceship->getPosition() + rotateVec2(my_spaceship->ship_template->model_data->getTubePosition2D(n), my_spaceship->getRotation()); + auto fire_draw_position = worldToScreen(fire_position); - float fire_angle = my_spaceship->getRotation() + my_spaceship->weapon_tube[n].getDirection() - view_rotation; + float fire_angle = my_spaceship->getRotation() + tubes->mounts[n].direction - view_rotation; - renderer.drawLine(fire_draw_position, fire_draw_position + (vec2FromAngle(fire_angle) * 1000.0f * scale), glm::u8vec4(128, 128, 128, 128), glm::u8vec4(128, 128, 128, 0)); - } + renderer.drawLine(fire_draw_position, fire_draw_position + (vec2FromAngle(fire_angle) * 1000.0f * scale), glm::u8vec4(128, 128, 128, 128), glm::u8vec4(128, 128, 128, 0)); } } @@ -796,8 +802,8 @@ void GuiRadarView::drawObjects(sp::RenderTarget& renderer) // Draw beam arcs on short-range radar only, and only for fully scanned // ships. if (!long_range) { - for(auto [entity, beamsystem, position, obj] : sp::ecs::Query()) { - auto object_position_on_screen = worldToScreen(position.getPosition()); + for(auto [entity, beamsystem, transform, obj] : sp::ecs::Query()) { + auto object_position_on_screen = worldToScreen(transform.getPosition()); if (!obj || (my_spaceship && (obj->getScannedStateFor(my_spaceship) != SS_FullScan))) continue; @@ -817,10 +823,10 @@ void GuiRadarView::drawObjects(sp::RenderTarget& renderer) float beam_range = mount.range; // Set the beam's origin on radar to its relative position on the mesh. - auto beam_offset = rotateVec2(glm::vec2(mount.position.x, mount.position.y) * scale, position.getRotation() - view_rotation); + auto beam_offset = rotateVec2(glm::vec2(mount.position.x, mount.position.y) * scale, transform.getRotation() - view_rotation); auto arc_center = beam_offset + object_position_on_screen; - draw_arc(arc_center, position.getRotation() - view_rotation + (beam_direction - beam_arc / 2.0f), beam_arc, beam_range * scale, color); + draw_arc(arc_center, transform.getRotation() - view_rotation + (beam_direction - beam_arc / 2.0f), beam_arc, beam_range * scale, color); // If the beam is turreted, draw the turret's arc. Otherwise, exit. @@ -835,13 +841,13 @@ void GuiRadarView::drawObjects(sp::RenderTarget& renderer) // TODO: Make this color configurable. color.a /= 4; - draw_arc(arc_center, position.getRotation() - view_rotation + (turret_direction - turret_arc / 2.0f), turret_arc, beam_range * scale, color); + draw_arc(arc_center, transform.getRotation() - view_rotation + (turret_direction - turret_arc / 2.0f), turret_arc, beam_range * scale, color); } } } - for(auto [entity, trace, position, obj] : sp::ecs::Query()) { - auto object_position_on_screen = worldToScreen(position.getPosition()); + for(auto [entity, trace, transform, obj] : sp::ecs::Query()) { + auto object_position_on_screen = worldToScreen(transform.getPosition()); //TODO: Only draw things that are in range of this radar view. auto size = trace.radius * scale * 2.0f; @@ -880,6 +886,68 @@ void GuiRadarView::drawObjects(sp::RenderTarget& renderer) renderer.drawSprite(icon, object_position_on_screen, size, color); } + if (!long_range) { + for(auto [entity, shields, transform, obj] : sp::ecs::Query()) { + //TODO: Only draw things that are in range of this radar view. + if (!shields.active) + continue; + auto object_position_on_screen = worldToScreen(transform.getPosition()); + bool show_levels = (!my_spaceship || obj->getScannedStateFor(my_spaceship) >= SS_SimpleScan); + float sprite_scale = scale * obj->getRadius() * 1.5f / 32; + + if (shields.count == 1) + { + glm::u8vec4 color = glm::u8vec4(255, 255, 255, 64); + if (show_levels) + { + float level = shields.entry[0].level / shields.entry[0].max; + color = Tween::linear(level, 1.0f, 0.0f, glm::u8vec4(128, 128, 255, 128), glm::u8vec4(255, 0, 0, 64)); + } + if (shields.entry[0].hit_effect > 0.0f) + { + color = Tween::linear(shields.entry[0].hit_effect, 0.0f, 1.0f, color, glm::u8vec4(255, 0, 0, 128)); + } + renderer.drawSprite("shield_circle.png", object_position_on_screen, sprite_scale * 0.25f * 1.5f * 256.0f, color); + }else if (shields.count > 1) { + float direction = transform.getRotation() - view_rotation; + float arc = 360.0f / float(shields.count); + + for(int n=0; n::linear(level, 1.0f, 0.0f, glm::u8vec4(128, 128, 255, 128), glm::u8vec4(255, 0, 0, 64)); + } + if (shield.hit_effect > 0.0f) + { + color = Tween::linear(shield.hit_effect, 0.0f, 1.0f, color, glm::u8vec4(255, 0, 0, 128)); + } + + glm::vec2 delta_a = vec2FromAngle(direction - arc / 2.0f); + glm::vec2 delta_b = vec2FromAngle(direction); + glm::vec2 delta_c = vec2FromAngle(direction + arc / 2.0f); + + auto p0 = object_position_on_screen + delta_b * sprite_scale * 32.0f * 0.05f; + renderer.drawTexturedQuad("shield_circle.png", + p0, + p0 + delta_a * sprite_scale * 32.0f * 1.5f, + p0 + delta_b * sprite_scale * 32.0f * 1.5f, + p0 + delta_c * sprite_scale * 32.0f * 1.5f, + glm::vec2(0.5, 0.5), + glm::vec2(0.5, 0.5) + delta_a * 0.5f, + glm::vec2(0.5, 0.5) + delta_b * 0.5f, + glm::vec2(0.5, 0.5) + delta_c * 0.5f, + color); + direction += arc; + } + } + } + } + + if (my_spaceship) { auto object_position_on_screen = worldToScreen(my_spaceship->getPosition()); diff --git a/src/screenComponents/shieldsEnableButton.cpp b/src/screenComponents/shieldsEnableButton.cpp index 313849bdfc..0db1c149ce 100644 --- a/src/screenComponents/shieldsEnableButton.cpp +++ b/src/screenComponents/shieldsEnableButton.cpp @@ -4,6 +4,7 @@ #include "spaceObjects/playerSpaceship.h" #include "powerDamageIndicator.h" #include "gameGlobalInfo.h" +#include "components/shields.h" #include "gui/gui2_togglebutton.h" #include "gui/gui2_progressbar.h" @@ -29,7 +30,12 @@ void GuiShieldsEnableButton::onDraw(sp::RenderTarget& target) { if (my_spaceship) { - if (my_spaceship->shield_calibration_delay > 0.0f) + auto shields = my_spaceship->entity.getComponent(); + if (!shields) { + button->hide(); + bar->hide(); + } + else if (my_spaceship->shield_calibration_delay > 0.0f) { button->hide(); bar->show(); @@ -38,11 +44,11 @@ void GuiShieldsEnableButton::onDraw(sp::RenderTarget& target) else { button->show(); - button->setValue(my_spaceship->shields_active); + button->setValue(shields->active); bar->hide(); - string shield_status=my_spaceship->shields_active ? tr("shields","ON") : tr("shields","OFF"); - if (gameGlobalInfo->use_beam_shield_frequencies) - button->setText(tr("{frequency} Shields: {status}").format({{"frequency", frequencyToString(my_spaceship->shield_frequency)}, {"status", shield_status}})); + string shield_status=shields->active ? tr("shields","ON") : tr("shields","OFF"); + if (gameGlobalInfo->use_beam_shield_frequencies && shields->frequency != -1) + button->setText(tr("{frequency} Shields: {status}").format({{"frequency", frequencyToString(shields->frequency)}, {"status", shield_status}})); else button->setText(tr("Shields: {status}").format({{"status", shield_status}})); } diff --git a/src/screens/crew6/engineeringScreen.cpp b/src/screens/crew6/engineeringScreen.cpp index 22647fc46e..44fca99e80 100644 --- a/src/screens/crew6/engineeringScreen.cpp +++ b/src/screens/crew6/engineeringScreen.cpp @@ -5,6 +5,8 @@ #include "components/reactor.h" #include "components/beamweapon.h" #include "components/hull.h" +#include "components/jumpdrive.h" +#include "components/shields.h" #include "screenComponents/shipInternalView.h" #include "screenComponents/selfDestructButton.h" @@ -325,38 +327,47 @@ void EngineeringScreen::onDraw(sp::RenderTarget& renderer) case SYS_Warp: addSystemEffect(tr("Warp drive speed"), toNearbyIntString(effectiveness * 100) + "%"); break; - case SYS_JumpDrive: - addSystemEffect(tr("Jump drive recharge rate"), toNearbyIntString(my_spaceship->getJumpDriveRechargeRate() * 100) + "%"); - addSystemEffect(tr("Jump drive jump speed"), toNearbyIntString(effectiveness * 100) + "%"); - break; - case SYS_FrontShield: - if (gameGlobalInfo->use_beam_shield_frequencies) - addSystemEffect(tr("shields","Calibration speed"), toNearbyIntString((my_spaceship->getSystemEffectiveness(SYS_FrontShield) + my_spaceship->getSystemEffectiveness(SYS_RearShield)) / 2.0f * 100) + "%"); - addSystemEffect(tr("shields","Charge rate"), toNearbyIntString(effectiveness * 100) + "%"); - { - DamageInfo di; - di.type = DT_Kinetic; - float damage_negate = 1.0f - my_spaceship->getShieldDamageFactor(di, 0); - if (damage_negate < 0.0f) - addSystemEffect(tr("Extra damage"), toNearbyIntString(-damage_negate * 100) + "%"); - else - addSystemEffect(tr("Damage negate"), toNearbyIntString(damage_negate * 100) + "%"); + case SYS_JumpDrive:{ + auto jump = my_spaceship->entity.getComponent(); + if (jump) { + addSystemEffect(tr("Jump drive recharge rate"), toNearbyIntString(jump->get_recharge_rate() * 100) + "%"); + addSystemEffect(tr("Jump drive jump speed"), toNearbyIntString(effectiveness * 100) + "%"); } - break; - case SYS_RearShield: - if (gameGlobalInfo->use_beam_shield_frequencies) - addSystemEffect(tr("shields","Calibration speed"), toNearbyIntString((my_spaceship->getSystemEffectiveness(SYS_FrontShield) + my_spaceship->getSystemEffectiveness(SYS_RearShield)) / 2.0f * 100) + "%"); - addSystemEffect(tr("shields","Charge rate"), toNearbyIntString(effectiveness * 100) + "%"); - { - DamageInfo di; - di.type = DT_Kinetic; - float damage_negate = 1.0f - my_spaceship->getShieldDamageFactor(di, my_spaceship->shield_count - 1); - if (damage_negate < 0.0f) - addSystemEffect(tr("Extra damage"), toNearbyIntString(-damage_negate * 100) + "%"); - else - addSystemEffect(tr("Damage negate"), toNearbyIntString(damage_negate * 100) + "%"); + }break; + case SYS_FrontShield:{ + auto shields = my_spaceship->entity.getComponent(); + if (shields) { + if (gameGlobalInfo->use_beam_shield_frequencies) + addSystemEffect(tr("shields","Calibration speed"), toNearbyIntString((shields->front_system.getSystemEffectiveness() + shields->rear_system.getSystemEffectiveness()) / 2.0f * 100) + "%"); + addSystemEffect(tr("shields","Charge rate"), toNearbyIntString(effectiveness * 100) + "%"); + { + DamageInfo di; + di.type = DT_Kinetic; + float damage_negate = 1.0f - my_spaceship->getShieldDamageFactor(di, 0); + if (damage_negate < 0.0f) + addSystemEffect(tr("Extra damage"), toNearbyIntString(-damage_negate * 100) + "%"); + else + addSystemEffect(tr("Damage negate"), toNearbyIntString(damage_negate * 100) + "%"); + } } - break; + }break; + case SYS_RearShield:{ + auto shields = my_spaceship->entity.getComponent(); + if (shields) { + if (gameGlobalInfo->use_beam_shield_frequencies) + addSystemEffect(tr("shields","Calibration speed"), toNearbyIntString((shields->front_system.getSystemEffectiveness() + shields->rear_system.getSystemEffectiveness()) / 2.0f * 100) + "%"); + addSystemEffect(tr("shields","Charge rate"), toNearbyIntString(effectiveness * 100) + "%"); + { + DamageInfo di; + di.type = DT_Kinetic; + float damage_negate = 1.0f - my_spaceship->getShieldDamageFactor(di, shields->count - 1); + if (damage_negate < 0.0f) + addSystemEffect(tr("Extra damage"), toNearbyIntString(-damage_negate * 100) + "%"); + else + addSystemEffect(tr("Damage negate"), toNearbyIntString(damage_negate * 100) + "%"); + } + } + }break; default: break; } diff --git a/src/screens/crew6/scienceScreen.cpp b/src/screens/crew6/scienceScreen.cpp index 2724b77a27..e0ce910b77 100644 --- a/src/screens/crew6/scienceScreen.cpp +++ b/src/screens/crew6/scienceScreen.cpp @@ -8,6 +8,7 @@ #include "multiplayer_client.h" #include "components/beamweapon.h" +#include "components/shields.h" #include "screenComponents/radarView.h" #include "screenComponents/rawScannerDataRadarOverlay.h" @@ -403,13 +404,13 @@ void ScienceScreen::onDraw(sp::RenderTarget& renderer) // populate their graphs. if (gameGlobalInfo->use_beam_shield_frequencies) { - info_shield_frequency->setFrequency(ship->shield_frequency); + auto shieldsystem = ship->entity.getComponent(); + info_shield_frequency->setFrequency(shieldsystem ? shieldsystem->frequency : -1); auto beamsystem = ship->entity.getComponent(); - if (beamsystem) - info_beam_frequency->setFrequency(beamsystem->frequency); + info_beam_frequency->setFrequency(beamsystem ? beamsystem->frequency : -1); // Show on graph information that target has no shields instead of frequencies. - info_shield_frequency->setEnemyHasEquipment(ship->getShieldCount() > 0); + info_shield_frequency->setEnemyHasEquipment(shieldsystem); // Show on graph information that target has no beams instad of frequencies. info_beam_frequency->setEnemyHasEquipment(beamsystem); diff --git a/src/screens/gm/tweak.cpp b/src/screens/gm/tweak.cpp index 95dd46ae8e..b3867a730b 100644 --- a/src/screens/gm/tweak.cpp +++ b/src/screens/gm/tweak.cpp @@ -260,8 +260,8 @@ GuiShipTweakMissileWeapons::GuiShipTweakMissileWeapons(GuiContainer* owner) { (new GuiLabel(left_col, "", getLocaleMissileWeaponName(EMissileWeapons(n)) + ":", 20))->setSize(GuiElement::GuiSizeMax, 30); missile_storage_amount_slider[n] = new GuiSlider(left_col, "", 0.0, 50, 0.0, [this, n](float value) { - target->weapon_storage_max[n] = int(round(value)); - target->weapon_storage[n] = std::min(target->weapon_storage[n], target->weapon_storage_max[n]); + //target->weapon_storage_max[n] = int(round(value)); + //target->weapon_storage[n] = std::min(target->weapon_storage[n], target->weapon_storage_max[n]); }); missile_storage_amount_slider[n]->addOverlay()->setSize(GuiElement::GuiSizeMax, 40); } @@ -273,7 +273,7 @@ GuiShipTweakMissileWeapons::GuiShipTweakMissileWeapons(GuiContainer* owner) { (new GuiLabel(right_col, "", getLocaleMissileWeaponName(EMissileWeapons(n)) + ":", 20))->setSize(GuiElement::GuiSizeMax, 30); missile_current_amount_slider[n] = new GuiSlider(right_col, "", 0.0, 50, 0.0, [this, n](float value) { - target->weapon_storage[n] = std::min(int(round(value)), target->weapon_storage_max[n]); + //target->weapon_storage[n] = std::min(int(round(value)), target->weapon_storage_max[n]); }); missile_current_amount_slider[n]->addOverlay()->setSize(GuiElement::GuiSizeMax, 40); } @@ -337,8 +337,8 @@ void GuiShipTweakMissileWeapons::onDraw(sp::RenderTarget& renderer) { for(int n=0; nweapon_storage[n] != int(missile_current_amount_slider[n]->getValue())) - missile_current_amount_slider[n]->setValue(float(target->weapon_storage[n])); + //if (target->weapon_storage[n] != int(missile_current_amount_slider[n]->getValue())) + // missile_current_amount_slider[n]->setValue(float(target->weapon_storage[n])); } } @@ -347,8 +347,8 @@ void GuiShipTweakMissileWeapons::open(P target) P ship = target; this->target = ship; - for(int n = 0; n < MW_Count; n++) - missile_storage_amount_slider[n]->setValue(float(ship->weapon_storage_max[n])); + //for(int n = 0; n < MW_Count; n++) + // missile_storage_amount_slider[n]->setValue(float(ship->weapon_storage_max[n])); } GuiShipTweakMissileTubes::GuiShipTweakMissileTubes(GuiContainer* owner) @@ -363,7 +363,7 @@ GuiShipTweakMissileTubes::GuiShipTweakMissileTubes(GuiContainer* owner) // Left column (new GuiLabel(left_col, "", tr("Tube count:"), 30))->setSize(GuiElement::GuiSizeMax, 50); missile_tube_amount_selector = new GuiSelector(left_col, "", [this](int index, string value) { - target->weapon_tube_count = index; + //target->weapon_tube_count = index; }); for(int n=0; naddEntry(string(n), ""); @@ -373,6 +373,7 @@ GuiShipTweakMissileTubes::GuiShipTweakMissileTubes(GuiContainer* owner) tube_index = 0; index_selector = new GuiSelector(right_col, "", [this](int index, string value) { + /* if (index >= target->weapon_tube_count) { if (index == max_weapon_tubes - 1) @@ -381,6 +382,7 @@ GuiShipTweakMissileTubes::GuiShipTweakMissileTubes(GuiContainer* owner) index = 0; index_selector->setSelectionIndex(index); } + */ tube_index = index; }); index_selector->setSize(GuiElement::GuiSizeMax, 40); @@ -390,20 +392,20 @@ GuiShipTweakMissileTubes::GuiShipTweakMissileTubes(GuiContainer* owner) (new GuiLabel(right_col, "", tr("tube", "Direction:"), 20))->setSize(GuiElement::GuiSizeMax, 30); direction_slider = new GuiSlider(right_col, "", -180.0, 180, 0.0, [this](float value) { - target->weapon_tube[tube_index].setDirection(roundf(value)); + //target->weapon_tube[tube_index].setDirection(roundf(value)); }); direction_slider->addOverlay()->setSize(GuiElement::GuiSizeMax, 40); (new GuiLabel(right_col, "", tr("tube", "Load time:"), 20))->setSize(GuiElement::GuiSizeMax, 30); load_time_slider = new GuiSlider(right_col, "", 0.0, 60.0, 0.0, [this](float value) { - target->weapon_tube[tube_index].setLoadTimeConfig(roundf(value * 10) / 10); + //target->weapon_tube[tube_index].setLoadTimeConfig(roundf(value * 10) / 10); }); load_time_slider->addOverlay()->setSize(GuiElement::GuiSizeMax, 40); (new GuiLabel(right_col, "", tr("tube", "Size:"), 20))->setSize(GuiElement::GuiSizeMax, 30); size_selector=new GuiSelector(right_col, "", [this](int index, string value) { - target->weapon_tube[tube_index].setSize(EMissileSizes(index)); + //target->weapon_tube[tube_index].setSize(EMissileSizes(index)); }); size_selector->addEntry(tr("tube", "Small"),MS_Small); size_selector->addEntry(tr("tube", "Medium"),MS_Medium); @@ -415,10 +417,10 @@ GuiShipTweakMissileTubes::GuiShipTweakMissileTubes(GuiContainer* owner) for(int n=0; nweapon_tube[tube_index].allowLoadOf(EMissileWeapons(n)); - else - target->weapon_tube[tube_index].disallowLoadOf(EMissileWeapons(n)); + //if (value) + // target->weapon_tube[tube_index].allowLoadOf(EMissileWeapons(n)); + //else + // target->weapon_tube[tube_index].disallowLoadOf(EMissileWeapons(n)); }); allowed_use[n]->setSize(GuiElement::GuiSizeMax, 40); } @@ -426,13 +428,13 @@ GuiShipTweakMissileTubes::GuiShipTweakMissileTubes(GuiContainer* owner) void GuiShipTweakMissileTubes::onDraw(sp::RenderTarget& renderer) { - direction_slider->setValue(angleDifference(0.0f, target->weapon_tube[tube_index].getDirection())); - load_time_slider->setValue(target->weapon_tube[tube_index].getLoadTimeConfig()); + //direction_slider->setValue(angleDifference(0.0f, target->weapon_tube[tube_index].getDirection())); + //load_time_slider->setValue(target->weapon_tube[tube_index].getLoadTimeConfig()); for(int n=0; nsetValue(target->weapon_tube[tube_index].canLoad(EMissileWeapons(n))); + //allowed_use[n]->setValue(target->weapon_tube[tube_index].canLoad(EMissileWeapons(n))); } - size_selector->setSelectionIndex(target->weapon_tube[tube_index].getSize()); + //size_selector->setSelectionIndex(target->weapon_tube[tube_index].getSize()); } void GuiShipTweakMissileTubes::open(P target) @@ -440,7 +442,7 @@ void GuiShipTweakMissileTubes::open(P target) P ship = target; this->target = ship; - missile_tube_amount_selector->setSelectionIndex(ship->weapon_tube_count); + //missile_tube_amount_selector->setSelectionIndex(ship->weapon_tube_count); } GuiShipTweakShields::GuiShipTweakShields(GuiContainer* owner) @@ -456,8 +458,8 @@ GuiShipTweakShields::GuiShipTweakShields(GuiContainer* owner) { (new GuiLabel(left_col, "", tr("Shield {id_shield} max:").format({{"id_shield", string(n + 1)}}), 20))->setSize(GuiElement::GuiSizeMax, 30); shield_max_slider[n] = new GuiSlider(left_col, "", 0.0, 500, 0.0, [this, n](float value) { - target->shield_max[n] = round(value); - target->shield_level[n] = std::min(target->shield_level[n], target->shield_max[n]); + //target->shield_max[n] = round(value); + //target->shield_level[n] = std::min(target->shield_level[n], target->shield_max[n]); }); shield_max_slider[n]->addOverlay()->setSize(GuiElement::GuiSizeMax, 40); } @@ -466,7 +468,7 @@ GuiShipTweakShields::GuiShipTweakShields(GuiContainer* owner) { (new GuiLabel(right_col, "", tr("Shield {id_shield}:").format({{"id_shield", string(n + 1)}}), 20))->setSize(GuiElement::GuiSizeMax, 30); shield_slider[n] = new GuiSlider(right_col, "", 0.0, 500, 0.0, [this, n](float value) { - target->shield_level[n] = std::min(roundf(value), target->shield_max[n]); + //target->shield_level[n] = std::min(roundf(value), target->shield_max[n]); }); shield_slider[n]->addOverlay()->setSize(GuiElement::GuiSizeMax, 40); } @@ -476,10 +478,11 @@ void GuiShipTweakShields::onDraw(sp::RenderTarget& renderer) { for(int n=0; nsetValue(target->shield_level[n]); - shield_max_slider[n]->setValue(target->shield_max[n]); + //shield_slider[n]->setValue(target->shield_level[n]); + //shield_max_slider[n]->setValue(target->shield_max[n]); // Set range to 0 on all unused shields, since values set there by GM are not reflected by the game anyways. + /* if(target->shield_count>n) { shield_slider[n]->setRange(0.0, 500); shield_max_slider[n]->setRange(0.0, 500); @@ -488,6 +491,7 @@ void GuiShipTweakShields::onDraw(sp::RenderTarget& renderer) shield_slider[n]->setRange(0.0, 0); shield_max_slider[n]->setRange(0.0, 0); } + */ } } diff --git a/src/spaceObjects/missiles/missileWeapon.cpp b/src/spaceObjects/missiles/missileWeapon.cpp index cd6e40e2bf..4bc02065ba 100644 --- a/src/spaceObjects/missiles/missileWeapon.cpp +++ b/src/spaceObjects/missiles/missileWeapon.cpp @@ -36,12 +36,11 @@ REGISTER_SCRIPT_SUBCLASS_NO_CREATE(MissileWeapon, SpaceObject) MissileWeapon::MissileWeapon(string multiplayer_name, const MissileWeaponData& data) : SpaceObject(10, multiplayer_name), data(data) { - target_id = -1; target_angle = 0; category_modifier = 1; lifetime = data.lifetime; - registerMemberReplication(&target_id); + registerMemberReplication(&target); registerMemberReplication(&target_angle); registerMemberReplication(&category_modifier); @@ -107,15 +106,7 @@ void MissileWeapon::updateMovement() { if (data.homing_range > 0) { - P target; - if (game_server) - { - target = game_server->getObjectById(target_id); - } - else - { - target = game_client->getObjectById(target_id); - } + P target = getTarget(); if (target) { @@ -157,9 +148,9 @@ P MissileWeapon::getOwner() P MissileWeapon::getTarget() { - if (game_server) - return game_server->getObjectById(target_id); - return game_client->getObjectById(target_id); + auto obj = this->target.getComponent(); + if (obj) return *obj; + return nullptr; } void MissileWeapon::setTarget(P target) @@ -168,7 +159,7 @@ void MissileWeapon::setTarget(P target) { return; } - target_id = target->getMultiplayerId(); + this->target = target->entity; } float MissileWeapon::getLifetime() @@ -200,12 +191,12 @@ std::unordered_map MissileWeapon::getGMInfo() ret[trMark("gm_info", "Owner")] = owner->getCallSign(); } - P target = game_server->getObjectById(target_id); + /*P target = game_server->getObjectById(target_id); if (target) { ret[trMark("gm_info", "Target")] = target->getCallSign(); - } + }*/ ret[trMark("gm_info", "Faction")] = getLocaleFaction(); ret[trMark("gm_info", "Lifetime")] = lifetime; diff --git a/src/spaceObjects/missiles/missileWeapon.h b/src/spaceObjects/missiles/missileWeapon.h index f57fbb2273..7f6a4acb06 100644 --- a/src/spaceObjects/missiles/missileWeapon.h +++ b/src/spaceObjects/missiles/missileWeapon.h @@ -15,7 +15,7 @@ class MissileWeapon : public SpaceObject, public Updatable public: P owner; //Only valid on server. - int32_t target_id; + sp::ecs::Entity target; float target_angle; // Damage modifier for this missile which indicates it's size. (eg; Missiles by fighters have a low modifier), missiles from // capital ships have a high modifier. diff --git a/src/spaceObjects/playerSpaceship.cpp b/src/spaceObjects/playerSpaceship.cpp index c48041c3ef..84ee965d35 100644 --- a/src/spaceObjects/playerSpaceship.cpp +++ b/src/spaceObjects/playerSpaceship.cpp @@ -14,8 +14,11 @@ #include "components/beamweapon.h" #include "components/warpdrive.h" #include "components/jumpdrive.h" +#include "components/shields.h" +#include "components/missiletubes.h" #include "systems/jumpsystem.h" #include "systems/docking.h" +#include "systems/missilesystem.h" #include "scriptInterface.h" @@ -1184,8 +1187,9 @@ void PlayerSpaceship::onReceiveClientCommand(int32_t client_id, sp::io::DataBuff EMissileWeapons type; packet >> tube_nr >> type; - if (tube_nr >= 0 && tube_nr < max_weapon_tubes) - weapon_tube[tube_nr].startLoad(type); + auto missiletubes = entity.getComponent(); + if (missiletubes && tube_nr >= 0 && tube_nr < missiletubes->count) + MissileSystem::startLoad(entity, missiletubes->mounts[tube_nr], type); } break; case CMD_UNLOAD_TUBE: @@ -1193,10 +1197,9 @@ void PlayerSpaceship::onReceiveClientCommand(int32_t client_id, sp::io::DataBuff int8_t tube_nr; packet >> tube_nr; - if (tube_nr >= 0 && tube_nr < max_weapon_tubes) - { - weapon_tube[tube_nr].startUnload(); - } + auto missiletubes = entity.getComponent(); + if (missiletubes && tube_nr >= 0 && tube_nr < missiletubes->count) + MissileSystem::startUnload(entity, missiletubes->mounts[tube_nr]); } break; case CMD_FIRE_TUBE: @@ -1205,8 +1208,9 @@ void PlayerSpaceship::onReceiveClientCommand(int32_t client_id, sp::io::DataBuff float missile_target_angle; packet >> tube_nr >> missile_target_angle; - if (tube_nr >= 0 && tube_nr < max_weapon_tubes) - weapon_tube[tube_nr].fire(missile_target_angle); + auto missiletubes = entity.getComponent(); + if (missiletubes && tube_nr >= 0 && tube_nr < missiletubes->count) + MissileSystem::fire(entity, missiletubes->mounts[tube_nr], missile_target_angle, getTarget() ? getTarget()->entity : sp::ecs::Entity{}); } break; case CMD_SET_SHIELDS: @@ -1447,15 +1451,16 @@ void PlayerSpaceship::onReceiveClientCommand(int32_t client_id, sp::io::DataBuff { int32_t new_frequency; packet >> new_frequency; - if (new_frequency != shield_frequency) + auto shields = entity.getComponent(); + if (shields && new_frequency != shields->frequency) { - shield_frequency = new_frequency; + shields->frequency = new_frequency; shield_calibration_delay = shield_calibration_time; - shields_active = false; - if (shield_frequency < 0) - shield_frequency = 0; - if (shield_frequency > SpaceShip::max_frequency) - shield_frequency = SpaceShip::max_frequency; + shields->active = false; + if (shields->frequency < 0) + shields->frequency = 0; + if (shields->frequency > SpaceShip::max_frequency) + shields->frequency = SpaceShip::max_frequency; } } break; @@ -1696,14 +1701,14 @@ void PlayerSpaceship::commandFireTube(int8_t tubeNumber, float missile_target_an void PlayerSpaceship::commandFireTubeAtTarget(int8_t tubeNumber, P target) { float targetAngle = 0.0; + auto missiletubes = entity.getComponent(); - if (!target || tubeNumber < 0 || tubeNumber >= getWeaponTubeCount()) + if (!target || !missiletubes || tubeNumber < 0 || tubeNumber >= missiletubes->count) return; - targetAngle = weapon_tube[tubeNumber].calculateFiringSolution(target); - + targetAngle = MissileSystem::calculateFiringSolution(entity, missiletubes->mounts[tubeNumber], target->entity); if (targetAngle == std::numeric_limits::infinity()) - targetAngle = getRotation() + weapon_tube[tubeNumber].getDirection(); + targetAngle = getRotation() + missiletubes->mounts[tubeNumber].direction; commandFireTube(tubeNumber, targetAngle); } diff --git a/src/spaceObjects/shipTemplateBasedObject.cpp b/src/spaceObjects/shipTemplateBasedObject.cpp index 0b577f4d7a..b2cf0c6157 100644 --- a/src/spaceObjects/shipTemplateBasedObject.cpp +++ b/src/spaceObjects/shipTemplateBasedObject.cpp @@ -5,6 +5,7 @@ #include "components/docking.h" #include "components/impulse.h" #include "components/hull.h" +#include "components/shields.h" #include "tween.h" #include "i18n.h" @@ -114,103 +115,35 @@ ShipTemplateBasedObject::ShipTemplateBasedObject(float collision_range, string m { entity.getOrAddComponent().setCircle(sp::Physics::Type::Dynamic, collision_range); - shield_count = 0; - for(int n=0; n::linear(level, 1.0f, 0.0f, glm::u8vec4(128, 128, 255, 128), glm::u8vec4(255, 0, 0, 64)); - } - if (shield_hit_effect[0] > 0.0f) - { - color = Tween::linear(shield_hit_effect[0], 0.0f, 1.0f, color, glm::u8vec4(255, 0, 0, 128)); - } - renderer.drawSprite("shield_circle.png", position, sprite_scale * 0.25f * 1.5f * 256.0f, color); - }else if (shield_count > 1) { - float direction = getRotation()-rotation; - float arc = 360.0f / float(shield_count); - - for(int n=0; n::linear(level, 1.0f, 0.0f, glm::u8vec4(128, 128, 255, 128), glm::u8vec4(255, 0, 0, 64)); - } - if (shield_hit_effect[n] > 0.0f) - { - color = Tween::linear(shield_hit_effect[n], 0.0f, 1.0f, color, glm::u8vec4(255, 0, 0, 128)); - } - - glm::vec2 delta_a = vec2FromAngle(direction - arc / 2.0f); - glm::vec2 delta_b = vec2FromAngle(direction); - glm::vec2 delta_c = vec2FromAngle(direction + arc / 2.0f); - - auto p0 = position + delta_b * sprite_scale * 32.0f * 0.05f; - renderer.drawTexturedQuad("shield_circle.png", - p0, - p0 + delta_a * sprite_scale * 32.0f * 1.5f, - p0 + delta_b * sprite_scale * 32.0f * 1.5f, - p0 + delta_c * sprite_scale * 32.0f * 1.5f, - glm::vec2(0.5, 0.5), - glm::vec2(0.5, 0.5) + delta_a * 0.5f, - glm::vec2(0.5, 0.5) + delta_b * 0.5f, - glm::vec2(0.5, 0.5) + delta_c * 0.5f, - color); - direction += arc; - } - } -} - void ShipTemplateBasedObject::draw3DTransparent() { - if (shield_count < 1) + auto shields = entity.getComponent(); + if (!shields) return; float angle = 0.0; - float arc = 360.0f / shield_count; + float arc = 360.0f / shields->count; const auto model_matrix = getModelMatrix(); - for(int n = 0; ncount; n++) { - if (shield_hit_effect[n] > 0) + if (shields->entry[n].hit_effect > 0) { - if (shield_count > 1) + if (shields->count > 1) { - model_info.renderShield(model_matrix, (shield_level[n] / shield_max[n]) * shield_hit_effect[n], angle); + model_info.renderShield(model_matrix, (shields->entry[n].level / shields->entry[n].max) * shields->entry[n].hit_effect, angle); }else{ - model_info.renderShield(model_matrix, (shield_level[n] / shield_max[n]) * shield_hit_effect[n]); + model_info.renderShield(model_matrix, (shields->entry[n].level / shields->entry[n].max) * shields->entry[n].hit_effect); } } angle += arc; @@ -238,18 +171,6 @@ void ShipTemplateBasedObject::update(float delta) ship_template->setCollisionData(this); model_info.setData(ship_template->model_data); } - - for(int n=0; n 0) - { - shield_hit_effect[n] -= delta; - } - } } std::unordered_map ShipTemplateBasedObject::getGMInfo() @@ -258,44 +179,39 @@ std::unordered_map ShipTemplateBasedObject::getGMInfo() ret[trMark("gm_info", "CallSign")] = callsign; ret[trMark("gm_info", "Type")] = type_name; //ret[trMark("gm_info", "Hull")] = string(hull_strength) + "/" + string(hull_max); - for(int n=0; n(); } void ShipTemplateBasedObject::takeDamage(float damage_amount, DamageInfo info) { - if (shield_count > 0 && getShieldsActive()) - { + auto shields = entity.getComponent(); + if (shields && shields->active) { float angle = angleDifference(getRotation(), vec2ToAngle(info.location - getPosition())); if (angle < 0) angle += 360.0f; - float arc = 360.0f / float(shield_count); + float arc = 360.0f / float(shields->count); int shield_index = int((angle + arc / 2.0f) / arc); - shield_index %= shield_count; + shield_index %= shields->count; + auto& shield = shields->entry[shield_index]; float shield_damage = damage_amount * getShieldDamageFactor(info, shield_index); - damage_amount -= shield_level[shield_index]; - shield_level[shield_index] -= shield_damage; - if (shield_level[shield_index] < 0) + damage_amount -= shield.level; + shield.level -= shield_damage; + if (shield.level < 0) { - shield_level[shield_index] = 0.0; + shield.level = 0.0; } else { - shield_hit_effect[shield_index] = 1.0; + shield.hit_effect = 1.0; } if (damage_amount < 0.0f) { @@ -354,11 +270,6 @@ float ShipTemplateBasedObject::getShieldDamageFactor(DamageInfo& info, int shiel return 1.0f; } -float ShipTemplateBasedObject::getShieldRechargeRate(int shield_index) -{ - return 0.3; -} - void ShipTemplateBasedObject::setCanBeDestroyed(bool enabled) { /*TODO*/ } bool ShipTemplateBasedObject::getCanBeDestroyed() { return true; } @@ -374,18 +285,21 @@ void ShipTemplateBasedObject::setTemplate(string template_name) ship_template = new_ship_template; type_name = template_name; - shield_count = ship_template->shield_count; - for(int n=0; nshield_level[n]; - // Set the ship's radar ranges. long_range_radar_range = ship_template->long_range_radar_range; short_range_radar_range = ship_template->short_range_radar_range; if (entity) { - auto hull = entity.getOrAddComponent(); + auto& hull = entity.getOrAddComponent(); hull.current = hull.max = ship_template->hull; + if (ship_template->shield_count) { + auto& shields = entity.getOrAddComponent(); + shields.count = ship_template->shield_count; + for(int n=0; nshield_level[n]; + } + auto& trace = entity.getOrAddComponent(); trace.radius = ship_template->model_data->getRadius() * 0.8f; trace.icon = ship_template->radar_trace; @@ -404,7 +318,6 @@ void ShipTemplateBasedObject::setTemplate(string template_name) if (ship_template->repair_docked) bay->flags |= DockingBay::Repair; } - if (ship_template->can_dock) { if (!ship_template->getClass().empty()) @@ -423,30 +336,12 @@ void ShipTemplateBasedObject::setTemplate(string template_name) void ShipTemplateBasedObject::setShields(const std::vector& amounts) { - for(int n=0; n& amounts) { - shield_count = std::min(max_shield_count, int(amounts.size())); - for(int n=0; n 0) data += ":"; data += string(int(shield_level[n])); } + */ return data; } diff --git a/src/spaceObjects/shipTemplateBasedObject.h b/src/spaceObjects/shipTemplateBasedObject.h index 2a851858b5..c2a13af452 100644 --- a/src/spaceObjects/shipTemplateBasedObject.h +++ b/src/spaceObjects/shipTemplateBasedObject.h @@ -22,16 +22,10 @@ class ShipTemplateBasedObject : public SpaceObject, public Updatable string type_name; P ship_template; - int shield_count; - float shield_level[max_shield_count]; - float shield_max[max_shield_count]; - float shield_hit_effect[max_shield_count]; - public: ShipTemplateBasedObject(float collision_range, string multiplayer_name, float multiplayer_significant_range=-1); virtual void draw3DTransparent() override; - virtual void drawShieldsOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, float sprite_scale, bool show_levels); virtual void update(float delta) override; virtual std::unordered_map getGMInfo() override; @@ -47,7 +41,6 @@ class ShipTemplateBasedObject : public SpaceObject, public Updatable bool getCanBeDestroyed(); virtual void applyTemplateValues() = 0; - virtual float getShieldRechargeRate(int shield_index); void setTemplate(string template_name); void setShipTemplate(string template_name) { LOG(WARNING) << "Deprecated \"setShipTemplate\" function called."; setTemplate(template_name); } @@ -61,24 +54,23 @@ class ShipTemplateBasedObject : public SpaceObject, public Updatable virtual bool getShieldsActive() { return true; } ///Shield script binding functions - float getShieldLevel(int index) { if (index < 0 || index >= shield_count) return 0; return shield_level[index]; } - float getShieldMax(int index) { if (index < 0 || index >= shield_count) return 0; return shield_max[index]; } - int getShieldCount() { return shield_count; } + float getShieldLevel(int index) { /*TODO*/ return 0.0f; } + float getShieldMax(int index) { /*TODO*/ return 0.0f; } + int getShieldCount() { /*TODO*/ return 0; } void setShields(const std::vector& amounts); void setShieldsMax(const std::vector& amounts); - int getShieldPercentage(int index) { if (index < 0 || index >= shield_count || shield_max[index] <= 0.0f) return 0; return int(100 * shield_level[index] / shield_max[index]); } - ESystem getShieldSystemForShieldIndex(int index); + int getShieldPercentage(int index) { /*TODO*/ return 0; } ///Deprecated old script functions for shields - float getFrontShield() { return shield_level[0]; } - float getFrontShieldMax() { return shield_max[0]; } - void setFrontShield(float amount) { if (amount < 0) return; shield_level[0] = amount; } - void setFrontShieldMax(float amount) { if (amount < 0) return; shield_level[0] = amount; shield_level[0] = std::min(shield_level[0], shield_max[0]); } - float getRearShield() { return shield_level[1]; } - float getRearShieldMax() { return shield_max[1]; } - void setRearShield(float amount) { if (amount < 0) return; shield_level[1] = amount; } - void setRearShieldMax(float amount) { if (amount < 0) return; shield_max[1] = amount; shield_level[1] = std::min(shield_level[1], shield_max[1]); } + float getFrontShield() { /*TODO*/ return 0.0f; } + float getFrontShieldMax() { /*TODO*/ return 0.0f; } + void setFrontShield(float amount) { } //TODO + void setFrontShieldMax(float amount) { } //TODO + float getRearShield() { /*TODO*/ return 0.0f; } + float getRearShieldMax() { /*TODO*/ return 0.0f; } + void setRearShield(float amount) { } //TODO + void setRearShieldMax(float amount) { } //TODO // Radar range float getLongRangeRadarRange() { return long_range_radar_range; } diff --git a/src/spaceObjects/spaceObject.cpp b/src/spaceObjects/spaceObject.cpp index 48323be581..89e5e82993 100644 --- a/src/spaceObjects/spaceObject.cpp +++ b/src/spaceObjects/spaceObject.cpp @@ -294,7 +294,7 @@ SpaceObject::SpaceObject(float collision_range, string multiplayer_name, float m if (isServer()) { entity = sp::ecs::Entity::create(); //TODO: multiplayer_significant_range - entity.addComponent(); + entity.addComponent(); entity.addComponent().setCircle(sp::Physics::Type::Sensor, collision_range); } @@ -504,11 +504,11 @@ void SpaceObject::damageArea(glm::vec2 position, float blast_range, float min_da { auto ptr = entity.getComponent(); if (!ptr) continue; - auto pos = entity.getComponent(); - if (!pos) continue; + auto transform = entity.getComponent(); + if (!transform) continue; P obj = *ptr; - float dist = glm::length(position - pos->getPosition()) - obj->getRadius() - min_range; + float dist = glm::length(position - transform->getPosition()) - obj->getRadius() - min_range; if (dist < 0) dist = 0; if (dist < blast_range - min_range) { @@ -523,7 +523,7 @@ bool SpaceObject::areEnemiesInRange(float range) { auto ptr = entity.getComponent(); if (!ptr) continue; - auto pos = entity.getComponent(); + auto pos = entity.getComponent(); if (!pos) continue; P obj = *ptr; if (obj && isEnemy(obj)) @@ -543,7 +543,7 @@ PVector SpaceObject::getObjectsInRange(float range) { auto ptr = entity.getComponent(); if (!ptr) continue; - auto pos = entity.getComponent(); + auto pos = entity.getComponent(); if (!pos) continue; P obj = *ptr; auto r = range + obj->getRadius(); @@ -635,7 +635,7 @@ bool SpaceObject::sendCommsMessageNoLog(P target, string messag glm::vec2 SpaceObject::getPosition() const { if (!entity) return {}; - const auto position = entity.getComponent(); + const auto position = entity.getComponent(); if (!position) return {}; return position->getPosition(); } @@ -643,7 +643,7 @@ glm::vec2 SpaceObject::getPosition() const void SpaceObject::setPosition(glm::vec2 p) { if (!entity) return; - auto position = entity.getComponent(); + auto position = entity.getComponent(); if (!position) return; position->setPosition(p); } @@ -651,7 +651,7 @@ void SpaceObject::setPosition(glm::vec2 p) float SpaceObject::getRotation() const { if (!entity) return {}; - auto position = entity.getComponent(); + auto position = entity.getComponent(); if (!position) return {}; return position->getRotation(); } @@ -659,7 +659,7 @@ float SpaceObject::getRotation() const void SpaceObject::setRotation(float a) { if (!entity) return; - auto position = entity.getComponent(); + auto position = entity.getComponent(); if (!position) return; position->setRotation(a); } diff --git a/src/spaceObjects/spaceStation.cpp b/src/spaceObjects/spaceStation.cpp index 0e564f614f..1ab3f3f57a 100644 --- a/src/spaceObjects/spaceStation.cpp +++ b/src/spaceObjects/spaceStation.cpp @@ -4,6 +4,7 @@ #include "spaceObjects/playerSpaceship.h" #include "components/collision.h" #include "components/hull.h" +#include "components/shields.h" #include "shipTemplate.h" #include "playerInfo.h" #include "factionInfo.h" @@ -33,17 +34,6 @@ SpaceStation::SpaceStation() } } -void SpaceStation::drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) -{ - float sprite_scale = scale * getRadius() * 1.5f / 32; - - if (!long_range) - { - sprite_scale *= 0.7f; - drawShieldsOnRadar(renderer, position, scale, rotation, sprite_scale, true); - } -} - void SpaceStation::applyTemplateValues() { PathPlannerManager::getInstance()->addAvoidObject(this, getRadius() * 1.5f); @@ -59,13 +49,14 @@ void SpaceStation::destroyedByDamage(DamageInfo& info) if (info.instigator) { float points = 0; - if (shield_count > 0) + auto shields = entity.getComponent(); + if (shields) { - for(int n=0; ncount; n++) { - points += shield_max[n] * 0.1f; + points += shields->entry[n].max * 0.1f; } - points /= shield_count; + points /= shields->count; } auto hull = entity.getComponent(); if (hull) diff --git a/src/spaceObjects/spaceStation.h b/src/spaceObjects/spaceStation.h index 06900bd1cc..89e27373a1 100644 --- a/src/spaceObjects/spaceStation.h +++ b/src/spaceObjects/spaceStation.h @@ -8,7 +8,6 @@ class SpaceStation : public ShipTemplateBasedObject public: SpaceStation(); - virtual void drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) override; virtual void destroyedByDamage(DamageInfo& info) override; virtual void applyTemplateValues() override; diff --git a/src/spaceObjects/spaceship.cpp b/src/spaceObjects/spaceship.cpp index 89eae7134d..4a9a19d093 100644 --- a/src/spaceObjects/spaceship.cpp +++ b/src/spaceObjects/spaceship.cpp @@ -23,7 +23,9 @@ #include "components/jumpdrive.h" #include "components/reactor.h" #include "components/beamweapon.h" +#include "components/shields.h" #include "components/hull.h" +#include "components/missiletubes.h" #include "scriptInterface.h" @@ -184,7 +186,6 @@ SpaceShip::SpaceShip(string multiplayerClassName, float multiplayer_significant_ { target_rotation = getRotation(); wormhole_alpha = 0.f; - weapon_tube_count = 0; turn_speed = 10.f; combat_maneuver_charge = 1.f; combat_maneuver_boost_request = 0.f; @@ -194,16 +195,13 @@ SpaceShip::SpaceShip(string multiplayerClassName, float multiplayer_significant_ combat_maneuver_boost_speed = 0.0f; combat_maneuver_strafe_speed = 0.0f; target_id = -1; - shield_frequency = irandom(0, max_frequency); turnSpeed = 0.0f; registerMemberReplication(&target_rotation, 1.5f); registerMemberReplication(&turnSpeed, 0.1f); registerMemberReplication(&wormhole_alpha, 0.5f); - registerMemberReplication(&weapon_tube_count); registerMemberReplication(&target_id); registerMemberReplication(&turn_speed); - registerMemberReplication(&shield_frequency); registerMemberReplication(&combat_maneuver_charge, 0.5f); registerMemberReplication(&combat_maneuver_boost_request); registerMemberReplication(&combat_maneuver_boost_active, 0.2f); @@ -233,20 +231,6 @@ SpaceShip::SpaceShip(string multiplayerClassName, float multiplayer_significant_ registerMemberReplication(&systems[n].hacked_level, 0.1f); } - for(int n = 0; n < max_weapon_tubes; n++) - { - weapon_tube[n].setParent(this); - weapon_tube[n].setIndex(n); - } - - for(int n = 0; n < MW_Count; n++) - { - weapon_storage[n] = 0; - weapon_storage_max[n] = 0; - registerMemberReplication(&weapon_storage[n]); - registerMemberReplication(&weapon_storage_max[n]); - } - scanning_complexity_value = -1; scanning_depth_value = -1; @@ -260,6 +244,10 @@ SpaceShip::SpaceShip(string multiplayerClassName, float multiplayer_significant_ if (entity) { auto& trace = entity.getOrAddComponent(); trace.flags |= RadarTrace::ArrowIfNotScanned; + + auto shields = entity.getComponent(); + if (shields) + shields->frequency = irandom(0, max_frequency); } } @@ -289,7 +277,6 @@ void SpaceShip::applyTemplateValues() mount.heat_per_beam_fire = ship_template->beams[n].getHeatPerFire(); } } - weapon_tube_count = ship_template->weapon_tube_count; if (ship_template->energy_storage_amount) { auto& reactor = entity.getOrAddComponent(); @@ -319,22 +306,20 @@ void SpaceShip::applyTemplateValues() jump.min_distance = ship_template->jump_drive_min_distance; jump.max_distance = ship_template->jump_drive_max_distance; } - for(int n=0; nweapon_tube[n].load_time); - weapon_tube[n].setDirection(ship_template->weapon_tube[n].direction); - weapon_tube[n].setSize(ship_template->weapon_tube[n].size); - for(int m=0; mweapon_tube_count) { + auto& tubes = entity.getOrAddComponent(); + tubes.count = ship_template->weapon_tube_count; + for(int n=0; nweapon_tube_count; n++) { - if (ship_template->weapon_tube[n].type_allowed_mask & (1 << m)) - weapon_tube[n].allowLoadOf(EMissileWeapons(m)); - else - weapon_tube[n].disallowLoadOf(EMissileWeapons(m)); + auto& tube = tubes.mounts[n]; + tube.load_time = ship_template->weapon_tube[n].load_time; + tube.direction = ship_template->weapon_tube[n].direction; + tube.size = ship_template->weapon_tube[n].size; + tube.type_allowed_mask = ship_template->weapon_tube[n].type_allowed_mask; } + for(int n=0; nweapon_storage[n]; } - //shipTemplate->has_cloaking; - for(int n=0; nweapon_storage[n]; ship_template->setCollisionData(this); model_info.setData(ship_template->model_data); @@ -418,24 +403,6 @@ void SpaceShip::updateDynamicRadarSignature() entity.addComponent(signature_delta); } -void SpaceShip::drawOnRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) -{ - // If not on long-range radar ... - if (!long_range) - { - // ... and the ship being drawn is either not our ship or has been - // scanned ... - if (!my_spaceship || getScannedStateFor(my_spaceship) >= SS_SimpleScan) - { - // ... draw and show shield indicators on our radar. - drawShieldsOnRadar(renderer, position, scale, rotation, 1.f, true); - } else { - // Otherwise, draw the indicators, but don't show them. - drawShieldsOnRadar(renderer, position, scale, rotation, 1.f, false); - } - } -} - void SpaceShip::drawOnGMRadar(sp::RenderTarget& renderer, glm::vec2 position, float scale, float rotation, bool long_range) { } @@ -518,11 +485,6 @@ void SpaceShip::update(float delta) addHeat(SYS_Impulse, fabs(combat_maneuver_boost_active) * delta * heat_per_combat_maneuver_boost); addHeat(SYS_Maneuver, fabs(combat_maneuver_strafe_active) * delta * heat_per_combat_maneuver_strafe); - for(int n=0; n(); - if (port && port->state == DockingPort::State::Docked && port->target) - { - auto bay = port->target.getComponent(); - if (bay && (bay->flags & DockingBay::ChargeShield)) - rate *= 4.0f; - } - return rate; -} - P SpaceShip::getTarget() { if (game_server) @@ -727,18 +675,22 @@ void SpaceShip::hackFinished(P source, string target) float SpaceShip::getShieldDamageFactor(DamageInfo& info, int shield_index) { + auto shields = entity.getComponent(); + if (!shields) + return 1.0f; + float frequency_damage_factor = 1.f; if (info.type == DT_Energy && gameGlobalInfo->use_beam_shield_frequencies) { - frequency_damage_factor = frequencyVsFrequencyDamageFactor(info.frequency, shield_frequency); + frequency_damage_factor = frequencyVsFrequencyDamageFactor(info.frequency, shields->frequency); } - ESystem system = getShieldSystemForShieldIndex(shield_index); + auto system = shields->getSystemForIndex(shield_index); //Shield damage reduction curve. Damage reduction gets slightly exponetial effective with power. // This also greatly reduces the ineffectiveness at low power situations. float shield_damage_exponent = 1.6f; float shield_damage_divider = 7.0f; - float shield_damage_factor = 1.0f + powf(1.0f, shield_damage_exponent) / shield_damage_divider-powf(getSystemEffectiveness(system), shield_damage_exponent) / shield_damage_divider; + float shield_damage_factor = 1.0f + powf(1.0f, shield_damage_exponent) / shield_damage_divider-powf(system.getSystemEffectiveness(), shield_damage_exponent) / shield_damage_divider; return shield_damage_factor * frequency_damage_factor; } @@ -814,8 +766,13 @@ void SpaceShip::destroyedByDamage(DamageInfo& info) auto hull = entity.getComponent(); if (hull) points += hull->max * 0.1f; - for(int n=0; n(); + if (shields) + { + for(int n=0; ncount; n++) + points += shields->entry[n].max * 0.1f; + } if (isEnemy(info.instigator)) info.instigator->addReputationPoints(points); else @@ -835,11 +792,16 @@ bool SpaceShip::hasSystem(ESystem system) case SYS_JumpDrive: return entity.hasComponent(); case SYS_MissileSystem: - return weapon_tube_count > 0; + return entity.hasComponent(); case SYS_FrontShield: - return shield_count > 0; + return entity.hasComponent(); case SYS_RearShield: - return shield_count > 1; + { + auto shields = entity.getComponent(); + if (shields && shields->count > 1) + return true; + return false; + } case SYS_Reactor: return entity.hasComponent(); case SYS_BeamWeapons: @@ -910,85 +872,66 @@ void SpaceShip::setBeamWeaponDamageType(int index, EDamageType type) { /* TODO * void SpaceShip::setWeaponTubeCount(int amount) { - weapon_tube_count = std::max(0, std::min(amount, max_weapon_tubes)); - for(int n=weapon_tube_count; n= weapon_tube_count) - return MW_None; - if (!weapon_tube[index].isLoaded()) - return MW_None; - return weapon_tube[index].getLoadType(); + //TODO + return MW_None; } void SpaceShip::weaponTubeAllowMissle(int index, EMissileWeapons type) { - if (index < 0 || index >= weapon_tube_count) - return; - weapon_tube[index].allowLoadOf(type); + //TODO + return; } void SpaceShip::weaponTubeDisallowMissle(int index, EMissileWeapons type) { - if (index < 0 || index >= weapon_tube_count) - return; - weapon_tube[index].disallowLoadOf(type); + //TODO + return; } void SpaceShip::setWeaponTubeExclusiveFor(int index, EMissileWeapons type) { - if (index < 0 || index >= weapon_tube_count) - return; - for(int n=0; n= weapon_tube_count) - return; - weapon_tube[index].setDirection(direction); + //TODO + return; } void SpaceShip::setTubeSize(int index, EMissileSizes size) { - if (index < 0 || index >= weapon_tube_count) - return; - weapon_tube[index].setSize(size); + //TODO + return; } EMissileSizes SpaceShip::getTubeSize(int index) { - if (index < 0 || index >= weapon_tube_count) - return MS_Medium; - return weapon_tube[index].getSize(); + //TODO + return MS_Medium; } float SpaceShip::getTubeLoadTime(int index) { - if (index < 0 || index >= weapon_tube_count) { - return 0; - } - return weapon_tube[index].getLoadTimeConfig(); + //TODO + return 0; } void SpaceShip::setTubeLoadTime(int index, float time) { - if (index < 0 || index >= weapon_tube_count) { - return; - } - weapon_tube[index].setLoadTimeConfig(time); + return; } void SpaceShip::addBroadcast(int threshold, string message) @@ -1172,6 +1115,7 @@ string SpaceShip::getScriptExportModificationsOnTemplate() } // Missile weapon data + /* if (weapon_tube_count != ship_template->weapon_tube_count) ret += ":setWeaponTubeCount(" + string(weapon_tube_count) + ")"; @@ -1197,7 +1141,7 @@ string SpaceShip::getScriptExportModificationsOnTemplate() if (weapon_storage[n] != ship_template->weapon_storage[n]) ret += ":setWeaponStorage(\"" + getMissileWeaponName(EMissileWeapons(n)) + "\", " + string(weapon_storage[n]) + ")"; } - + */ // Beam weapon data /* for(int n=0; n::linear(getSystemEffectiveness(SYS_JumpDrive), 0.0, 1.0, -0.25, 1.0); } /*! * Check if the ship can be targeted. @@ -225,10 +211,10 @@ class SpaceShip : public ShipTemplateBasedObject bool isDocked(P target); P getDockedWith(); DockingPort::State getDockingState(); - int getWeaponStorage(EMissileWeapons weapon) { if (weapon == MW_None) return 0; return weapon_storage[weapon]; } - int getWeaponStorageMax(EMissileWeapons weapon) { if (weapon == MW_None) return 0; return weapon_storage_max[weapon]; } - void setWeaponStorage(EMissileWeapons weapon, int amount) { if (weapon == MW_None) return; weapon_storage[weapon] = amount; } - void setWeaponStorageMax(EMissileWeapons weapon, int amount) { if (weapon == MW_None) return; weapon_storage_max[weapon] = amount; weapon_storage[weapon] = std::min(int(weapon_storage[weapon]), amount); } + int getWeaponStorage(EMissileWeapons weapon) { return 0; } //TODO + int getWeaponStorageMax(EMissileWeapons weapon) { return 0; } //TODO + void setWeaponStorage(EMissileWeapons weapon, int amount) { } //TODO + void setWeaponStorageMax(EMissileWeapons weapon, int amount) { } //TODO float getMaxEnergy(); void setMaxEnergy(float amount); float getEnergy(); @@ -288,8 +274,8 @@ class SpaceShip : public ShipTemplateBasedObject float getBeamWeaponEnergyPerFire(int index); float getBeamWeaponHeatPerFire(int index); - int getShieldsFrequency(){ return shield_frequency; } - void setShieldsFrequency(int freq) { if ((freq > SpaceShip::max_frequency) || (freq < 0)) return; shield_frequency = freq;} + int getShieldsFrequency() { return 0.0; } //TODO + void setShieldsFrequency(int freq) { return; } //TODO int getBeamFrequency(); @@ -330,7 +316,6 @@ float frequencyVsFrequencyDamageFactor(int beam_frequency, int shield_frequency) string getMissileWeaponName(EMissileWeapons missile); string getLocaleMissileWeaponName(EMissileWeapons missile); REGISTER_MULTIPLAYER_ENUM(EMissileWeapons); -REGISTER_MULTIPLAYER_ENUM(EWeaponTubeState); REGISTER_MULTIPLAYER_ENUM(EMainScreenSetting); REGISTER_MULTIPLAYER_ENUM(EMainScreenOverlay); REGISTER_MULTIPLAYER_ENUM(EScannedState); diff --git a/src/spaceObjects/spaceshipParts/weaponTube.cpp b/src/spaceObjects/spaceshipParts/weaponTube.cpp deleted file mode 100644 index 533e396b67..0000000000 --- a/src/spaceObjects/spaceshipParts/weaponTube.cpp +++ /dev/null @@ -1,380 +0,0 @@ -#include "weaponTube.h" -#include "spaceObjects/missiles/EMPMissile.h" -#include "spaceObjects/missiles/homingMissile.h" -#include "spaceObjects/mine.h" -#include "spaceObjects/missiles/nuke.h" -#include "spaceObjects/missiles/hvli.h" -#include "spaceObjects/spaceship.h" -#include "multiplayer_server.h" -#include "components/warpdrive.h" -#include - - -WeaponTube::WeaponTube() -{ - parent = nullptr; - - load_time = 8.0; - direction = 0; - type_allowed_mask = (1 << MW_Count) - 1; - type_loaded = MW_None; - state = WTS_Empty; - delay = 0.0; - tube_index = 0; - size = MS_Medium; -} - -void WeaponTube::setParent(SpaceShip* parent) -{ - SDL_assert(!this->parent); - this->parent = parent; - - parent->registerMemberReplication(&load_time); - parent->registerMemberReplication(&type_allowed_mask); - parent->registerMemberReplication(&direction); - parent->registerMemberReplication(&size); - - parent->registerMemberReplication(&type_loaded); - parent->registerMemberReplication(&state); - parent->registerMemberReplication(&delay, 0.5); -} - -float WeaponTube::getLoadTimeConfig() -{ - return load_time; -} - -void WeaponTube::setLoadTimeConfig(float load_time) -{ - this->load_time = load_time; -} - -void WeaponTube::setIndex(int index) -{ - tube_index = index; -} - -void WeaponTube::setDirection(float direction) -{ - this->direction = direction; -} - -float WeaponTube::getDirection() -{ - return direction; -} - -void WeaponTube::startLoad(EMissileWeapons type) -{ - if (!canLoad(type)) - return; - if (state != WTS_Empty) - return; - if (parent->weapon_storage[type] <= 0) - return; - - state = WTS_Loading; - delay = load_time; - parent->forceMemberReplicationUpdate(&delay); - type_loaded = type; - parent->weapon_storage[type]--; -} - -void WeaponTube::startUnload() -{ - if (state == WTS_Loaded) - { - state = WTS_Unloading; - delay = load_time; - parent->forceMemberReplicationUpdate(&delay); - } -} - -void WeaponTube::fire(float target_angle) -{ - parent->didAnOffensiveAction(); - - auto docking_port = parent->entity.getComponent(); - if (docking_port && docking_port->state != DockingPort::State::NotDocking) return; - - auto warp = parent->entity.getComponent(); - if (warp && warp->current > 0.0f) return; - if (state != WTS_Loaded) return; - - if (type_loaded == MW_HVLI) - { - fire_count = 5; - state = WTS_Firing; - delay = 0.0; - }else{ - spawnProjectile(target_angle); - state = WTS_Empty; - type_loaded = MW_None; - } -} - -void WeaponTube::spawnProjectile(float target_angle) -{ - auto fireLocation = parent->getPosition() + rotateVec2(parent->ship_template->model_data->getTubePosition2D(tube_index), parent->getRotation()); - switch(type_loaded) - { - case MW_Homing: - { - P missile = new HomingMissile(); - missile->owner = parent; - missile->setFactionId(parent->getFactionId()); - missile->target_id = parent->target_id; - missile->setPosition(fireLocation); - missile->setRotation(parent->getRotation() + direction); - missile->target_angle = target_angle; - missile->category_modifier = MissileWeaponData::convertSizeToCategoryModifier(size); - } - break; - case MW_Nuke: - { - P missile = new Nuke(); - missile->owner = parent; - missile->setFactionId(parent->getFactionId()); - missile->target_id = parent->target_id; - missile->setPosition(fireLocation); - missile->setRotation(parent->getRotation() + direction); - missile->target_angle = target_angle; - missile->category_modifier = MissileWeaponData::convertSizeToCategoryModifier(size); - } - break; - case MW_Mine: - { - P missile = new Mine(); - missile->owner = parent; - missile->setFactionId(parent->getFactionId()); - missile->setPosition(fireLocation); - missile->setRotation(parent->getRotation() + direction); - missile->eject(); - } - break; - case MW_HVLI: - { - P missile = new HVLI(); - missile->owner = parent; - missile->setFactionId(parent->getFactionId()); - missile->setPosition(fireLocation); - missile->setRotation(parent->getRotation() + direction); - missile->target_angle = parent->getRotation() + direction; - missile->category_modifier = MissileWeaponData::convertSizeToCategoryModifier(size); - } - break; - case MW_EMP: - { - P missile = new EMPMissile(); - missile->owner = parent; - missile->setFactionId(parent->getFactionId()); - missile->target_id = parent->target_id; - missile->setPosition(fireLocation); - missile->setRotation(parent->getRotation() + direction); - missile->target_angle = target_angle; - missile->category_modifier = MissileWeaponData::convertSizeToCategoryModifier(size); - } - break; - default: - break; - } -} - -bool WeaponTube::canLoad(EMissileWeapons type) -{ - if (type <= MW_None || type >= MW_Count) - return false; - if (type_allowed_mask & (1 << type)) - return true; - return false; -} - -bool WeaponTube::canOnlyLoad(EMissileWeapons type) -{ - if (type_allowed_mask == (1U << type)) - return true; - return false; -} - -void WeaponTube::allowLoadOf(EMissileWeapons type) -{ - type_allowed_mask |= (1 << type); -} - -void WeaponTube::disallowLoadOf(EMissileWeapons type) -{ - type_allowed_mask &=~(1 << type); -} - -void WeaponTube::forceUnload() -{ - if (state != WTS_Empty && type_loaded != MW_None) - { - state = WTS_Empty; - if (parent->weapon_storage[type_loaded] < parent->weapon_storage_max[type_loaded]) - parent->weapon_storage[type_loaded] ++; - type_loaded = MW_None; - } -} - -void WeaponTube::update(float delta) -{ - if (delay > 0.0f) - { - delay -= delta * parent->getSystemEffectiveness(SYS_MissileSystem); - }else{ - switch(state) - { - case WTS_Loading: - state = WTS_Loaded; - break; - case WTS_Unloading: - state = WTS_Empty; - if (parent->weapon_storage[type_loaded] < parent->weapon_storage_max[type_loaded]) - parent->weapon_storage[type_loaded] ++; - type_loaded = MW_None; - break; - case WTS_Firing: - if (game_server) - { - spawnProjectile(0); - - fire_count -= 1; - if (fire_count > 0) - { - delay = 1.5; - } - else - { - state = WTS_Empty; - type_loaded = MW_None; - } - } - break; - default: - break; - } - } -} - -bool WeaponTube::isEmpty() -{ - return state == WTS_Empty; -} - -bool WeaponTube::isLoaded() -{ - return state == WTS_Loaded; -} - -bool WeaponTube::isLoading() -{ - return state == WTS_Loading; -} - -bool WeaponTube::isUnloading() -{ - return state == WTS_Unloading; -} - -bool WeaponTube::isFiring() -{ - return state == WTS_Firing; -} - -float WeaponTube::getLoadProgress() -{ - return 1.0f - delay / load_time; -} - -float WeaponTube::getUnloadProgress() -{ - return delay / load_time; -} - -EMissileWeapons WeaponTube::getLoadType() -{ - return type_loaded; -} - -string WeaponTube::getTubeName() -{ - if (std::abs(angleDifference(0.0f, direction)) <= 45) - return tr("tube","Front"); - if (std::abs(angleDifference(90.0f, direction)) < 45) - return tr("tube","Right"); - if (std::abs(angleDifference(-90.0f, direction)) < 45) - return tr("tube","Left"); - if (std::abs(angleDifference(180.0f, direction)) <= 45) - return tr("tube","Rear"); - return "?" + string(direction); -} - -float WeaponTube::calculateFiringSolution(P target) -{ - if (!target) - return std::numeric_limits::infinity(); - const MissileWeaponData& data = MissileWeaponData::getDataFor(type_loaded); - if (data.turnrate == 0.0f) //If the missile cannot turn, we cannot find a firing solution. - return std::numeric_limits::infinity(); - - auto target_position = target->getPosition(); - auto target_velocity = target->getVelocity(); - float target_velocity_length = glm::length(target_velocity); - float missile_angle = vec2ToAngle(target_position - parent->getPosition()); - float turn_radius = ((360.0f / data.turnrate) * data.speed) / (2.0f * float(M_PI)); - float missile_exit_angle = parent->getRotation() + direction; - - for(int iterations=0; iterations<10; iterations++) - { - float angle_diff = angleDifference(missile_angle, missile_exit_angle); - - float left_or_right = 90; - if (angle_diff > 0) - left_or_right = -90; - - auto turn_center = parent->getPosition() + vec2FromAngle(missile_exit_angle + left_or_right) * turn_radius; - auto turn_exit = turn_center + vec2FromAngle(missile_angle - left_or_right) * turn_radius; - if (target_velocity_length < 1.0f) - { - //If the target is almost standing still, just target the position directly instead of using the velocity of the target in the calculations. - float time_missile = glm::length(turn_exit - target_position) / data.speed; - auto interception = turn_exit + vec2FromAngle(missile_angle) * data.speed * time_missile; - float r = target->getRadius() / 2; - if (glm::length2(interception - target_position) < r*r) - return missile_angle; - missile_angle = vec2ToAngle(target_position - turn_exit); - } - else - { - auto missile_velocity = vec2FromAngle(missile_angle) * data.speed; - //Calculate the position where missile and the target will cross each others path. - auto intersection = lineLineIntersection(target_position, target_position + target_velocity, turn_exit, turn_exit + missile_velocity); - //Calculate the time it will take for the target and missile to reach the intersection - float turn_time = fabs(angle_diff) / data.turnrate; - float time_target = glm::length((target_position - intersection)) / target_velocity_length; - float time_missile = glm::length(turn_exit - intersection) / data.speed + turn_time; - //Calculate the time in which the radius will be on the intersection, to know in which time range we need to hit. - float time_radius = (target->getRadius() / 2.0f) / target_velocity_length;//TODO: This value could be improved, as it is allowed to be bigger when the angle between the missile and the ship is low - // When both the missile and the target are at the same position at the same time, we can take a shot! - if (fabsf(time_target - time_missile) < time_radius) - return missile_angle; - - //When we cannot hit the target with this setup yet. Calculate a new intersection target, and aim for that. - float guessed_impact_time = (time_target * target_velocity_length / (target_velocity_length + data.speed)) + (time_missile * data.speed / (target_velocity_length + data.speed)); - auto new_target_position = target_position + target_velocity * guessed_impact_time; - missile_angle = vec2ToAngle(new_target_position - turn_exit); - } - } - return std::numeric_limits::infinity(); -} - -void WeaponTube::setSize(EMissileSizes size) -{ - this->size = size; -} - -EMissileSizes WeaponTube::getSize() -{ - return size; -} diff --git a/src/spaceObjects/spaceshipParts/weaponTube.h b/src/spaceObjects/spaceshipParts/weaponTube.h deleted file mode 100644 index cccaa25a8f..0000000000 --- a/src/spaceObjects/spaceshipParts/weaponTube.h +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef WEAPON_TUBE_H -#define WEAPON_TUBE_H - -#include "nonCopyable.h" -#include "shipTemplate.h" - -class SpaceShip; - -enum EWeaponTubeState -{ - WTS_Empty, - WTS_Loading, - WTS_Loaded, - WTS_Unloading, - WTS_Firing -}; - -class WeaponTube : sp::NonCopyable -{ -public: - WeaponTube(); - - void setParent(SpaceShip* parent); - void setIndex(int index); - - float getLoadTimeConfig(); - void setLoadTimeConfig(float load_time); - - void setDirection(float direction); - float getDirection(); - - /*! - * Load a missile tube. - * \param type Weapon type that is loaded. - */ - void startLoad(EMissileWeapons type); - void startUnload(); - /*! - * Fire a missile tube. - * \param target_angle Angle in degrees to where the missile needs to be shot. - */ - void fire(float target_angle); - - bool canLoad(EMissileWeapons type); - bool canOnlyLoad(EMissileWeapons type); - void allowLoadOf(EMissileWeapons type); - void disallowLoadOf(EMissileWeapons type); - - void setSize(EMissileSizes size); - EMissileSizes getSize(); - - void forceUnload(); - - void update(float delta); - - bool isEmpty(); - bool isLoaded(); - bool isLoading(); - bool isUnloading(); - bool isFiring(); - - float getLoadProgress(); - float getUnloadProgress(); - - EMissileWeapons getLoadType(); - - string getTubeName(); //Get the tube name based on the direction of the tube. - - //Calculate a possible firing solution towards the target for this missile tube. - //Will return the angle that the missile needs to turn to to possibly hit this target. - //Will return infinity when no solution is found. - float calculateFiringSolution(P target); -private: - void spawnProjectile(float target_angle); - - SpaceShip* parent; - int tube_index; - - //Configuration - float load_time; - uint32_t type_allowed_mask; - float direction; - - //Runtime state - EMissileWeapons type_loaded; - - EMissileSizes size; - EWeaponTubeState state; - float delay; - int fire_count; -}; - -#endif//WEAPON_TUBE_H diff --git a/src/spaceObjects/supplyDrop.cpp b/src/spaceObjects/supplyDrop.cpp index e8c8bf2ec7..b0cd00a3f0 100644 --- a/src/spaceObjects/supplyDrop.cpp +++ b/src/spaceObjects/supplyDrop.cpp @@ -3,6 +3,7 @@ #include "playerInfo.h" #include "playerSpaceship.h" #include "components/reactor.h" +#include "components/missiletubes.h" #include "main.h" #include "scriptInterface.h" @@ -51,14 +52,17 @@ void SupplyDrop::collide(SpaceObject* target, float force) reactor->energy += energy; picked_up = true; } - for(int n=0; nweapon_storage_max[n] - ship->weapon_storage[n]); - if (delta > 0) + auto missiletubes = ship->entity.getComponent(); + if (missiletubes) { + for(int n=0; nweapon_storage[n] += delta; - weapon_storage[n] -= delta; - picked_up = true; + uint8_t delta = std::min(int(missiletubes->storage[n]), missiletubes->storage_max[n] - missiletubes->storage[n]); + if (delta > 0) + { + missiletubes->storage[n] += delta; + weapon_storage[n] -= delta; + picked_up = true; + } } } if (on_pickup_callback.isSet()) diff --git a/src/systems/beamweapon.cpp b/src/systems/beamweapon.cpp index 6359cb3cfd..defa644899 100644 --- a/src/systems/beamweapon.cpp +++ b/src/systems/beamweapon.cpp @@ -15,14 +15,14 @@ void BeamWeaponSystem::update(float delta) if (!game_server) return; if (delta <= 0.0f) return; - for(auto [entity, beamsys, position, reactor, docking_port, obj] : sp::ecs::Query, sp::ecs::optional, SpaceObject*>()) { + for(auto [entity, beamsys, transform, reactor, docking_port, obj] : sp::ecs::Query, sp::ecs::optional, SpaceObject*>()) { if (!beamsys.target) continue; P ship = P(obj); auto warp = entity.getComponent(); for(auto& mount : beamsys.mounts) { if (mount.cooldown > 0.0f) - mount.cooldown -= delta * beamsys.get_system_effectiveness(); + mount.cooldown -= delta * beamsys.getSystemEffectiveness(); P target = *beamsys.target.getComponent(); @@ -31,7 +31,7 @@ void BeamWeaponSystem::update(float delta) if (mount.range > 0.0f && target && obj->isEnemy(target) && delta > 0.0f && (!warp || warp->current == 0.0f) && (!docking_port || docking_port->state == DockingPort::State::NotDocking)) { // Get the angle to the target. - auto diff = target->getPosition() - (position.getPosition() + rotateVec2(glm::vec2(mount.position.x, mount.position.y), position.getRotation())); + auto diff = target->getPosition() - (transform.getPosition() + rotateVec2(glm::vec2(mount.position.x, mount.position.y), transform.getRotation())); float distance = glm::length(diff) - target->getRadius() / 2.0f; // We also only care if the target is within no more than its @@ -40,12 +40,12 @@ void BeamWeaponSystem::update(float delta) if (distance < mount.range * 1.3f) { float angle = vec2ToAngle(diff); - float angle_diff = angleDifference(mount.direction + position.getRotation(), angle); + float angle_diff = angleDifference(mount.direction + transform.getRotation(), angle); if (mount.turret_arc > 0) { // Get the target's angle relative to the turret's direction. - float turret_angle_diff = angleDifference(mount.turret_direction + position.getRotation(), angle); + float turret_angle_diff = angleDifference(mount.turret_direction + transform.getRotation(), angle); // If the turret can rotate ... if (mount.turret_rotation_rate > 0) @@ -56,7 +56,7 @@ void BeamWeaponSystem::update(float delta) // ... rotate the turret's beam toward the target. if (fabsf(angle_diff) > 0) { - mount.direction += (angle_diff / fabsf(angle_diff)) * std::min(mount.turret_rotation_rate * beamsys.get_system_effectiveness(), fabsf(angle_diff)); + mount.direction += (angle_diff / fabsf(angle_diff)) * std::min(mount.turret_rotation_rate * beamsys.getSystemEffectiveness(), fabsf(angle_diff)); } // If the target is outside of the turret's arc ... } else { @@ -66,7 +66,7 @@ void BeamWeaponSystem::update(float delta) if (fabsf(reset_angle_diff) > 0) { - mount.direction += (reset_angle_diff / fabsf(reset_angle_diff)) * std::min(mount.turret_rotation_rate * beamsys.get_system_effectiveness(), fabsf(reset_angle_diff)); + mount.direction += (reset_angle_diff / fabsf(reset_angle_diff)) * std::min(mount.turret_rotation_rate * beamsys.getSystemEffectiveness(), fabsf(reset_angle_diff)); } } } @@ -77,7 +77,7 @@ void BeamWeaponSystem::update(float delta) if (distance < mount.range && mount.cooldown <= 0.0f && fabsf(angle_diff) < mount.arc / 2.0f && (!reactor || reactor->use_energy(mount.energy_per_beam_fire))) { // ... add heat to the beam and zap the target. - beamsys.add_heat(mount.heat_per_beam_fire); + beamsys.addHeat(mount.heat_per_beam_fire); //When we fire a beam, and we hit an enemy, check if we are not scanned yet, if we are not, and we hit something that we know is an enemy or friendly, // we now know if this ship is an enemy or friend. @@ -86,7 +86,7 @@ void BeamWeaponSystem::update(float delta) mount.cooldown = mount.cycle_time; // Reset time of weapon - auto hit_location = target->getPosition() - glm::normalize(target->getPosition() - position.getPosition()) * target->getRadius(); + auto hit_location = target->getPosition() - glm::normalize(target->getPosition() - transform.getPosition()) * target->getRadius(); P effect = new BeamEffect(); effect->setSource(obj, mount.position); effect->setTarget(target, hit_location); @@ -107,7 +107,7 @@ void BeamWeaponSystem::update(float delta) if (fabsf(reset_angle_diff) > 0) { - mount.direction += (reset_angle_diff / fabsf(reset_angle_diff)) * std::min(mount.turret_rotation_rate * beamsys.get_system_effectiveness(), fabsf(reset_angle_diff)); + mount.direction += (reset_angle_diff / fabsf(reset_angle_diff)) * std::min(mount.turret_rotation_rate * beamsys.getSystemEffectiveness(), fabsf(reset_angle_diff)); } } } diff --git a/src/systems/docking.cpp b/src/systems/docking.cpp index 85237978e3..ca24eebff3 100644 --- a/src/systems/docking.cpp +++ b/src/systems/docking.cpp @@ -6,6 +6,7 @@ #include "components/hull.h" #include "components/warpdrive.h" #include "components/jumpdrive.h" +#include "components/missiletubes.h" #include "spaceObjects/spaceship.h" #include "spaceObjects/playerSpaceship.h" #include "spaceObjects/cpuShip.h" @@ -21,23 +22,23 @@ void DockingSystem::update(float delta) { if (!game_server) return; - for(auto [entity, docking_port, position, obj] : sp::ecs::Query, SpaceObject*>()) { + for(auto [entity, docking_port, transform, obj] : sp::ecs::Query, SpaceObject*>()) { SpaceShip* ship = dynamic_cast(obj); PlayerSpaceship* player = dynamic_cast(obj); if (!ship) continue; - sp::Position* target_position; + sp::Transform* target_transform; switch(docking_port.state) { case DockingPort::State::NotDocking: break; case DockingPort::State::Docking: - if (!docking_port.target || !(target_position = docking_port.target.getComponent())) { + if (!docking_port.target || !(target_transform = docking_port.target.getComponent())) { docking_port.state = DockingPort::State::NotDocking; } else { auto engine = entity.getComponent(); auto warp = entity.getComponent(); - ship->target_rotation = vec2ToAngle(position->getPosition() - target_position->getPosition()); + ship->target_rotation = vec2ToAngle(transform->getPosition() - target_transform->getPosition()); if (engine) { - if (fabs(angleDifference(ship->target_rotation, position->getRotation())) < 10.0f) + if (fabs(angleDifference(ship->target_rotation, transform->getRotation())) < 10.0f) engine->request = -1.f; else engine->request = 0.f; @@ -47,16 +48,16 @@ void DockingSystem::update(float delta) } break; case DockingPort::State::Docked: - if (!docking_port.target || !(target_position = docking_port.target.getComponent())) + if (!docking_port.target || !(target_transform = docking_port.target.getComponent())) { docking_port.state = DockingPort::State::NotDocking; - if (!position) { // Internal docking and our bay is destroyed. So, destroy ourselves as well. + if (!transform) { // Internal docking and our bay is destroyed. So, destroy ourselves as well. entity.destroy(); } }else{ - if (position) { - position->setPosition(target_position->getPosition() + rotateVec2(docking_port.docked_offset, target_position->getRotation())); - ship->target_rotation = vec2ToAngle(position->getPosition() - target_position->getPosition()); + if (transform) { + transform->setPosition(target_transform->getPosition() + rotateVec2(docking_port.docked_offset, target_transform->getRotation())); + ship->target_rotation = vec2ToAngle(transform->getPosition() - target_transform->getPosition()); } auto bay = docking_port.target.getComponent(); @@ -107,25 +108,27 @@ void DockingSystem::update(float delta) if (!player && bay && (bay->flags & DockingBay::RestockMissiles)) { auto cpu = dynamic_cast(ship); if (cpu) { - bool needs_missile = false; - - for(int n=0; nweapon_storage[n] < ship->weapon_storage_max[n]) + auto tubes = entity.getComponent(); + if (tubes) { + bool needs_missile = false; + for(int n=0; nmissile_resupply >= cpu->missile_resupply_time) + if (tubes->storage[n] < tubes->storage_max[n]) { - cpu->weapon_storage[n] += 1; - cpu->missile_resupply = 0.0; - break; + if (cpu->missile_resupply >= cpu->missile_resupply_time) + { + tubes->storage[n] += 1; + cpu->missile_resupply = 0.0; + break; + } + else + needs_missile = true; } - else - needs_missile = true; } - } - if (needs_missile) - cpu->missile_resupply += delta; + if (needs_missile) + cpu->missile_resupply += delta; + } } } } @@ -157,8 +160,8 @@ void DockingSystem::collision(sp::ecs::Entity a, sp::ecs::Entity b, float force) { auto port = a.getComponent(); if (port && port->state == DockingPort::State::Docking && port->target == b) { - auto position = a.getComponent(); - auto other_position = b.getComponent(); + auto position = a.getComponent(); + auto other_position = b.getComponent(); auto ship = dynamic_cast(*a.getComponent()); if (ship && position && other_position && fabs(angleDifference(ship->target_rotation, position->getRotation())) < 10.0f) @@ -170,7 +173,7 @@ void DockingSystem::collision(sp::ecs::Entity a, sp::ecs::Entity b, float force) port->docked_offset = port->docked_offset / length * (length + 2.0f); if (bay && port->canDockOn(*bay) == DockingStyle::Internal) - a.removeComponent(); + a.removeComponent(); } } } @@ -186,9 +189,9 @@ void DockingSystem::requestDock(sp::ecs::Entity entity, sp::ecs::Entity target) if (!target) return; auto bay = target.getComponent(); if (!bay || docking_port->canDockOn(*bay) == DockingStyle::None) return; - auto position = entity.getComponent(); + auto position = entity.getComponent(); if (position) return; - auto target_position = target.getComponent(); + auto target_position = target.getComponent(); if (target_position) return; auto target_physics = target.getComponent(); if (target_physics) return; @@ -207,7 +210,7 @@ void DockingSystem::requestUndock(sp::ecs::Entity entity) auto docking_port = entity.getComponent(); if (!docking_port || docking_port->state != DockingPort::State::Docked) return; auto impulse = entity.getComponent(); - if (impulse && impulse->get_system_effectiveness() < 0.1f) return; + if (impulse && impulse->getSystemEffectiveness() < 0.1f) return; docking_port->state = DockingPort::State::NotDocking; if (impulse) impulse->request = 0.5; diff --git a/src/systems/jumpsystem.cpp b/src/systems/jumpsystem.cpp index 55649fd3ce..60f61116a8 100644 --- a/src/systems/jumpsystem.cpp +++ b/src/systems/jumpsystem.cpp @@ -14,7 +14,7 @@ void JumpSystem::update(float delta) { - for(auto [entity, jump, position, physics, obj] : sp::ecs::Query()) + for(auto [entity, jump, position, physics, obj] : sp::ecs::Query()) { SpaceShip* ship = dynamic_cast(obj); if (jump.delay > 0.0f) @@ -33,7 +33,7 @@ void JumpSystem::update(float delta) if (warp) warp->request = 0; - jump.delay -= delta * jump.get_system_effectiveness(); + jump.delay -= delta * jump.getSystemEffectiveness(); if (jump.delay <= 0.0f) { float f = jump.health; @@ -49,12 +49,12 @@ void JumpSystem::update(float delta) auto target_position = position.getPosition() + vec2FromAngle(position.getRotation()) * distance; target_position = WarpJammer::getFirstNoneJammedPosition(position.getPosition(), target_position); position.setPosition(target_position); - jump.add_heat(jump.heat_per_jump); + jump.addHeat(jump.heat_per_jump); jump.delay = 0.f; } } else { - float f = ship->getJumpDriveRechargeRate(); + float f = jump.get_recharge_rate(); if (f > 0) { if (jump.charge < jump.max_distance) diff --git a/src/systems/missilesystem.cpp b/src/systems/missilesystem.cpp new file mode 100644 index 0000000000..767eb5b427 --- /dev/null +++ b/src/systems/missilesystem.cpp @@ -0,0 +1,250 @@ +#include "systems/missilesystem.h" + +#include "components/collision.h" +#include "components/missiletubes.h" +#include "ecs/query.h" +#include "multiplayer_server.h" + + +void MissileSystem::update(float delta) +{ + for(auto [entity, tubes] : sp::ecs::Query()) + { + for(int n=0; n 0.0f) + { + tube.delay -= delta * tubes.getSystemEffectiveness(); + }else{ + switch(tube.state) + { + case MissileTubes::MountPoint::State::Loading: + tube.state = MissileTubes::MountPoint::State::Loaded; + break; + case MissileTubes::MountPoint::State::Unloading: + tube.state = MissileTubes::MountPoint::State::Empty; + if (tubes.storage[tube.type_loaded] < tubes.storage_max[tube.type_loaded]) + tubes.storage[tube.type_loaded]++; + tube.type_loaded = MW_None; + break; + case MissileTubes::MountPoint::State::Firing: + if (game_server) + { + spawnProjectile(entity, tube, 0, {}); + + tube.fire_count -= 1; + if (tube.fire_count > 0) + { + tube.delay = 1.5; + } + else + { + tube.state = MissileTubes::MountPoint::State::Empty; + tube.type_loaded = MW_None; + } + } + break; + default: + break; + } + } + } + } +} + +#include "spaceObjects/missiles/EMPMissile.h" +#include "spaceObjects/missiles/homingMissile.h" +#include "spaceObjects/mine.h" +#include "spaceObjects/missiles/nuke.h" +#include "spaceObjects/missiles/hvli.h" +#include "spaceObjects/spaceship.h" +#include "multiplayer_server.h" +#include "components/warpdrive.h" +#include + + +void MissileSystem::startLoad(sp::ecs::Entity source, MissileTubes::MountPoint& tube, EMissileWeapons type) +{ + if (!tube.canLoad(type)) + return; + if (tube.state != MissileTubes::MountPoint::State::Empty) + return; + auto tubes = source.getComponent(); + if (!tubes) return; + if (tubes->storage[type] <= 0) + return; + + tube.state = MissileTubes::MountPoint::State::Loading; + tube.delay = tube.load_time; + tube.type_loaded = type; + tubes->storage[type]--; +} + +void MissileSystem::startUnload(sp::ecs::Entity source, MissileTubes::MountPoint& tube) +{ + if (tube.state == MissileTubes::MountPoint::State::Loaded) + { + tube.state = MissileTubes::MountPoint::State::Unloading; + tube.delay = tube.load_time; + } +} + +void MissileSystem::fire(sp::ecs::Entity source, MissileTubes::MountPoint& tube, float target_angle, sp::ecs::Entity target) +{ + //TODO: parent->didAnOffensiveAction(); + + auto docking_port = source.getComponent(); + if (docking_port && docking_port->state != DockingPort::State::NotDocking) return; + + auto warp = source.getComponent(); + if (warp && warp->current > 0.0f) return; + if (tube.state != MissileTubes::MountPoint::State::Loaded) return; + + if (tube.type_loaded == MW_HVLI) + { + tube.fire_count = 5; + tube.state = MissileTubes::MountPoint::State::Firing; + tube.delay = 0.0; + }else{ + spawnProjectile(source, tube, target_angle, target); + tube.state = MissileTubes::MountPoint::State::Empty; + tube.type_loaded = MW_None; + } +} + +void MissileSystem::spawnProjectile(sp::ecs::Entity source, MissileTubes::MountPoint& tube, float target_angle, sp::ecs::Entity target) +{ + auto source_transform = source.getComponent(); + if (!source_transform) return; + auto fireLocation = source_transform->getPosition() + rotateVec2(glm::vec2(tube.position), source_transform->getRotation()); + switch(tube.type_loaded) + { + case MW_Homing: + { + P missile = new HomingMissile(); + missile->owner = *source.getComponent(); + missile->setFactionId(missile->owner->getFactionId()); + missile->target = target; + missile->setPosition(fireLocation); + missile->setRotation(source_transform->getRotation() + tube.direction); + missile->target_angle = target_angle; + missile->category_modifier = MissileWeaponData::convertSizeToCategoryModifier(tube.size); + } + break; + case MW_Nuke: + { + P missile = new Nuke(); + missile->owner = *source.getComponent(); + missile->setFactionId(missile->owner->getFactionId()); + missile->target = target; + missile->setPosition(fireLocation); + missile->setRotation(source_transform->getRotation() + tube.direction); + missile->target_angle = target_angle; + missile->category_modifier = MissileWeaponData::convertSizeToCategoryModifier(tube.size); + } + break; + case MW_Mine: + { + P missile = new Mine(); + missile->owner = *source.getComponent(); + missile->setFactionId(missile->owner->getFactionId()); + missile->setPosition(fireLocation); + missile->setRotation(source_transform->getRotation() + tube.direction); + missile->eject(); + } + break; + case MW_HVLI: + { + P missile = new HVLI(); + missile->owner = *source.getComponent(); + missile->setFactionId(missile->owner->getFactionId()); + missile->setPosition(fireLocation); + missile->setRotation(source_transform->getRotation() + tube.direction); + missile->target_angle = source_transform->getRotation() + tube.direction; + missile->category_modifier = MissileWeaponData::convertSizeToCategoryModifier(tube.size); + } + break; + case MW_EMP: + { + P missile = new EMPMissile(); + missile->owner = *source.getComponent(); + missile->setFactionId(missile->owner->getFactionId()); + missile->target = target; + missile->setPosition(fireLocation); + missile->setRotation(source_transform->getRotation() + tube.direction); + missile->target_angle = target_angle; + missile->category_modifier = MissileWeaponData::convertSizeToCategoryModifier(tube.size); + } + break; + default: + break; + } +} + +float MissileSystem::calculateFiringSolution(sp::ecs::Entity source, const MissileTubes::MountPoint& tube, sp::ecs::Entity target) +{ + if (!target) + return std::numeric_limits::infinity(); + const MissileWeaponData& data = MissileWeaponData::getDataFor(tube.type_loaded); + if (data.turnrate == 0.0f) //If the missile cannot turn, we cannot find a firing solution. + return std::numeric_limits::infinity(); + auto source_transform = source.getComponent(); + if (!source_transform) + return std::numeric_limits::infinity(); + auto target_transform = target.getComponent(); + if (!target_transform) + return std::numeric_limits::infinity(); + auto target_physics = target.getComponent(); + + auto target_position = target_transform->getPosition(); + auto target_velocity = target_physics ? target_physics->getVelocity() : glm::vec2{0, 0}; + float target_velocity_length = glm::length(target_velocity); + float missile_angle = vec2ToAngle(target_position - source_transform->getPosition()); + float turn_radius = ((360.0f / data.turnrate) * data.speed) / (2.0f * float(M_PI)); + float missile_exit_angle = source_transform->getRotation() + tube.direction; + float target_radius = target_physics ? target_physics->getSize().x : 100.0f; + + for(int iterations=0; iterations<10; iterations++) + { + float angle_diff = angleDifference(missile_angle, missile_exit_angle); + + float left_or_right = 90; + if (angle_diff > 0) + left_or_right = -90; + + auto turn_center = source_transform->getPosition() + vec2FromAngle(missile_exit_angle + left_or_right) * turn_radius; + auto turn_exit = turn_center + vec2FromAngle(missile_angle - left_or_right) * turn_radius; + if (target_velocity_length < 1.0f) + { + //If the target is almost standing still, just target the position directly instead of using the velocity of the target in the calculations. + float time_missile = glm::length(turn_exit - target_position) / data.speed; + auto interception = turn_exit + vec2FromAngle(missile_angle) * data.speed * time_missile; + float r = target_radius * 0.5f; + if (glm::length2(interception - target_position) < r*r) + return missile_angle; + missile_angle = vec2ToAngle(target_position - turn_exit); + } + else + { + auto missile_velocity = vec2FromAngle(missile_angle) * data.speed; + //Calculate the position where missile and the target will cross each others path. + auto intersection = lineLineIntersection(target_position, target_position + target_velocity, turn_exit, turn_exit + missile_velocity); + //Calculate the time it will take for the target and missile to reach the intersection + float turn_time = fabs(angle_diff) / data.turnrate; + float time_target = glm::length((target_position - intersection)) / target_velocity_length; + float time_missile = glm::length(turn_exit - intersection) / data.speed + turn_time; + //Calculate the time in which the radius will be on the intersection, to know in which time range we need to hit. + float time_radius = (target_radius * 0.5f) / target_velocity_length;//TODO: This value could be improved, as it is allowed to be bigger when the angle between the missile and the ship is low + // When both the missile and the target are at the same position at the same time, we can take a shot! + if (fabsf(time_target - time_missile) < time_radius) + return missile_angle; + + //When we cannot hit the target with this setup yet. Calculate a new intersection target, and aim for that. + float guessed_impact_time = (time_target * target_velocity_length / (target_velocity_length + data.speed)) + (time_missile * data.speed / (target_velocity_length + data.speed)); + auto new_target_position = target_position + target_velocity * guessed_impact_time; + missile_angle = vec2ToAngle(new_target_position - turn_exit); + } + } + return std::numeric_limits::infinity(); +} diff --git a/src/systems/missilesystem.h b/src/systems/missilesystem.h new file mode 100644 index 0000000000..79f8a42371 --- /dev/null +++ b/src/systems/missilesystem.h @@ -0,0 +1,19 @@ +#pragma once + +#include "ecs/system.h" +#include "components/missiletubes.h" + + +class MissileSystem : public sp::ecs::System +{ +public: + void update(float delta) override; + + static void startLoad(sp::ecs::Entity source, MissileTubes::MountPoint& tube, EMissileWeapons type); + 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); + +private: + static void spawnProjectile(sp::ecs::Entity source, MissileTubes::MountPoint& tube, float angle, sp::ecs::Entity target); +}; diff --git a/src/systems/shieldsystem.cpp b/src/systems/shieldsystem.cpp new file mode 100644 index 0000000000..4e58983b0b --- /dev/null +++ b/src/systems/shieldsystem.cpp @@ -0,0 +1,35 @@ +#include "systems/shieldsystem.h" + +#include "components/shields.h" +#include "components/docking.h" +#include "ecs/query.h" + + +void ShieldSystem::update(float delta) +{ + for(auto [entity, shields] : sp::ecs::Query()) + { + for(int n=0; n(); + if (port && port->state == DockingPort::State::Docked && port->target) + { + auto bay = port->target.getComponent(); + if (bay && (bay->flags & DockingBay::ChargeShield)) + rate *= 4.0f; + } + + shield.level = std::min(shield.max, shield.level + delta * rate); + } + if (shield.hit_effect > 0) + shield.hit_effect -= delta; + } + + } +} diff --git a/src/systems/shieldsystem.h b/src/systems/shieldsystem.h new file mode 100644 index 0000000000..e0aa68030e --- /dev/null +++ b/src/systems/shieldsystem.h @@ -0,0 +1,10 @@ +#pragma once + +#include "ecs/system.h" + + +class ShieldSystem : public sp::ecs::System +{ +public: + void update(float delta) override; +}; diff --git a/src/systems/warpsystem.cpp b/src/systems/warpsystem.cpp index 6924f8b325..4f7d8d36b0 100644 --- a/src/systems/warpsystem.cpp +++ b/src/systems/warpsystem.cpp @@ -13,7 +13,7 @@ void WarpSystem::update(float delta) { - for(auto [entity, warp, impulse, position, physics, obj] : sp::ecs::Query, sp::Position, sp::Physics, SpaceObject*>()) + for(auto [entity, warp, impulse, position, physics, obj] : sp::ecs::Query, sp::Transform, sp::Physics, SpaceObject*>()) { if (warp.request > 0 || warp.current > 0) { @@ -44,7 +44,7 @@ void WarpSystem::update(float delta) if (reactor) { // If warping, consume energy at a rate of 120% the warp request. // If shields are up, that rate is increased by an additional 50%. - auto energy_use = warp.energy_warp_per_second * delta * warp.get_system_effectiveness() * powf(warp.current, 1.3f); + auto energy_use = warp.energy_warp_per_second * delta * warp.getSystemEffectiveness() * powf(warp.current, 1.3f); auto ship = dynamic_cast(obj); if (ship && ship->getShieldsActive()) energy_use *= 1.7f; @@ -54,13 +54,13 @@ void WarpSystem::update(float delta) } // Add heat based on warp factor. - warp.add_heat(warp.current * delta * warp.heat_per_warp * warp.get_system_effectiveness()); + warp.addHeat(warp.current * delta * warp.heat_per_warp * warp.getSystemEffectiveness()); // Determine forward direction and velocity. auto forward = vec2FromAngle(position.getRotation()); auto current_velocity = physics.getVelocity(); if (!impulse) current_velocity = glm::vec2{0, 0}; - physics.setVelocity(current_velocity + forward * (warp.current * warp.speed_per_level * warp.get_system_effectiveness())); + physics.setVelocity(current_velocity + forward * (warp.current * warp.speed_per_level * warp.getSystemEffectiveness())); } } diff --git a/src/threatLevelEstimate.cpp b/src/threatLevelEstimate.cpp index 6d25691dcd..3b0fb2c78a 100644 --- a/src/threatLevelEstimate.cpp +++ b/src/threatLevelEstimate.cpp @@ -4,6 +4,7 @@ #include "spaceObjects/beamEffect.h" #include "spaceObjects/missiles/missileWeapon.h" #include "components/hull.h" +#include "components/shields.h" #include "systems/collision.h" @@ -52,11 +53,13 @@ float ThreatLevelEstimate::getThreatFor(P ship) if (ship->getShieldsActive()) threat += 200; - for(int n=0; nshield_count; n++) - threat += ship->shield_max[n] - ship->shield_level[n]; auto hull = ship->entity.getComponent(); if (hull) threat += hull->max - hull->current; + auto shields = ship->entity.getComponent(); + if (shields) + for(int n=0; ncount; n++) + threat += shields->entry[n].max - shields->entry[n].level; float radius = 7000.0; @@ -81,11 +84,13 @@ float ThreatLevelEstimate::getThreatFor(P ship) float score = 200.0f; if (hull) score += hull->max; - for(int n=0; nshield_count; n++) - { - score += other_ship->shield_max[n] * 2.0f / float(other_ship->shield_count); - if (other_ship->shield_hit_effect[n] > 0.0f) - is_being_attacked = true; + auto shields = entity.getComponent(); + if (shields) { + for(int n=0; ncount; n++) { + score += shields->entry[n].max * 2.0f / float(shields->count); + if (shields->entry[n].hit_effect > 0.0f) + is_being_attacked = true; + } } if (is_being_attacked) score += 500.0f; From 32207473c36e93f8d1b751fb060fdc4b585da514 Mon Sep 17 00:00:00 2001 From: Daid Date: Fri, 9 Dec 2022 16:14:03 +0100 Subject: [PATCH 019/320] Change maneuvering into ECS --- src/components/maneuveringthrusters.h | 30 ++++++++ src/systems/docking.cpp | 24 +++--- src/systems/maneuvering.cpp | 101 ++++++++++++++++++++++++++ src/systems/maneuvering.h | 11 +++ 4 files changed, 153 insertions(+), 13 deletions(-) create mode 100644 src/components/maneuveringthrusters.h create mode 100644 src/systems/maneuvering.cpp create mode 100644 src/systems/maneuvering.h diff --git a/src/components/maneuveringthrusters.h b/src/components/maneuveringthrusters.h new file mode 100644 index 0000000000..33b5c784e5 --- /dev/null +++ b/src/components/maneuveringthrusters.h @@ -0,0 +1,30 @@ +#pragma once + +#include "shipsystem.h" +#include + + +class ManeuveringThrusters : public ShipSystem { +public: + // Config + float speed = 10.0f; // [config] Speed of rotation, in deg/second + + // Runtime + float target = std::numeric_limits::min(); // [input] Ship will try to aim to this rotation. (degrees) + float rotation_request = std::numeric_limits::min(); // [input] Ship will rotate in this velocity. ([-1,1], overrides target_rotation) + + void stop() { target = std::numeric_limits::min(); rotation_request = std::numeric_limits::min(); } +}; + +class CombatManeuveringThrusters { +public: + float charge = 1.0f; // [output] How much charge there is in the combat maneuvering system (0.0-1.0) + + struct Thruster { + float request = 0.0f; // [input] How much boost we want at this moment (0.0-1.0) + float active = 0.0f; + float speed = 0.0f; /*< [config] Speed to indicate how fast we will fly forwards/sideways with a full boost/strafe */ + }; + Thruster boost; + Thruster strafe; +}; diff --git a/src/systems/docking.cpp b/src/systems/docking.cpp index ca24eebff3..9c24fb94c3 100644 --- a/src/systems/docking.cpp +++ b/src/systems/docking.cpp @@ -2,6 +2,7 @@ #include "components/docking.h" #include "components/collision.h" #include "components/impulse.h" +#include "components/maneuveringthrusters.h" #include "components/reactor.h" #include "components/hull.h" #include "components/warpdrive.h" @@ -25,7 +26,6 @@ void DockingSystem::update(float delta) for(auto [entity, docking_port, transform, obj] : sp::ecs::Query, SpaceObject*>()) { SpaceShip* ship = dynamic_cast(obj); PlayerSpaceship* player = dynamic_cast(obj); - if (!ship) continue; sp::Transform* target_transform; switch(docking_port.state) { case DockingPort::State::NotDocking: @@ -36,9 +36,11 @@ void DockingSystem::update(float delta) } else { auto engine = entity.getComponent(); auto warp = entity.getComponent(); - ship->target_rotation = vec2ToAngle(transform->getPosition() - target_transform->getPosition()); + auto thrusters = entity.getComponent(); + if (thrusters) + thrusters->target = vec2ToAngle(transform->getPosition() - target_transform->getPosition()); if (engine) { - if (fabs(angleDifference(ship->target_rotation, transform->getRotation())) < 10.0f) + if (thrusters && fabs(angleDifference(thrusters->target, transform->getRotation())) < 10.0f) engine->request = -1.f; else engine->request = 0.f; @@ -57,7 +59,8 @@ void DockingSystem::update(float delta) }else{ if (transform) { transform->setPosition(target_transform->getPosition() + rotateVec2(docking_port.docked_offset, target_transform->getRotation())); - ship->target_rotation = vec2ToAngle(transform->getPosition() - target_transform->getPosition()); + auto thrusters = entity.getComponent(); + if (thrusters) thrusters->target = vec2ToAngle(transform->getPosition() - target_transform->getPosition()); } auto bay = docking_port.target.getComponent(); @@ -162,9 +165,9 @@ void DockingSystem::collision(sp::ecs::Entity a, sp::ecs::Entity b, float force) if (port && port->state == DockingPort::State::Docking && port->target == b) { auto position = a.getComponent(); auto other_position = b.getComponent(); - auto ship = dynamic_cast(*a.getComponent()); + auto thrusters = a.getComponent(); - if (ship && position && other_position && fabs(angleDifference(ship->target_rotation, position->getRotation())) < 10.0f) + if (position && other_position && thrusters && fabs(angleDifference(thrusters->target, position->getRotation())) < 10.0f) { port->state = DockingPort::State::Docked; auto bay = b.getComponent(); @@ -226,11 +229,6 @@ void DockingSystem::abortDock(sp::ecs::Entity entity) if (engine) engine->request = 0.f; auto warp = entity.getComponent(); if (warp) warp->request = 0; - - auto obj = entity.getComponent(); - if (obj && *obj) { - auto ship = dynamic_cast(*obj); - if (ship) - ship->target_rotation = ship->getRotation(); - } + auto thrusters = entity.getComponent(); + if (thrusters) thrusters->stop(); } diff --git a/src/systems/maneuvering.cpp b/src/systems/maneuvering.cpp new file mode 100644 index 0000000000..4d0bfb7e41 --- /dev/null +++ b/src/systems/maneuvering.cpp @@ -0,0 +1,101 @@ +#include "systems/maneuvering.h" +#include "components/collision.h" +#include "components/maneuveringthrusters.h" +#include "components/impulse.h" +#include "ecs/query.h" +#include "vectorUtils.h" + + +void ManeuveringSystem::update(float delta) +{ + for(auto [entity, thrusters, transform, physics] : sp::ecs::Query()) { + float rotationDiff = 0.0f; + if (thrusters.rotation_request != std::numeric_limits::min()) + rotationDiff = thrusters.rotation_request; + if (thrusters.rotation_request) + rotationDiff = angleDifference(transform.getRotation(), thrusters.rotation_request); + + if (rotationDiff > 1.0f) + physics.setAngularVelocity(thrusters.speed * thrusters.getSystemEffectiveness()); + else if (rotationDiff < -1.0f) + physics.setAngularVelocity(-thrusters.speed * thrusters.getSystemEffectiveness()); + else + physics.setAngularVelocity(rotationDiff * thrusters.speed * thrusters.getSystemEffectiveness()); + } + + constexpr static float combat_maneuver_charge_time = 20.0f; /*< Amount of time it takes to fully charge the combat maneuver system */ + constexpr static float combat_maneuver_boost_max_time = 3.0f; /*< Amount of time we can boost with a fully charged combat maneuver system */ + constexpr static float combat_maneuver_strafe_max_time = 3.0f; /*< Amount of time we can strafe with a fully charged combat maneuver system */ + constexpr static float heat_per_combat_maneuver_boost = 0.2f; + constexpr static float heat_per_combat_maneuver_strafe = 0.2f; + + for(auto [entity, combat] : sp::ecs::Query()) { + if (combat.boost.active > combat.boost.request) + { + combat.boost.active -= delta; + if (combat.boost.active < combat.boost.request) + combat.boost.active = combat.boost.request; + } + if (combat.boost.active < combat.boost.request) + { + combat.boost.active += delta; + if (combat.boost.active > combat.boost.request) + combat.boost.active = combat.boost.request; + } + if (combat.strafe.active > combat.strafe.request) + { + combat.strafe.active -= delta; + if (combat.strafe.active < combat.strafe.request) + combat.strafe.active = combat.strafe.request; + } + if (combat.strafe.active < combat.strafe.request) + { + combat.strafe.active += delta; + if (combat.strafe.active > combat.strafe.request) + combat.strafe.active = combat.strafe.request; + } + + // If the ship is making a combat maneuver ... + if (combat.boost.active != 0.0f || combat.strafe.active != 0.0f) + { + // ... consume its combat maneuver boost. + combat.charge -= fabs(combat.boost.active) * delta / combat_maneuver_boost_max_time; + combat.charge -= fabs(combat.strafe.active) * delta / combat_maneuver_strafe_max_time; + + // Use boost only if we have boost available. + if (combat.charge <= 0.0f) + { + combat.charge = 0.0f; + combat.boost.request = 0.0f; + combat.strafe.request = 0.0f; + }else{ + auto physics = entity.getComponent(); + auto transform = entity.getComponent(); + if (physics && transform) + { + auto forward = vec2FromAngle(transform->getRotation()); + physics->setVelocity(physics->getVelocity() + forward * combat.boost.speed * combat.boost.active); + physics->setVelocity(physics->getVelocity() + vec2FromAngle(transform->getRotation() + 90) * combat.strafe.speed * combat.strafe.active); + } + } + // Add heat to systems consuming combat maneuver boost. + auto thrusters = entity.getComponent(); + if (thrusters) + thrusters->addHeat(std::abs(combat.boost.active) * delta * heat_per_combat_maneuver_boost); + auto impulse = entity.getComponent(); + if (impulse) + impulse->addHeat(std::abs(combat.strafe.active) * delta * heat_per_combat_maneuver_strafe); + }else if (combat.charge < 1.0f) + { + // If the ship isn't making a combat maneuver, recharge its boost. + auto thrusters = entity.getComponent(); + if (thrusters) + combat.charge += (delta / combat_maneuver_charge_time) * thrusters->getSystemEffectiveness() * 0.5f; + auto impulse = entity.getComponent(); + if (impulse) + combat.charge += (delta / combat_maneuver_charge_time) * impulse->getSystemEffectiveness() * 0.5f; + if (combat.charge > 1.0f) + combat.charge = 1.0f; + } + } +} diff --git a/src/systems/maneuvering.h b/src/systems/maneuvering.h new file mode 100644 index 0000000000..d5035e7f9f --- /dev/null +++ b/src/systems/maneuvering.h @@ -0,0 +1,11 @@ +#pragma once + +#include "ecs/system.h" +#include "ecs/entity.h" + + +class ManeuveringSystem : public sp::ecs::System +{ +public: + void update(float delta) override; +}; From a8913d4d2e07962e5f4e915e82bf49f3486a1501 Mon Sep 17 00:00:00 2001 From: Daid Date: Thu, 15 Dec 2022 14:54:50 +0100 Subject: [PATCH 020/320] ShipSystems to ECS, this was a large change --- CMakeLists.txt | 10 + src/ai/ai.cpp | 30 +- src/ai/fighterAI.cpp | 4 +- src/ai/missileVolleyAI.cpp | 4 +- src/components/beamweapon.h | 2 +- src/components/coolant.h | 11 + src/components/reactor.h | 3 +- src/components/shipsystem.cpp | 61 +++ src/components/shipsystem.h | 48 ++- src/gameStateLogger.cpp | 34 +- src/hardware/hardwareController.cpp | 12 +- src/main.cpp | 10 + src/menus/shipSelectionScreen.cpp | 1 - src/repairCrew.cpp | 25 +- src/screenComponents/beamTargetSelector.cpp | 8 +- src/screenComponents/combatManeuver.cpp | 15 +- src/screenComponents/hackingDialog.cpp | 22 +- src/screenComponents/hackingDialog.h | 4 +- src/screenComponents/impulseControls.cpp | 2 +- src/screenComponents/impulseSound.cpp | 2 +- src/screenComponents/jumpControls.cpp | 2 +- src/screenComponents/missileTubeControls.cpp | 2 +- src/screenComponents/powerDamageIndicator.cpp | 31 +- src/screenComponents/powerDamageIndicator.h | 4 +- src/screenComponents/shieldsEnableButton.cpp | 2 +- src/screenComponents/shipInternalView.cpp | 29 +- src/screenComponents/shipInternalView.h | 4 +- src/screenComponents/warpControls.cpp | 2 +- src/screens/crew1/singlePilotScreen.cpp | 4 +- src/screens/crew4/tacticalScreen.cpp | 6 +- src/screens/crew6/engineeringScreen.cpp | 355 ++++++++++-------- src/screens/crew6/engineeringScreen.h | 4 +- src/screens/crew6/scienceScreen.cpp | 21 +- src/screens/crew6/scienceScreen.h | 2 +- src/screens/crew6/weaponsScreen.cpp | 6 +- src/screens/extra/damcon.cpp | 26 +- src/screens/extra/damcon.h | 2 +- src/screens/extra/powerManagement.cpp | 84 +++-- src/screens/extra/powerManagement.h | 4 +- src/screens/gm/tweak.cpp | 78 ++-- src/screens/gm/tweak.h | 18 +- src/shipTemplate.cpp | 48 +-- src/shipTemplate.h | 31 +- src/shipTemplate.hpp | 22 +- src/spaceObjects/cpuShip.cpp | 14 +- src/spaceObjects/playerSpaceship.cpp | 275 +++----------- src/spaceObjects/playerSpaceship.h | 23 +- src/spaceObjects/spaceObject.cpp | 8 +- src/spaceObjects/spaceObject.h | 11 +- src/spaceObjects/spaceship.cpp | 282 +++----------- src/spaceObjects/spaceship.h | 136 ++----- src/systems/coolantsystem.cpp | 57 +++ src/systems/coolantsystem.h | 11 + src/systems/energysystem.cpp | 62 +++ src/systems/energysystem.h | 11 + src/systems/impulse.cpp | 2 +- src/systems/shipsystemssystem.cpp | 57 +++ src/systems/shipsystemssystem.h | 16 + 58 files changed, 1024 insertions(+), 1036 deletions(-) create mode 100644 src/components/coolant.h create mode 100644 src/systems/coolantsystem.cpp create mode 100644 src/systems/coolantsystem.h create mode 100644 src/systems/energysystem.cpp create mode 100644 src/systems/energysystem.h create mode 100644 src/systems/shipsystemssystem.cpp create mode 100644 src/systems/shipsystemssystem.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f7362429c..665f86559a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -355,9 +355,11 @@ set(MAIN_SOURCES src/components/hull.h src/components/rendering.h src/components/docking.h + src/components/coolant.h src/components/shipsystem.h src/components/shipsystem.cpp src/components/impulse.h + src/components/maneuveringthrusters.h src/components/warpdrive.h src/components/jumpdrive.h src/components/reactor.h @@ -367,8 +369,16 @@ set(MAIN_SOURCES src/components/missiletubes.h src/systems/docking.h src/systems/docking.cpp + src/systems/shipsystemssystem.h + src/systems/shipsystemssystem.cpp + src/systems/coolantsystem.h + src/systems/coolantsystem.cpp + src/systems/energysystem.h + src/systems/energysystem.cpp src/systems/impulse.h src/systems/impulse.cpp + src/systems/maneuvering.h + src/systems/maneuvering.cpp src/systems/beamweapon.h src/systems/beamweapon.cpp src/systems/missilesystem.h diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp index 55820ac059..86d437829a 100644 --- a/src/ai/ai.cpp +++ b/src/ai/ai.cpp @@ -11,6 +11,7 @@ #include "components/hull.h" #include "components/beamweapon.h" #include "components/missiletubes.h" +#include "components/maneuveringthrusters.h" #include "systems/collision.h" #include "systems/jumpsystem.h" #include "systems/docking.h" @@ -63,7 +64,9 @@ void ShipAI::drawOnGMRadar(sp::RenderTarget& renderer, glm::vec2 draw_position, void ShipAI::run(float delta) { - owner->target_rotation = owner->getRotation(); + auto thrusters = owner->entity.getComponent(); + if (thrusters) thrusters->stop(); + auto impulse = owner->entity.getComponent(); if (impulse) impulse->request = 0.0f; @@ -551,7 +554,8 @@ void ShipAI::runAttack(P target) if (owner->getOrder() == AI_StandGround) { - owner->target_rotation = vec2ToAngle(position_diff); + auto thrusters = owner->entity.getComponent(); + if (thrusters) thrusters->target = vec2ToAngle(position_diff); }else{ if (weapon_direction == EWeaponDirection::Side || weapon_direction == EWeaponDirection::Left || weapon_direction == EWeaponDirection::Right) { @@ -585,8 +589,10 @@ void ShipAI::flyTowards(glm::vec2 target, float keep_distance) float distance = glm::length(diff); //Normal flying towards target code - owner->target_rotation = vec2ToAngle(diff); - float rotation_diff = fabs(angleDifference(owner->target_rotation, owner->getRotation())); + auto target_rotation = vec2ToAngle(diff); + auto thrusters = owner->entity.getComponent(); + if (thrusters) thrusters->target = target_rotation; + float rotation_diff = fabs(angleDifference(target_rotation, owner->getRotation())); auto warp = owner->entity.getComponent(); if (warp && rotation_diff < 30.0f && distance > 2000.0f) @@ -646,6 +652,7 @@ void ShipAI::flyFormation(P target, glm::vec2 offset) if (pathPlanner.route.size() == 1) { + auto thrusters = owner->entity.getComponent(); auto docking_port = owner->entity.getComponent(); if (docking_port && docking_port->state == DockingPort::State::Docked) DockingSystem::requestUndock(owner->entity); @@ -655,14 +662,14 @@ void ShipAI::flyFormation(P target, glm::vec2 offset) //Formation flying code float r = owner->getRadius() * 5.0f; - owner->target_rotation = vec2ToAngle(diff); + auto target_rotation = vec2ToAngle(diff); if (distance > r * 3) { flyTowards(target_position); } else if (distance > r) { - float angle_diff = angleDifference(owner->target_rotation, owner->getRotation()); + float angle_diff = angleDifference(target_rotation, owner->getRotation()); if (angle_diff > 10.0f) impulse->request = 0.0f; else if (angle_diff > 5.0f) @@ -672,13 +679,14 @@ void ShipAI::flyFormation(P target, glm::vec2 offset) }else{ if (distance > r / 2.0f) { - owner->target_rotation += angleDifference(owner->target_rotation, target->getRotation()) * (1.0f - distance / r); + target_rotation += angleDifference(target_rotation, target->getRotation()) * (1.0f - distance / r); impulse->request = distance / r; }else{ - owner->target_rotation = target->getRotation(); + target_rotation = target->getRotation(); impulse->request = 0.0f; } } + if (thrusters) thrusters->target = target_rotation; }else{ flyTowards(target_position); } @@ -718,7 +726,8 @@ float ShipAI::targetScore(P target) //auto position_difference_normal = position_difference / distance; //float rel_velocity = dot(target->getVelocity(), position_difference_normal) - dot(getVelocity(), position_difference_normal); float angle_difference = angleDifference(owner->getRotation(), vec2ToAngle(position_difference)); - float score = -distance - std::abs(angle_difference / owner->turn_speed * (impulse ? impulse->max_speed_forward : 0.0f)) * 1.5f; + auto thrusters = owner->entity.getComponent(); + float score = -distance - std::abs(angle_difference / (thrusters ? thrusters->speed : 10.0f) * (impulse ? impulse->max_speed_forward : 0.0f)) * 1.5f; if (P(target)) { score -= 5000; @@ -872,7 +881,8 @@ P ShipAI::findBestMissileRestockTarget(glm::vec2 position, float ra auto position_difference = obj->getPosition() - owner_position; float distance = glm::length(position_difference); float angle_difference = angleDifference(owner->getRotation(), vec2ToAngle(position_difference)); - float score = -distance - std::abs(angle_difference / owner->turn_speed * impulse.max_speed_forward) * 1.5f; + auto thrusters = owner->entity.getComponent(); + float score = -distance - std::abs(angle_difference / (thrusters ? thrusters->speed : 10.0f) * impulse.max_speed_forward) * 1.5f; if (P(P(obj))) { score -= 5000; diff --git a/src/ai/fighterAI.cpp b/src/ai/fighterAI.cpp index d296cc5848..d7bb8da796 100644 --- a/src/ai/fighterAI.cpp +++ b/src/ai/fighterAI.cpp @@ -2,6 +2,7 @@ #include "components/impulse.h" #include "components/shields.h" #include "components/missiletubes.h" +#include "components/maneuveringthrusters.h" #include "systems/missilesystem.h" #include "ai/fighterAI.h" #include "ai/aiFactory.h" @@ -99,7 +100,8 @@ void FighterAI::runAttack(P target) } else { - owner->target_rotation = evade_direction; + auto thrusters = owner->entity.getComponent(); + if (thrusters) thrusters->target = evade_direction; auto impulse = owner->entity.getComponent(); if (impulse) impulse->request = 1.0; diff --git a/src/ai/missileVolleyAI.cpp b/src/ai/missileVolleyAI.cpp index dcbd811329..0e2c57ecd1 100644 --- a/src/ai/missileVolleyAI.cpp +++ b/src/ai/missileVolleyAI.cpp @@ -1,5 +1,6 @@ #include "spaceObjects/cpuShip.h" #include "components/missiletubes.h" +#include "components/maneuveringthrusters.h" #include "systems/missilesystem.h" #include "ai/missileVolleyAI.h" #include "ai/aiFactory.h" @@ -111,7 +112,8 @@ void MissileVolleyAI::runAttack(P target) if (owner->getOrder() == AI_StandGround) { - owner->target_rotation = vec2ToAngle(target_position - owner->getPosition()); + auto thrusters = owner->entity.getComponent(); + if (thrusters) thrusters->target = vec2ToAngle(target_position - owner->getPosition()); }else{ flyTowards(target_position, 0.0f); } diff --git a/src/components/beamweapon.h b/src/components/beamweapon.h index 7729d1fe9e..844b41d2da 100644 --- a/src/components/beamweapon.h +++ b/src/components/beamweapon.h @@ -32,7 +32,7 @@ class BeamWeaponSys : public ShipSystem { }; int frequency = 0; - ESystem system_target = SYS_None; + ShipSystem::Type system_target = ShipSystem::Type::None; sp::ecs::Entity target; MountPoint mounts[max_beam_weapons]; diff --git a/src/components/coolant.h b/src/components/coolant.h new file mode 100644 index 0000000000..071f8a5912 --- /dev/null +++ b/src/components/coolant.h @@ -0,0 +1,11 @@ +#pragma once + +// The coolant component interacts heavily with the ShipComponents. +// An important aspect is that if this component exists, the ShipComponents will interact with coolant and heat. +class Coolant +{ +public: + float max = 10.0f; + float max_coolant_per_system = 10.0f; + bool auto_levels = false; +}; \ No newline at end of file diff --git a/src/components/reactor.h b/src/components/reactor.h index 653b1cd0f5..4d607ea08d 100644 --- a/src/components/reactor.h +++ b/src/components/reactor.h @@ -6,11 +6,10 @@ class Reactor : public ShipSystem { public: // Config + float max_energy = 1000.0f; // Runtime float energy = 1000.0f; - float max_energy = 1000.0f; - bool use_energy(float amount) { if (amount > energy) return false; energy -= amount; return true; } }; \ No newline at end of file diff --git a/src/components/shipsystem.cpp b/src/components/shipsystem.cpp index f601e74b95..706f805bfb 100644 --- a/src/components/shipsystem.cpp +++ b/src/components/shipsystem.cpp @@ -1,5 +1,27 @@ #include "shipsystem.h" #include "gameGlobalInfo.h" +#include "components/reactor.h" +#include "components/beamweapon.h" +#include "components/missiletubes.h" +#include "components/shields.h" +#include "components/impulse.h" +#include "components/maneuveringthrusters.h" +#include "components/jumpdrive.h" +#include "components/warpdrive.h" + +// TODO +static std::array default_system_power_factors{ + /*ShipSystem::Type::Reactor*/ -25.f, + /*ShipSystem::Type::BeamWeapons*/ 3.f, + /*ShipSystem::Type::MissileSystem*/ 1.f, + /*ShipSystem::Type::Maneuver*/ 2.f, + /*ShipSystem::Type::Impulse*/ 4.f, + /*ShipSystem::Type::Warp*/ 5.f, + /*ShipSystem::Type::JumpDrive*/ 5.f, + /*ShipSystem::Type::FrontShield*/ 5.f, + /*ShipSystem::Type::RearShield*/ 5.f, +}; + // Overheat subsystem damage rate constexpr static float damage_per_second_on_overheat = 0.08f; @@ -56,4 +78,43 @@ void ShipSystem::addHeat(float amount) if (heat_level < 0.0f) heat_level = 0.0f; +} + +ShipSystem* ShipSystem::get(sp::ecs::Entity entity, Type type) +{ + switch(type) + { + case Type::None: + case Type::COUNT: + return nullptr; + case Type::Reactor: + return entity.getComponent(); + case Type::BeamWeapons: + return entity.getComponent(); + case Type::MissileSystem: + return entity.getComponent(); + case Type::Maneuver: + return entity.getComponent(); + case Type::Impulse: + return entity.getComponent(); + case Type::Warp: + return entity.getComponent(); + case Type::JumpDrive: + return entity.getComponent(); + case Type::FrontShield: + { + auto shields = entity.getComponent(); + if (shields) + return &shields->front_system; + return nullptr; + } + case Type::RearShield: + { + auto shields = entity.getComponent(); + if (shields && shields->count > 1) + return &shields->rear_system; + return nullptr; + } + } + return nullptr; } \ No newline at end of file diff --git a/src/components/shipsystem.h b/src/components/shipsystem.h index e2b612867a..cf9c4e9bba 100644 --- a/src/components/shipsystem.h +++ b/src/components/shipsystem.h @@ -1,27 +1,55 @@ #pragma once +#include "ecs/entity.h" +#include + //Base class for ship systems, ever created directly, use as base class for other components. class ShipSystem { public: + enum class Type + { + None = -1, + Reactor = 0, + BeamWeapons, + MissileSystem, + Maneuver, + Impulse, + Warp, + JumpDrive, + FrontShield, + RearShield, + COUNT + }; + static constexpr int COUNT = static_cast(Type::COUNT); + static constexpr float power_factor_rate = 0.08f; static constexpr float default_add_heat_rate_per_second = 0.05f; static constexpr float default_power_rate_per_second = 0.3f; static constexpr float default_coolant_rate_per_second = 1.2f; - float health; //1.0-0.0, where 0.0 is fully broken. - float health_max; //1.0-0.0, where 0.0 is fully broken. - float power_level; //0.0-3.0, default 1.0 - float power_request; - float heat_level; //0.0-1.0, system will damage at 1.0 - float coolant_level; //0.0-10.0 - float coolant_request; - float hacked_level; //0.0-1.0 - float power_factor; + float health = 1.0f; //1.0-0.0, where 0.0 is fully broken. + float health_max = 1.0f; //1.0-0.0, where 0.0 is fully broken. + bool auto_repair; + float power_level = 1.0f; //0.0-3.0, default 1.0 + float power_request = 1.0f; + float heat_level = 0.0f; //0.0-1.0, system will damage at 1.0 + float coolant_level = 0.0f; //0.0-10.0 + float coolant_request = 0.0f; + float hacked_level = 0.0f; //0.0-1.0 + float power_factor = 1.0f; float coolant_change_rate_per_second = default_coolant_rate_per_second; float heat_add_rate_per_second = default_add_heat_rate_per_second; float power_change_rate_per_second = default_power_rate_per_second; + float auto_repair_per_second = 0.0f; // = 0.005f; for CPU ships float getSystemEffectiveness(); void addHeat(float amount); -}; \ No newline at end of file + + float getHeatingDelta() const + { + return std::pow(1.7f, power_level - 1.0f) - (1.01f + coolant_level * 0.1f); + } + + static ShipSystem* get(sp::ecs::Entity entity, Type type); +}; diff --git a/src/gameStateLogger.cpp b/src/gameStateLogger.cpp index a21de10141..4b836bf87c 100644 --- a/src/gameStateLogger.cpp +++ b/src/gameStateLogger.cpp @@ -379,6 +379,7 @@ void GameStateLogger::writeShipEntry(JSONGenerator& json, P ship) json.endArray(); } */ + /* { JSONGenerator systems = json.createDict("systems"); for(int n=0; n ship) } } } + */ { JSONGenerator input = json.createDict("input"); - input.write("rotation", ship->target_rotation); + //input.write("rotation", ship->target_rotation); //input.write("impulse", ship->impulse_request); //if (ship->has_warp_drive) // input.write("warp", ship->warp_request); - if (ship->combat_maneuver_boost_speed > 0) - input.write("combat_maneuver_boost", ship->combat_maneuver_boost_request); - if (ship->combat_maneuver_strafe_speed > 0) - input.write("combat_maneuver_strafe", ship->combat_maneuver_strafe_request); + //if (ship->combat_maneuver_boost_speed > 0) + // input.write("combat_maneuver_boost", ship->combat_maneuver_boost_request); + //if (ship->combat_maneuver_strafe_speed > 0) + // input.write("combat_maneuver_strafe", ship->combat_maneuver_strafe_request); } { JSONGenerator output = json.createDict("output"); //output.write("impulse", ship->current_impulse); //if (ship->has_warp_drive) // output.write("warp", ship->current_warp); - if (ship->combat_maneuver_boost_speed > 0 || ship->combat_maneuver_strafe_speed > 0) - output.write("combat_maneuver_charge", ship->combat_maneuver_charge); - if (ship->combat_maneuver_boost_speed > 0) - output.write("combat_maneuver_boost", ship->combat_maneuver_boost_active); - if (ship->combat_maneuver_strafe_speed > 0) - output.write("combat_maneuver_strafe", ship->combat_maneuver_strafe_active); + //if (ship->combat_maneuver_boost_speed > 0 || ship->combat_maneuver_strafe_speed > 0) + // output.write("combat_maneuver_charge", ship->combat_maneuver_charge); + //if (ship->combat_maneuver_boost_speed > 0) + // output.write("combat_maneuver_boost", ship->combat_maneuver_boost_active); + //if (ship->combat_maneuver_strafe_speed > 0) + // output.write("combat_maneuver_strafe", ship->combat_maneuver_strafe_active); /*if (ship->has_jump_drive) { JSONGenerator jump = output.createDict("jump"); @@ -435,7 +437,7 @@ void GameStateLogger::writeShipEntry(JSONGenerator& json, P ship) } { JSONGenerator config = json.createDict("config"); - config.write("turn_speed", ship->turn_speed); + //config.write("turn_speed", ship->turn_speed); //config.write("impulse_speed", ship->impulse_max_speed); //config.write("impulse_acceleration", ship->impulse_acceleration); //config.write("impulse_reverse_speed", ship->impulse_max_reverse_speed); @@ -443,10 +445,10 @@ void GameStateLogger::writeShipEntry(JSONGenerator& json, P ship) //config.write("hull", ship->hull_max); //if (ship->has_warp_drive) // config.write("warp", ship->warp_speed_per_warp_level); - if (ship->combat_maneuver_boost_speed > 0) - config.write("combat_maneuver_boost", ship->combat_maneuver_boost_speed); - if (ship->combat_maneuver_strafe_speed > 0) - config.write("combat_maneuver_strafe", ship->combat_maneuver_strafe_speed); + //if (ship->combat_maneuver_boost_speed > 0) + // config.write("combat_maneuver_boost", ship->combat_maneuver_boost_speed); + //if (ship->combat_maneuver_strafe_speed > 0) + // config.write("combat_maneuver_strafe", ship->combat_maneuver_strafe_speed); //if (ship->has_jump_drive) // config.write("jumpdrive", true); /* diff --git a/src/hardware/hardwareController.cpp b/src/hardware/hardwareController.cpp index 2aa69183cf..f98424507e 100644 --- a/src/hardware/hardwareController.cpp +++ b/src/hardware/hardwareController.cpp @@ -391,13 +391,13 @@ bool HardwareController::getVariableValue(string variable_name, float& value) //SHIP_VARIABLE("TubeUnloading" + string(n), ship->weapon_tube[n].isUnloading() ? 1.0f : 0.0f); //SHIP_VARIABLE("TubeFiring" + string(n), ship->weapon_tube[n].isFiring() ? 1.0f : 0.0f); } - for(int n=0; nsystems[n].health); - SHIP_VARIABLE(getSystemName(ESystem(n)).replace(" ", "") + "Power", ship->systems[n].power_level / 3.0f); - SHIP_VARIABLE(getSystemName(ESystem(n)).replace(" ", "") + "Heat", ship->systems[n].heat_level); - SHIP_VARIABLE(getSystemName(ESystem(n)).replace(" ", "") + "Coolant", ship->systems[n].coolant_level); - SHIP_VARIABLE(getSystemName(ESystem(n)).replace(" ", "") + "Hacked", ship->systems[n].hacked_level); + //SHIP_VARIABLE(getSystemName(ESystem(n)).replace(" ", "") + "Health", ship->systems[n].health); + //SHIP_VARIABLE(getSystemName(ESystem(n)).replace(" ", "") + "Power", ship->systems[n].power_level / 3.0f); + //SHIP_VARIABLE(getSystemName(ESystem(n)).replace(" ", "") + "Heat", ship->systems[n].heat_level); + //SHIP_VARIABLE(getSystemName(ESystem(n)).replace(" ", "") + "Coolant", ship->systems[n].coolant_level); + //SHIP_VARIABLE(getSystemName(ESystem(n)).replace(" ", "") + "Hacked", ship->systems[n].hacked_level); } LOG(WARNING) << "Unknown variable: " << variable_name; diff --git a/src/main.cpp b/src/main.cpp index 836c8038f3..1f3d2f52a9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -30,8 +30,14 @@ #include "systems/docking.h" #include "systems/impulse.h" #include "systems/warpsystem.h" +#include "systems/jumpsystem.h" #include "systems/beamweapon.h" #include "systems/shieldsystem.h" +#include "systems/shipsystemssystem.h" +#include "systems/coolantsystem.h" +#include "systems/missilesystem.h" +#include "systems/maneuvering.h" +#include "systems/energysystem.h" #include "packResourceProvider.h" #include "main.h" #include "epsilonServer.h" @@ -140,9 +146,13 @@ int main(int argc, char** argv) new Engine(); engine->registerSystem(); engine->registerSystem(); + engine->registerSystem(); engine->registerSystem(); + engine->registerSystem(); engine->registerSystem(); engine->registerSystem(); + engine->registerSystem(); + engine->registerSystem(); string configuration_path = "."; if (getenv("HOME")) configuration_path = string(getenv("HOME")) + "/.emptyepsilon"; diff --git a/src/menus/shipSelectionScreen.cpp b/src/menus/shipSelectionScreen.cpp index 468df1091e..6202a8eb42 100644 --- a/src/menus/shipSelectionScreen.cpp +++ b/src/menus/shipSelectionScreen.cpp @@ -323,7 +323,6 @@ ShipSelectionScreen::ShipSelectionScreen() { // set the position before the template so that onNewPlayerShip has as much data as possible ship->setRotation(random(0, 360)); - ship->target_rotation = ship->getRotation(); ship->setPosition(glm::vec2(random(-100, 100), random(-100, 100))); ship->setTemplate(ship_template_selector->getSelectionValue()); my_player_info->commandSetShipId(ship->getMultiplayerId()); diff --git a/src/repairCrew.cpp b/src/repairCrew.cpp index a64069927e..6871a676c9 100644 --- a/src/repairCrew.cpp +++ b/src/repairCrew.cpp @@ -190,25 +190,26 @@ void RepairCrew::update(float delta) } position = glm::vec2{pos.x, pos.y}; - ESystem system = ship->ship_template->getSystemAtRoom(pos); - if (system != SYS_None) + auto system = ShipSystem::get(ship->entity, ship->ship_template->getSystemAtRoom(pos)); + if (system) { - ship->systems[system].health += repair_per_second * delta; - if (ship->systems[system].health > 1.0f) - ship->systems[system].health = 1.0; - ship->systems[system].hacked_level -= repair_per_second * delta; - if (ship->systems[system].hacked_level < 0.0f) - ship->systems[system].hacked_level = 0.0; + system->health += repair_per_second * delta; + if (system->health > 1.0f) + system->health = 1.0; + system->hacked_level -= repair_per_second * delta; + if (system->hacked_level < 0.0f) + system->hacked_level = 0.0; } - if (ship->auto_repair_enabled && pos == target_position && (system == SYS_None || !ship->hasSystem(system) || ship->systems[system].health == 1.0f)) + if (ship->auto_repair_enabled && pos == target_position && (!system || system->health == 1.0f)) { - int n=irandom(0, SYS_COUNT - 1); + int n=irandom(0, ShipSystem::COUNT - 1); - if (ship->hasSystem(ESystem(n)) && ship->systems[n].health < 1.0f) + system = ShipSystem::get(ship->entity, ShipSystem::Type(n)); + if (system && system->health < 1.0f) { for(unsigned int idx=0; idxship_template->rooms.size(); idx++) { - if (ship->ship_template->rooms[idx].system == ESystem(n)) + if (ship->ship_template->rooms[idx].system == ShipSystem::Type(n)) { target_position = ship->ship_template->rooms[idx].position + glm::ivec2(irandom(0, ship->ship_template->rooms[idx].size.x - 1), irandom(0, ship->ship_template->rooms[idx].size.y - 1)); } diff --git a/src/screenComponents/beamTargetSelector.cpp b/src/screenComponents/beamTargetSelector.cpp index 67518392f0..6efc6e4716 100644 --- a/src/screenComponents/beamTargetSelector.cpp +++ b/src/screenComponents/beamTargetSelector.cpp @@ -6,15 +6,15 @@ #include "components/beamweapon.h" GuiBeamTargetSelector::GuiBeamTargetSelector(GuiContainer* owner, string id) -: GuiSelector(owner, id, [](int index, string value) { if (my_spaceship) my_spaceship->commandSetBeamSystemTarget(ESystem(index + SYS_None)); }) +: GuiSelector(owner, id, [](int index, string value) { if (my_spaceship) my_spaceship->commandSetBeamSystemTarget(ShipSystem::Type(index + int(ShipSystem::Type::None))); }) { addEntry(tr("target","Hull"), "-1"); - for(int n=0; nentity.getComponent(); if (beamweapons) - setSelectionIndex(beamweapons->system_target - SYS_None); + setSelectionIndex(int(beamweapons->system_target) - int(ShipSystem::Type::None)); } if (!gameGlobalInfo->use_system_damage) hide(); diff --git a/src/screenComponents/combatManeuver.cpp b/src/screenComponents/combatManeuver.cpp index d3eb5ab203..64ea8bdfb6 100644 --- a/src/screenComponents/combatManeuver.cpp +++ b/src/screenComponents/combatManeuver.cpp @@ -1,6 +1,7 @@ #include #include "playerInfo.h" #include "spaceObjects/playerSpaceship.h" +#include "components/maneuveringthrusters.h" #include "combatManeuver.h" #include "powerDamageIndicator.h" #include "snapSlider.h" @@ -24,8 +25,8 @@ GuiCombatManeuver::GuiCombatManeuver(GuiContainer* owner, string id) }); slider->setPosition(0, -50, sp::Alignment::BottomCenter)->setSize(GuiElement::GuiSizeMax, 165); - (new GuiPowerDamageIndicator(slider, id + "_STRAFE_INDICATOR", SYS_Maneuver, sp::Alignment::CenterLeft))->setPosition(0, 0, sp::Alignment::BottomLeft)->setSize(GuiElement::GuiSizeMax, 50); - (new GuiPowerDamageIndicator(slider, id + "_BOOST_INDICATOR", SYS_Impulse, sp::Alignment::BottomLeft))->setPosition(0, 0, sp::Alignment::BottomLeft)->setSize(GuiElement::GuiSizeMax, 50); + (new GuiPowerDamageIndicator(slider, id + "_STRAFE_INDICATOR", ShipSystem::Type::Maneuver, sp::Alignment::CenterLeft))->setPosition(0, 0, sp::Alignment::BottomLeft)->setSize(GuiElement::GuiSizeMax, 50); + (new GuiPowerDamageIndicator(slider, id + "_BOOST_INDICATOR", ShipSystem::Type::Impulse, sp::Alignment::BottomLeft))->setPosition(0, 0, sp::Alignment::BottomLeft)->setSize(GuiElement::GuiSizeMax, 50); } void GuiCombatManeuver::onUpdate() @@ -49,13 +50,13 @@ void GuiCombatManeuver::onDraw(sp::RenderTarget& target) { if (my_spaceship) { - if (my_spaceship->combat_maneuver_boost_speed <= 0.0f && my_spaceship->combat_maneuver_strafe_speed <= 0.0f) - { + auto thrusters = my_spaceship->entity.getComponent(); + if (thrusters) { + charge_bar->setValue(thrusters->charge)->show(); + slider->show(); + } else { charge_bar->hide(); slider->hide(); - }else{ - charge_bar->setValue(my_spaceship->combat_maneuver_charge)->show(); - slider->show(); } } } diff --git a/src/screenComponents/hackingDialog.cpp b/src/screenComponents/hackingDialog.cpp index c9f2480ff3..63852f4492 100644 --- a/src/screenComponents/hackingDialog.cpp +++ b/src/screenComponents/hackingDialog.cpp @@ -58,8 +58,7 @@ GuiHackingDialog::GuiHackingDialog(GuiContainer* owner, string id) target_list = new GuiListbox(target_selection_box, "", [this](int index, string value) { - target_system = value; - locale_target_system = target_list->getEntryName(index); + target_system = ShipSystem::Type(value.toInt()); getNewGame(); }); target_list->setPosition(25, 75, sp::Alignment::TopLeft); @@ -74,16 +73,15 @@ void GuiHackingDialog::open(P target) show(); while(target_list->entryCount() > 0) target_list->removeEntry(0); - std::vector > targets = target->getHackingTargets(); - for(std::pair& target : targets) + std::vector > targets = target->getHackingTargets(); + for(auto& target : targets) { - target_list->addEntry(getLocaleSystemName(target.first), getSystemName(target.first)); + target_list->addEntry(getLocaleSystemName(target.first), string(int(target.first))); } if (targets.size() == 1) { target_selection_box->hide(); - target_system = getSystemName(targets[0].first); - locale_target_system = getLocaleSystemName(targets[0].first); + target_system = targets[0].first; getNewGame(); } else { target_selection_box->show(); @@ -115,14 +113,14 @@ void GuiHackingDialog::onDraw(sp::RenderTarget& renderer) progress_bar->setValue(game->getProgress()); status_label->setText(tr("hacking", "Hacking in Progress: {percent}%").format({{"percent", string(int(100 * game->getProgress()))}})); } - if (target_system != "") + if (target_system != ShipSystem::Type::None) { - std::vector > targets = target->getHackingTargets(); - for(std::pair& target : targets) + auto targets = target->getHackingTargets(); + for(auto& target : targets) { - if (getSystemName(target.first) == target_system) + if (target.first == target_system) { - hacking_status_label->setText(tr("hacking", "{target}: hacked {percent}%").format({{"target", locale_target_system}, {"percent", string(int(target.second * 100.0f + 0.5f))}})); + hacking_status_label->setText(tr("hacking", "{target}: hacked {percent}%").format({{"target", getLocaleSystemName(target_system)}, {"percent", string(int(target.second * 100.0f + 0.5f))}})); break; } } diff --git a/src/screenComponents/hackingDialog.h b/src/screenComponents/hackingDialog.h index 0585d0b84b..c4e0394ae2 100644 --- a/src/screenComponents/hackingDialog.h +++ b/src/screenComponents/hackingDialog.h @@ -2,6 +2,7 @@ #define HACKING_DIALOG_H #include "gui/gui2_overlay.h" +#include "components/shipsystem.h" #include class GuiPanel; @@ -25,8 +26,7 @@ class GuiHackingDialog : public GuiOverlay private: P target; - string target_system; - string locale_target_system; + ShipSystem::Type target_system = ShipSystem::Type::None; float reset_time; static constexpr float auto_reset_time = 2.0f; bool last_game_success; diff --git a/src/screenComponents/impulseControls.cpp b/src/screenComponents/impulseControls.cpp index 6a7c0ce240..8a7297f5f4 100644 --- a/src/screenComponents/impulseControls.cpp +++ b/src/screenComponents/impulseControls.cpp @@ -19,7 +19,7 @@ GuiImpulseControls::GuiImpulseControls(GuiContainer* owner, string id) label = new GuiKeyValueDisplay(this, id, 0.5, tr("slider", "Impulse"), "0%"); label->setTextSize(30)->setPosition(50, 0, sp::Alignment::TopLeft)->setSize(40, GuiElement::GuiSizeMax); - (new GuiPowerDamageIndicator(this, id + "_DPI", SYS_Impulse, sp::Alignment::TopCenter))->setSize(50, GuiElement::GuiSizeMax); + (new GuiPowerDamageIndicator(this, id + "_DPI", ShipSystem::Type::Impulse, sp::Alignment::TopCenter))->setSize(50, GuiElement::GuiSizeMax); } void GuiImpulseControls::onDraw(sp::RenderTarget& target) diff --git a/src/screenComponents/impulseSound.cpp b/src/screenComponents/impulseSound.cpp index 5f481e1071..cb9b6b1288 100644 --- a/src/screenComponents/impulseSound.cpp +++ b/src/screenComponents/impulseSound.cpp @@ -62,7 +62,7 @@ void ImpulseSound::update(float delta) if (!my_spaceship) return; auto engine = my_spaceship->entity.getComponent(); // Get whether the ship's impulse engines are functional. - float impulse_ability = std::max(0.0f, std::min(my_spaceship->getSystemEffectiveness(SYS_Impulse), my_spaceship->getSystemPower(SYS_Impulse))); + float impulse_ability = std::max(0.0f, std::min(engine->getSystemEffectiveness(), engine->power_level)); // If so, update their pitch and volume. if (impulse_ability > 0.0f && engine) diff --git a/src/screenComponents/jumpControls.cpp b/src/screenComponents/jumpControls.cpp index 99a5888da9..c3a7e4389f 100644 --- a/src/screenComponents/jumpControls.cpp +++ b/src/screenComponents/jumpControls.cpp @@ -28,7 +28,7 @@ GuiJumpControls::GuiJumpControls(GuiContainer* owner, string id) }); button->setPosition(0, 0, sp::Alignment::BottomLeft)->setSize(GuiElement::GuiSizeMax, 50); - (new GuiPowerDamageIndicator(this, id + "_DPI", SYS_JumpDrive, sp::Alignment::TopCenter))->setPosition(0, -50, sp::Alignment::BottomLeft)->setSize(50, GuiElement::GuiSizeMax); + (new GuiPowerDamageIndicator(this, id + "_DPI", ShipSystem::Type::JumpDrive, sp::Alignment::TopCenter))->setPosition(0, -50, sp::Alignment::BottomLeft)->setSize(50, GuiElement::GuiSizeMax); } void GuiJumpControls::onDraw(sp::RenderTarget& target) diff --git a/src/screenComponents/missileTubeControls.cpp b/src/screenComponents/missileTubeControls.cpp index e2b0a32f89..5f50572bae 100644 --- a/src/screenComponents/missileTubeControls.cpp +++ b/src/screenComponents/missileTubeControls.cpp @@ -57,7 +57,7 @@ GuiMissileTubeControls::GuiMissileTubeControls(GuiContainer* owner, string id) } }); row.fire_button->setSize(200, 50); - (new GuiPowerDamageIndicator(row.fire_button, id + "_" + string(n) + "_PDI", SYS_MissileSystem, sp::Alignment::CenterRight))->setSize(GuiElement::GuiSizeMax, GuiElement::GuiSizeMax); + (new GuiPowerDamageIndicator(row.fire_button, id + "_" + string(n) + "_PDI", ShipSystem::Type::MissileSystem, sp::Alignment::CenterRight))->setSize(GuiElement::GuiSizeMax, GuiElement::GuiSizeMax); row.loading_bar = new GuiProgressbar(row.layout, id + "_" + string(n) + "_PROGRESS", 0, 1.0, 0); row.loading_bar->setColor(glm::u8vec4(128, 128, 128, 255))->setSize(200, 50); row.loading_label = new GuiLabel(row.loading_bar, id + "_" + string(n) + "_PROGRESS_LABEL", "Loading", 35); diff --git a/src/screenComponents/powerDamageIndicator.cpp b/src/screenComponents/powerDamageIndicator.cpp index 524890cfe3..12a7a6d640 100644 --- a/src/screenComponents/powerDamageIndicator.cpp +++ b/src/screenComponents/powerDamageIndicator.cpp @@ -3,9 +3,10 @@ #include "powerDamageIndicator.h" #include "spaceObjects/warpJammer.h" #include "components/reactor.h" +#include "components/shipsystem.h" #include "main.h" -GuiPowerDamageIndicator::GuiPowerDamageIndicator(GuiContainer* owner, string name, ESystem system, sp::Alignment icon_align) +GuiPowerDamageIndicator::GuiPowerDamageIndicator(GuiContainer* owner, string name, ShipSystem::Type system, sp::Alignment icon_align) : GuiElement(owner, name), system(system), text_size(30), icon_align(icon_align) { } @@ -15,26 +16,32 @@ void GuiPowerDamageIndicator::onDraw(sp::RenderTarget& renderer) if (!my_spaceship) return; auto reactor = my_spaceship->entity.getComponent(); + auto sys = ShipSystem::get(my_spaceship->entity, system); + if (!sys) + return; glm::u8vec4 color; string display_text; - float power = my_spaceship->systems[system].power_level; - float health = my_spaceship->systems[system].health; - float heat = my_spaceship->systems[system].heat_level; - float hacked_level = my_spaceship->systems[system].hacked_level; - if (system == SYS_FrontShield) + float power = sys->power_level; + float health = sys->health; + float heat = sys->heat_level; + float hacked_level = sys->hacked_level; + if (system == ShipSystem::Type::FrontShield) { - power = std::max(power, my_spaceship->systems[SYS_RearShield].power_level); - health = std::max(health, my_spaceship->systems[SYS_RearShield].health); - heat = std::max(heat, my_spaceship->systems[SYS_RearShield].heat_level); - hacked_level = std::max(hacked_level, my_spaceship->systems[SYS_RearShield].hacked_level); + auto rear = ShipSystem::get(my_spaceship->entity, ShipSystem::Type::RearShield); + if (rear) { + power = std::max(power, rear->power_level); + health = std::max(health, rear->health); + heat = std::max(heat, rear->heat_level); + hacked_level = std::max(hacked_level, rear->hacked_level); + } } if (health <= 0.0f) { color = colorConfig.overlay_damaged; display_text = tr("systems", "DAMAGED"); - }else if ((system == SYS_Warp || system == SYS_JumpDrive) && WarpJammer::isWarpJammed(my_spaceship->getPosition())) + }else if ((system == ShipSystem::Type::Warp || system == ShipSystem::Type::JumpDrive) && WarpJammer::isWarpJammed(my_spaceship->getPosition())) { color = colorConfig.overlay_jammed; display_text = tr("systems", "JAMMED"); @@ -114,7 +121,7 @@ void GuiPowerDamageIndicator::onDraw(sp::RenderTarget& renderer) { drawIcon(renderer, "gui/icons/status_damaged", colorConfig.overlay_damaged); } - if ((system == SYS_Warp || system == SYS_JumpDrive) && WarpJammer::isWarpJammed(my_spaceship->getPosition())) + if ((system == ShipSystem::Type::Warp || system == ShipSystem::Type::JumpDrive) && WarpJammer::isWarpJammed(my_spaceship->getPosition())) { drawIcon(renderer, "gui/icons/status_jammed", colorConfig.overlay_jammed); } diff --git a/src/screenComponents/powerDamageIndicator.h b/src/screenComponents/powerDamageIndicator.h index 189ff522fb..45d8f226c9 100644 --- a/src/screenComponents/powerDamageIndicator.h +++ b/src/screenComponents/powerDamageIndicator.h @@ -7,12 +7,12 @@ class GuiPowerDamageIndicator : public GuiElement { public: - GuiPowerDamageIndicator(GuiContainer* owner, string name, ESystem system, sp::Alignment icon_align); + GuiPowerDamageIndicator(GuiContainer* owner, string name, ShipSystem::Type system, sp::Alignment icon_align); virtual void onDraw(sp::RenderTarget& target) override; private: - ESystem system; + ShipSystem::Type system; float text_size; sp::Alignment icon_align; diff --git a/src/screenComponents/shieldsEnableButton.cpp b/src/screenComponents/shieldsEnableButton.cpp index 0db1c149ce..ddf6f55a30 100644 --- a/src/screenComponents/shieldsEnableButton.cpp +++ b/src/screenComponents/shieldsEnableButton.cpp @@ -23,7 +23,7 @@ GuiShieldsEnableButton::GuiShieldsEnableButton(GuiContainer* owner, string id) bar->setSize(GuiElement::GuiSizeMax, GuiElement::GuiSizeMax); (new GuiLabel(bar, id + "_CALIBRATING_LABEL", tr("shields","Calibrating"), 30))->setSize(GuiElement::GuiSizeMax, GuiElement::GuiSizeMax); - (new GuiPowerDamageIndicator(this, id + "_PDI", SYS_FrontShield, sp::Alignment::CenterLeft))->setSize(GuiElement::GuiSizeMax, GuiElement::GuiSizeMax); + (new GuiPowerDamageIndicator(this, id + "_PDI", ShipSystem::Type::FrontShield, sp::Alignment::CenterLeft))->setSize(GuiElement::GuiSizeMax, GuiElement::GuiSizeMax); } void GuiShieldsEnableButton::onDraw(sp::RenderTarget& target) diff --git a/src/screenComponents/shipInternalView.cpp b/src/screenComponents/shipInternalView.cpp index 69c905add8..0b560d3dfb 100644 --- a/src/screenComponents/shipInternalView.cpp +++ b/src/screenComponents/shipInternalView.cpp @@ -161,7 +161,7 @@ void GuiShipRoomContainer::onMouseUp(glm::vec2 position, sp::io::Pointer::ID id) } GuiShipRoom::GuiShipRoom(GuiContainer* owner, string id, float room_size, glm::ivec2 dimensions, func_t func) -: GuiElement(owner, id), system(SYS_None), room_size(room_size), func(func) +: GuiElement(owner, id), system(ShipSystem::Type::None), room_size(room_size), func(func) { setSize(glm::vec2(dimensions) * room_size); } @@ -169,40 +169,43 @@ GuiShipRoom::GuiShipRoom(GuiContainer* owner, string id, float room_size, glm::i void GuiShipRoom::onDraw(sp::RenderTarget& renderer) { float f = 1.0; - if (ship && ship->hasSystem(system)) - f = std::max(0.0f, ship->systems[system].health); + ShipSystem* sys = nullptr; + if (ship) + sys = ShipSystem::get(ship->entity, system); + if (sys) + f = std::max(0.0f, sys->health); renderer.drawStretchedHV(rect, rect.size.x * 0.25f, "room_background", glm::u8vec4(255, 255 * f, 255 * f, 255)); - if (system != SYS_None && ship && ship->hasSystem(system)) + if (system != ShipSystem::Type::None && ship && ship->hasSystem(system)) { std::string_view icon; switch(system) { - case SYS_Reactor: + case ShipSystem::Type::Reactor: icon = "gui/icons/system_reactor.png"; break; - case SYS_BeamWeapons: + case ShipSystem::Type::BeamWeapons: icon = "gui/icons/system_beam"; break; - case SYS_MissileSystem: + case ShipSystem::Type::MissileSystem: icon = "gui/icons/system_missile"; break; - case SYS_Maneuver: + case ShipSystem::Type::Maneuver: icon = "gui/icons/system_maneuver"; break; - case SYS_Impulse: + case ShipSystem::Type::Impulse: icon = "gui/icons/system_impulse"; break; - case SYS_Warp: + case ShipSystem::Type::Warp: icon = "gui/icons/system_warpdrive"; break; - case SYS_JumpDrive: + case ShipSystem::Type::JumpDrive: icon = "gui/icons/system_jumpdrive"; break; - case SYS_FrontShield: + case ShipSystem::Type::FrontShield: icon = "gui/icons/shields-fore"; break; - case SYS_RearShield: + case ShipSystem::Type::RearShield: icon = "gui/icons/shields-aft"; break; default: diff --git a/src/screenComponents/shipInternalView.h b/src/screenComponents/shipInternalView.h index 0bf9ad0597..60af57e317 100644 --- a/src/screenComponents/shipInternalView.h +++ b/src/screenComponents/shipInternalView.h @@ -45,7 +45,7 @@ class GuiShipRoom : public GuiElement typedef std::function func_t; private: P ship; - ESystem system; + ShipSystem::Type system; float room_size; func_t func; public: @@ -53,7 +53,7 @@ class GuiShipRoom : public GuiElement virtual void onDraw(sp::RenderTarget& target) override; - GuiShipRoom* setSystem(P ship, ESystem system) { this->ship = ship; this->system = system; return this; } + GuiShipRoom* setSystem(P ship, ShipSystem::Type system) { this->ship = ship; this->system = system; return this; } virtual bool onMouseDown(sp::io::Pointer::Button button, glm::vec2 position, sp::io::Pointer::ID id) override; virtual void onMouseUp(glm::vec2 position, sp::io::Pointer::ID id) override; diff --git a/src/screenComponents/warpControls.cpp b/src/screenComponents/warpControls.cpp index 5df629f578..5ad8c4e6a4 100644 --- a/src/screenComponents/warpControls.cpp +++ b/src/screenComponents/warpControls.cpp @@ -45,7 +45,7 @@ GuiWarpControls::GuiWarpControls(GuiContainer* owner, string id) label->setTextSize(30)->setPosition(50, 0, sp::Alignment::TopLeft)->setSize(40, GuiElement::GuiSizeMax); // Prep the alert overlay. - (new GuiPowerDamageIndicator(this, id + "_DPI", SYS_Warp, sp::Alignment::TopCenter))->setSize(50, GuiElement::GuiSizeMax); + (new GuiPowerDamageIndicator(this, id + "_DPI", ShipSystem::Type::Warp, sp::Alignment::TopCenter))->setSize(50, GuiElement::GuiSizeMax); } void GuiWarpControls::onDraw(sp::RenderTarget& target) diff --git a/src/screens/crew1/singlePilotScreen.cpp b/src/screens/crew1/singlePilotScreen.cpp index 9938e5d22f..7780c24dfb 100644 --- a/src/screens/crew1/singlePilotScreen.cpp +++ b/src/screens/crew1/singlePilotScreen.cpp @@ -130,12 +130,12 @@ void SinglePilotScreen::onDraw(sp::RenderTarget& renderer) jump_controls->setVisible(my_spaceship->entity.hasComponent()); string shields_value = string(my_spaceship->getShieldPercentage(0)) + "%"; - if (my_spaceship->hasSystem(SYS_RearShield)) + if (my_spaceship->hasSystem(ShipSystem::Type::RearShield)) { shields_value += " " + string(my_spaceship->getShieldPercentage(1)) + "%"; } shields_display->setValue(shields_value); - if (my_spaceship->hasSystem(SYS_FrontShield) || my_spaceship->hasSystem(SYS_RearShield)) + if (my_spaceship->hasSystem(ShipSystem::Type::FrontShield) || my_spaceship->hasSystem(ShipSystem::Type::RearShield)) { shields_display->show(); } else { diff --git a/src/screens/crew4/tacticalScreen.cpp b/src/screens/crew4/tacticalScreen.cpp index 7af0f24185..195b30e8c1 100644 --- a/src/screens/crew4/tacticalScreen.cpp +++ b/src/screens/crew4/tacticalScreen.cpp @@ -91,7 +91,7 @@ TacticalScreen::TacticalScreen(GuiContainer* owner) beam_info_box->setPosition(0, -20, sp::Alignment::BottomCenter)->setSize(500, 50); (new GuiLabel(beam_info_box, "BEAM_INFO_LABEL", tr("Beams"), 30))->addBackground()->setPosition(0, 0, sp::Alignment::BottomLeft)->setSize(80, 50); (new GuiBeamFrequencySelector(beam_info_box, "BEAM_FREQUENCY_SELECTOR"))->setPosition(80, 0, sp::Alignment::BottomLeft)->setSize(132, 50); - (new GuiPowerDamageIndicator(beam_info_box, "", SYS_BeamWeapons, sp::Alignment::CenterLeft))->setPosition(0, 0, sp::Alignment::BottomLeft)->setSize(212, 50); + (new GuiPowerDamageIndicator(beam_info_box, "", ShipSystem::Type::BeamWeapons, sp::Alignment::CenterLeft))->setPosition(0, 0, sp::Alignment::BottomLeft)->setSize(212, 50); (new GuiBeamTargetSelector(beam_info_box, "BEAM_TARGET_SELECTOR"))->setPosition(0, 0, sp::Alignment::BottomRight)->setSize(288, 50); } @@ -131,12 +131,12 @@ void TacticalScreen::onDraw(sp::RenderTarget& renderer) jump_controls->setVisible(my_spaceship->entity.hasComponent()); string shields_value = string(my_spaceship->getShieldPercentage(0)) + "%"; - if (my_spaceship->hasSystem(SYS_RearShield)) + if (my_spaceship->hasSystem(ShipSystem::Type::RearShield)) { shields_value += " " + string(my_spaceship->getShieldPercentage(1)) + "%"; } shields_display->setValue(shields_value); - if (my_spaceship->hasSystem(SYS_FrontShield) || my_spaceship->hasSystem(SYS_RearShield)) + if (my_spaceship->hasSystem(ShipSystem::Type::FrontShield) || my_spaceship->hasSystem(ShipSystem::Type::RearShield)) { shields_display->show(); } else { diff --git a/src/screens/crew6/engineeringScreen.cpp b/src/screens/crew6/engineeringScreen.cpp index 44fca99e80..5868df2240 100644 --- a/src/screens/crew6/engineeringScreen.cpp +++ b/src/screens/crew6/engineeringScreen.cpp @@ -3,10 +3,13 @@ #include "engineeringScreen.h" #include "components/reactor.h" +#include "components/coolant.h" #include "components/beamweapon.h" #include "components/hull.h" #include "components/jumpdrive.h" #include "components/shields.h" +#include "components/impulse.h" +#include "components/maneuveringthrusters.h" #include "screenComponents/shipInternalView.h" #include "screenComponents/selfDestructButton.h" @@ -23,7 +26,7 @@ #include "gui/gui2_panel.h" EngineeringScreen::EngineeringScreen(GuiContainer* owner, ECrewPosition crew_position) -: GuiOverlay(owner, "ENGINEERING_SCREEN", colorConfig.background), selected_system(SYS_None) +: GuiOverlay(owner, "ENGINEERING_SCREEN", colorConfig.background), selected_system(ShipSystem::Type::None) { // Render the background decorations. background_crosses = new GuiOverlay(this, "BACKGROUND_CROSSES", glm::u8vec4{255,255,255,255}); @@ -56,16 +59,16 @@ EngineeringScreen::EngineeringScreen(GuiContainer* owner, ECrewPosition crew_pos system_row_layouts->setPosition(0, 0, sp::Alignment::BottomLeft)->setAttribute("layout", "verticalbottom"); system_row_layouts->setSize(GuiElement::GuiSizeMax, GuiElement::GuiSizeMax); float column_width = gameGlobalInfo->use_system_damage ? 100 : 150; - for(int n=0; nsetAttribute("layout", "horizontal"); info.row->setSize(GuiElement::GuiSizeMax, 50); - info.button = new GuiToggleButton(info.row, id + "_SELECT", getLocaleSystemName(ESystem(n)), [this, n](bool value){ - selectSystem(ESystem(n)); + info.button = new GuiToggleButton(info.row, id + "_SELECT", getLocaleSystemName(ShipSystem::Type(n)), [this, n](bool value){ + selectSystem(ShipSystem::Type(n)); }); info.button->setSize(300, GuiElement::GuiSizeMax); info.damage_bar = new GuiProgressbar(info.row, id + "_DAMAGE", 0.0f, 1.0f, 0.0f); @@ -82,12 +85,12 @@ EngineeringScreen::EngineeringScreen(GuiContainer* owner, ECrewPosition crew_pos info.heat_icon->setColor(colorConfig.overlay_overheating)->setPosition(0, 0, sp::Alignment::Center)->setSize(GuiElement::GuiSizeMatchHeight, GuiElement::GuiSizeMax); info.power_bar = new GuiProgressSlider(info.row, id + "_POWER", 0.0f, 3.0f, 0.0f, [this,n](float value){ if (my_spaceship) - my_spaceship->commandSetSystemPowerRequest(ESystem(n), value); + my_spaceship->commandSetSystemPowerRequest(ShipSystem::Type(n), value); }); info.power_bar->setColor(glm::u8vec4(192, 192, 32, 128))->setSize(column_width, GuiElement::GuiSizeMax); info.coolant_bar = new GuiProgressSlider(info.row, id + "_COOLANT", 0.0f, 10.0f, 0.0f, [this,n](float value){ if (my_spaceship) - my_spaceship->commandSetSystemCoolantRequest(ESystem(n), value); + my_spaceship->commandSetSystemCoolantRequest(ShipSystem::Type(n), value); }); info.coolant_bar->setColor(glm::u8vec4(32, 128, 128, 128))->setSize(column_width, GuiElement::GuiSizeMax); if (!gameGlobalInfo->use_system_damage) @@ -111,35 +114,45 @@ EngineeringScreen::EngineeringScreen(GuiContainer* owner, ECrewPosition crew_pos coolant_remaining_bar = new GuiProgressSlider(icon_layout, "", 0, 10.0, 10.0, [](float requested_unused_coolant) { float total_requested = 0.0f; - float new_max_total = my_spaceship->max_coolant - requested_unused_coolant; - for(int n=0; nsystems[n].coolant_request; + auto coolant = my_spaceship->entity.getComponent(); + if (!coolant) return; + float new_max_total = coolant->max - requested_unused_coolant; + for(int n=0; nentity, ShipSystem::Type(n)); + if (sys) + total_requested += sys->coolant_request; + } if (new_max_total < total_requested) { // Drain systems - for(int n=0; ncommandSetSystemCoolantRequest((ESystem)n, my_spaceship->systems[n].coolant_request * new_max_total / total_requested); + for(int n=0; nentity, ShipSystem::Type(n)); + if (sys) + my_spaceship->commandSetSystemCoolantRequest(ShipSystem::Type(n), sys->coolant_request * new_max_total / total_requested); + } } else { // Put coolant into systems int system_count = 0; - for(int n=0; nhasSystem((ESystem)n)) + for(int n=0; nhasSystem(ShipSystem::Type(n))) system_count += 1; float add = (new_max_total - total_requested) / float(system_count); - for(int n=0; nhasSystem((ESystem)n)) - my_spaceship->commandSetSystemCoolantRequest((ESystem)n, std::min(my_spaceship->systems[n].coolant_request + add, 10.0f)); + for(int n=0; nentity, ShipSystem::Type(n)); + if (sys) + my_spaceship->commandSetSystemCoolantRequest(ShipSystem::Type(n), std::min(sys->coolant_request + add, 10.0f)); + } } }); coolant_remaining_bar->setColor(glm::u8vec4(32, 128, 128, 128))->setDrawBackground(false)->setSize(column_width, GuiElement::GuiSizeMax); (new GuiImage(coolant_remaining_bar, "COOLANT_ICON", "gui/icons/coolant"))->setSize(GuiElement::GuiSizeMax, GuiElement::GuiSizeMax); - system_rows[SYS_Reactor].button->setIcon("gui/icons/system_reactor"); - system_rows[SYS_BeamWeapons].button->setIcon("gui/icons/system_beam"); - system_rows[SYS_MissileSystem].button->setIcon("gui/icons/system_missile"); - system_rows[SYS_Maneuver].button->setIcon("gui/icons/system_maneuver"); - system_rows[SYS_Impulse].button->setIcon("gui/icons/system_impulse"); - system_rows[SYS_Warp].button->setIcon("gui/icons/system_warpdrive"); - system_rows[SYS_JumpDrive].button->setIcon("gui/icons/system_jumpdrive"); - system_rows[SYS_FrontShield].button->setIcon("gui/icons/shields-fore"); - system_rows[SYS_RearShield].button->setIcon("gui/icons/shields-aft"); + system_rows[int(ShipSystem::Type::Reactor)].button->setIcon("gui/icons/system_reactor"); + system_rows[int(ShipSystem::Type::BeamWeapons)].button->setIcon("gui/icons/system_beam"); + system_rows[int(ShipSystem::Type::MissileSystem)].button->setIcon("gui/icons/system_missile"); + system_rows[int(ShipSystem::Type::Maneuver)].button->setIcon("gui/icons/system_maneuver"); + system_rows[int(ShipSystem::Type::Impulse)].button->setIcon("gui/icons/system_impulse"); + system_rows[int(ShipSystem::Type::Warp)].button->setIcon("gui/icons/system_warpdrive"); + system_rows[int(ShipSystem::Type::JumpDrive)].button->setIcon("gui/icons/system_jumpdrive"); + system_rows[int(ShipSystem::Type::FrontShield)].button->setIcon("gui/icons/shields-fore"); + system_rows[int(ShipSystem::Type::RearShield)].button->setIcon("gui/icons/shields-aft"); system_effects_container = new GuiElement(system_config_container, ""); system_effects_container->setPosition(0, -400, sp::Alignment::BottomRight)->setSize(270, 400)->setAttribute("layout", "verticalbottom"); @@ -151,7 +164,7 @@ EngineeringScreen::EngineeringScreen(GuiContainer* owner, ECrewPosition crew_pos coolant_label->setVertical()->setAlignment(sp::Alignment::Center)->setPosition(110, 20, sp::Alignment::TopLeft)->setSize(30, 360); power_slider = new GuiSlider(box, "POWER_SLIDER", 3.0, 0.0, 1.0, [this](float value) { - if (my_spaceship && selected_system != SYS_None) + if (my_spaceship && selected_system != ShipSystem::Type::None) my_spaceship->commandSetSystemPowerRequest(selected_system, value); }); power_slider->setPosition(50, 20, sp::Alignment::TopLeft)->setSize(60, 360); @@ -159,7 +172,7 @@ EngineeringScreen::EngineeringScreen(GuiContainer* owner, ECrewPosition crew_pos power_slider->addSnapValue(snap_point, snap_point == 1.0f ? 0.1f : 0.01f); power_slider->disable(); coolant_slider = new GuiSlider(box, "COOLANT_SLIDER", 10.0, 0.0, 0.0, [this](float value) { - if (my_spaceship && selected_system != SYS_None) + if (my_spaceship && selected_system != ShipSystem::Type::None) my_spaceship->commandSetSystemCoolantRequest(selected_system, value); }); coolant_slider->setPosition(140, 20, sp::Alignment::TopLeft)->setSize(60, 360); @@ -215,43 +228,43 @@ void EngineeringScreen::onDraw(sp::RenderTarget& renderer) hull_display->setColor(glm::u8vec4{255,255,255,255}); } front_shield_display->setValue(string(my_spaceship->getShieldPercentage(0)) + "%"); - if (my_spaceship->hasSystem(SYS_FrontShield)) + if (my_spaceship->hasSystem(ShipSystem::Type::FrontShield)) { front_shield_display->show(); } else { front_shield_display->hide(); } rear_shield_display->setValue(string(my_spaceship->getShieldPercentage(1)) + "%"); - if (my_spaceship->hasSystem(SYS_RearShield)) + if (my_spaceship->hasSystem(ShipSystem::Type::RearShield)) { rear_shield_display->show(); } else { rear_shield_display->hide(); } - coolant_display->setValue(toNearbyIntString(my_spaceship->max_coolant * 10) + "%"); - float total_coolant_used = 0.0f; - for(int n=0; nsystems[n]; - info.row->setVisible(my_spaceship->hasSystem(ESystem(n))); + auto system = ShipSystem::get(my_spaceship->entity, ShipSystem::Type(n)); + info.row->setVisible(system); + if (!system) + continue; - float health = system.health; + float health = system->health; if (health < 0.0f) info.damage_bar->setValue(-health)->setColor(glm::u8vec4(128, 32, 32, 192)); else info.damage_bar->setValue(health)->setColor(glm::u8vec4(64, 128 * health, 64 * health, 192)); info.damage_label->setText(toNearbyIntString(health * 100) + "%"); - float health_max = system.health_max; + float health_max = system->health_max; if (health_max < 1.0f) info.damage_icon->show(); else info.damage_icon->hide(); - float heat = system.heat_level; + float heat = system->heat_level; info.heat_bar->setValue(heat)->setColor(glm::u8vec4(128, 32 + 96 * (1.0f - heat), 32, 192)); - float heating_diff = system.getHeatingDelta(); + float heating_diff = system->getHeatingDelta(); if (heating_diff > 0) info.heat_arrow->setAngle(90); else @@ -263,116 +276,139 @@ void EngineeringScreen::onDraw(sp::RenderTarget& renderer) else info.heat_icon->hide(); - info.power_bar->setValue(system.power_level); - info.coolant_bar->setValue(system.coolant_level); - if (system.coolant_request > 0.0f) { - float f = system.coolant_request / 10.f; + info.power_bar->setValue(system->power_level); + info.coolant_bar->setValue(system->coolant_level); + if (system->coolant_request > 0.0f) { + float f = system->coolant_request / 10.f; info.coolant_max_indicator->setPosition(-20 + info.coolant_bar->getSize().x * f, 5); info.coolant_max_indicator->setColor({255,255,255,255}); } else { info.coolant_max_indicator->setColor({255,255,255,0}); } - total_coolant_used += system.coolant_level; + total_coolant_used += system->coolant_level; + } + + auto coolant = my_spaceship->entity.getComponent(); + coolant_display->setVisible(coolant); + coolant_remaining_bar->setVisible(coolant); + if (coolant) { + coolant_display->setValue(toNearbyIntString(coolant->max * 100.0f / coolant->max_coolant_per_system) + "%"); + coolant_remaining_bar->setRange(0, coolant->max); + coolant_remaining_bar->setValue(coolant->max - total_coolant_used); } - coolant_remaining_bar->setRange(0, my_spaceship->max_coolant); - coolant_remaining_bar->setValue(my_spaceship->max_coolant - total_coolant_used); - if (selected_system != SYS_None) + if (selected_system != ShipSystem::Type::None) { - auto& system = my_spaceship->systems[selected_system]; - power_label->setText(tr("slider", "Power: {current_level}% / {requested}%").format({{"current_level", toNearbyIntString(system.power_level * 100)}, {"requested", toNearbyIntString(system.power_request * 100)}})); - power_slider->setValue(system.power_request); - coolant_label->setText(tr("slider", "Coolant: {current_level}% / {requested}%").format({{"current_level", toNearbyIntString(system.coolant_level / PlayerSpaceship::max_coolant_per_system * 100)}, {"requested", toNearbyIntString(std::min(system.coolant_request, my_spaceship->max_coolant) / PlayerSpaceship::max_coolant_per_system * 100)}})); - coolant_slider->setEnable(!my_spaceship->auto_coolant_enabled); - coolant_slider->setValue(std::min(system.coolant_request, my_spaceship->max_coolant)); - - system_effects_index = 0; - float effectiveness = my_spaceship->getSystemEffectiveness(selected_system); - float health_max = my_spaceship->getSystemHealthMax(selected_system); - if (health_max < 1.0f) - addSystemEffect("Maximal health", toNearbyIntString(health_max * 100) + "%"); - switch(selected_system) - { - case SYS_Reactor: - if (effectiveness > 1.0f) - effectiveness = (1.0f + effectiveness) / 2.0f; - addSystemEffect(tr("Energy production"), tr("{energy}/min").format({{"energy", string(effectiveness * - my_spaceship->getSystemPowerUserFactor(selected_system) * 60.0f, 1)}})); - break; - case SYS_BeamWeapons: - addSystemEffect(tr("Firing rate"), toNearbyIntString(effectiveness * 100) + "%"); - // If the ship has a turret, also note that the rotation rate - // is affected. - if (auto beamweapons = my_spaceship->entity.getComponent()) { - for(int n = 0; n < max_beam_weapons; n++) { - if (beamweapons->mounts[n].turret_arc > 0) { - addSystemEffect("Turret rotation rate", toNearbyIntString(effectiveness * 100) + "%"); - break; + auto system = ShipSystem::get(my_spaceship->entity, selected_system); + if (system) { + power_label->setText(tr("slider", "Power: {current_level}% / {requested}%").format({{"current_level", toNearbyIntString(system->power_level * 100)}, {"requested", toNearbyIntString(system->power_request * 100)}})); + power_slider->setValue(system->power_request); + coolant_label->setVisible(coolant); + coolant_slider->setVisible(coolant); + if (coolant) { + coolant_label->setText(tr("slider", "Coolant: {current_level}% / {requested}%").format({{"current_level", toNearbyIntString(system->coolant_level / coolant->max_coolant_per_system * 100.0f)}, {"requested", toNearbyIntString(std::min(system->coolant_request, coolant->max) / coolant->max_coolant_per_system * 100)}})); + coolant_slider->setEnable(!coolant->auto_levels); + coolant_slider->setValue(std::min(system->coolant_request, coolant->max)); + } + + system_effects_index = 0; + float effectiveness = system->getSystemEffectiveness(); + float health_max = system->health_max; + if (health_max < 1.0f) + addSystemEffect("Maximal health", toNearbyIntString(health_max * 100) + "%"); + switch(selected_system) + { + case ShipSystem::Type::Reactor: + if (effectiveness > 1.0f) + effectiveness = (1.0f + effectiveness) / 2.0f; + addSystemEffect(tr("Energy production"), tr("{energy}/min").format({{"energy", string(effectiveness * - my_spaceship->getSystemPowerUserFactor(selected_system) * 60.0f, 1)}})); + break; + case ShipSystem::Type::BeamWeapons: + addSystemEffect(tr("Firing rate"), toNearbyIntString(effectiveness * 100) + "%"); + // If the ship has a turret, also note that the rotation rate + // is affected. + if (auto beamweapons = my_spaceship->entity.getComponent()) { + for(int n = 0; n < max_beam_weapons; n++) { + if (beamweapons->mounts[n].turret_arc > 0) { + addSystemEffect("Turret rotation rate", toNearbyIntString(effectiveness * 100) + "%"); + break; + } } } - } - break; - case SYS_MissileSystem: - addSystemEffect(tr("missile","Reload rate"), toNearbyIntString(effectiveness * 100) + "%"); - break; - case SYS_Maneuver: - addSystemEffect(tr("Turning speed"), toNearbyIntString(effectiveness * 100) + "%"); - if (my_spaceship->combat_maneuver_boost_speed > 0.0f || my_spaceship->combat_maneuver_strafe_speed) - addSystemEffect(tr("Combat recharge rate"), toNearbyIntString(((my_spaceship->getSystemEffectiveness(SYS_Maneuver) + my_spaceship->getSystemEffectiveness(SYS_Impulse)) / 2.0f) * 100) + "%"); - break; - case SYS_Impulse: - addSystemEffect(tr("Impulse speed"), toNearbyIntString(effectiveness * 100) + "%"); - if (my_spaceship->combat_maneuver_boost_speed > 0.0f || my_spaceship->combat_maneuver_strafe_speed) - addSystemEffect(tr("Combat recharge rate"), toNearbyIntString(((my_spaceship->getSystemEffectiveness(SYS_Maneuver) + my_spaceship->getSystemEffectiveness(SYS_Impulse)) / 2.0f) * 100) + "%"); - break; - case SYS_Warp: - addSystemEffect(tr("Warp drive speed"), toNearbyIntString(effectiveness * 100) + "%"); - break; - case SYS_JumpDrive:{ - auto jump = my_spaceship->entity.getComponent(); - if (jump) { - addSystemEffect(tr("Jump drive recharge rate"), toNearbyIntString(jump->get_recharge_rate() * 100) + "%"); - addSystemEffect(tr("Jump drive jump speed"), toNearbyIntString(effectiveness * 100) + "%"); - } - }break; - case SYS_FrontShield:{ - auto shields = my_spaceship->entity.getComponent(); - if (shields) { - if (gameGlobalInfo->use_beam_shield_frequencies) - addSystemEffect(tr("shields","Calibration speed"), toNearbyIntString((shields->front_system.getSystemEffectiveness() + shields->rear_system.getSystemEffectiveness()) / 2.0f * 100) + "%"); - addSystemEffect(tr("shields","Charge rate"), toNearbyIntString(effectiveness * 100) + "%"); - { - DamageInfo di; - di.type = DT_Kinetic; - float damage_negate = 1.0f - my_spaceship->getShieldDamageFactor(di, 0); - if (damage_negate < 0.0f) - addSystemEffect(tr("Extra damage"), toNearbyIntString(-damage_negate * 100) + "%"); - else - addSystemEffect(tr("Damage negate"), toNearbyIntString(damage_negate * 100) + "%"); + break; + case ShipSystem::Type::MissileSystem: + addSystemEffect(tr("missile","Reload rate"), toNearbyIntString(effectiveness * 100) + "%"); + break; + case ShipSystem::Type::Maneuver:{ + addSystemEffect(tr("Turning speed"), toNearbyIntString(effectiveness * 100) + "%"); + auto combat = my_spaceship->entity.getComponent(); + if (combat) { + auto impulse = my_spaceship->entity.getComponent(); + auto thrusters = my_spaceship->entity.getComponent(); + if (impulse && thrusters) + addSystemEffect(tr("Combat recharge rate"), toNearbyIntString(((impulse->getSystemEffectiveness() + thrusters->getSystemEffectiveness()) / 2.0f) * 100) + "%"); } - } - }break; - case SYS_RearShield:{ - auto shields = my_spaceship->entity.getComponent(); - if (shields) { - if (gameGlobalInfo->use_beam_shield_frequencies) - addSystemEffect(tr("shields","Calibration speed"), toNearbyIntString((shields->front_system.getSystemEffectiveness() + shields->rear_system.getSystemEffectiveness()) / 2.0f * 100) + "%"); - addSystemEffect(tr("shields","Charge rate"), toNearbyIntString(effectiveness * 100) + "%"); - { - DamageInfo di; - di.type = DT_Kinetic; - float damage_negate = 1.0f - my_spaceship->getShieldDamageFactor(di, shields->count - 1); - if (damage_negate < 0.0f) - addSystemEffect(tr("Extra damage"), toNearbyIntString(-damage_negate * 100) + "%"); - else - addSystemEffect(tr("Damage negate"), toNearbyIntString(damage_negate * 100) + "%"); + }break; + case ShipSystem::Type::Impulse:{ + addSystemEffect(tr("Impulse speed"), toNearbyIntString(effectiveness * 100) + "%"); + auto combat = my_spaceship->entity.getComponent(); + if (combat) { + auto impulse = my_spaceship->entity.getComponent(); + auto thrusters = my_spaceship->entity.getComponent(); + if (impulse && thrusters) + addSystemEffect(tr("Combat recharge rate"), toNearbyIntString(((impulse->getSystemEffectiveness() + thrusters->getSystemEffectiveness()) / 2.0f) * 100) + "%"); + } + }break; + case ShipSystem::Type::Warp: + addSystemEffect(tr("Warp drive speed"), toNearbyIntString(effectiveness * 100) + "%"); + break; + case ShipSystem::Type::JumpDrive:{ + auto jump = my_spaceship->entity.getComponent(); + if (jump) { + addSystemEffect(tr("Jump drive recharge rate"), toNearbyIntString(jump->get_recharge_rate() * 100) + "%"); + addSystemEffect(tr("Jump drive jump speed"), toNearbyIntString(effectiveness * 100) + "%"); } + }break; + case ShipSystem::Type::FrontShield:{ + auto shields = my_spaceship->entity.getComponent(); + if (shields) { + if (gameGlobalInfo->use_beam_shield_frequencies) + addSystemEffect(tr("shields","Calibration speed"), toNearbyIntString((shields->front_system.getSystemEffectiveness() + shields->rear_system.getSystemEffectiveness()) / 2.0f * 100) + "%"); + addSystemEffect(tr("shields","Charge rate"), toNearbyIntString(effectiveness * 100) + "%"); + { + DamageInfo di; + di.type = DT_Kinetic; + float damage_negate = 1.0f - my_spaceship->getShieldDamageFactor(di, 0); + if (damage_negate < 0.0f) + addSystemEffect(tr("Extra damage"), toNearbyIntString(-damage_negate * 100) + "%"); + else + addSystemEffect(tr("Damage negate"), toNearbyIntString(damage_negate * 100) + "%"); + } + } + }break; + case ShipSystem::Type::RearShield:{ + auto shields = my_spaceship->entity.getComponent(); + if (shields) { + if (gameGlobalInfo->use_beam_shield_frequencies) + addSystemEffect(tr("shields","Calibration speed"), toNearbyIntString((shields->front_system.getSystemEffectiveness() + shields->rear_system.getSystemEffectiveness()) / 2.0f * 100) + "%"); + addSystemEffect(tr("shields","Charge rate"), toNearbyIntString(effectiveness * 100) + "%"); + { + DamageInfo di; + di.type = DT_Kinetic; + float damage_negate = 1.0f - my_spaceship->getShieldDamageFactor(di, shields->count - 1); + if (damage_negate < 0.0f) + addSystemEffect(tr("Extra damage"), toNearbyIntString(-damage_negate * 100) + "%"); + else + addSystemEffect(tr("Damage negate"), toNearbyIntString(damage_negate * 100) + "%"); + } + } + }break; + default: + break; } - }break; - default: - break; + for(unsigned int idx=system_effects_index; idxhide(); } - for(unsigned int idx=system_effects_index; idxhide(); } } GuiOverlay::onDraw(renderer); @@ -382,17 +418,17 @@ void EngineeringScreen::onUpdate() { if (my_spaceship && isVisible()) { - if (keys.engineering_select_reactor.getDown()) selectSystem(SYS_Reactor); - if (keys.engineering_select_beam_weapons.getDown()) selectSystem(SYS_BeamWeapons); - if (keys.engineering_select_missile_system.getDown()) selectSystem(SYS_MissileSystem); - if (keys.engineering_select_maneuvering_system.getDown()) selectSystem(SYS_Maneuver); - if (keys.engineering_select_impulse_system.getDown()) selectSystem(SYS_Impulse); - if (keys.engineering_select_warp_system.getDown()) selectSystem(SYS_Warp); - if (keys.engineering_select_jump_drive_system.getDown()) selectSystem(SYS_JumpDrive); - if (keys.engineering_select_front_shield_system.getDown()) selectSystem(SYS_FrontShield); - if (keys.engineering_select_rear_shield_system.getDown()) selectSystem(SYS_RearShield); - - if (selected_system != SYS_None) + if (keys.engineering_select_reactor.getDown()) selectSystem(ShipSystem::Type::Reactor); + if (keys.engineering_select_beam_weapons.getDown()) selectSystem(ShipSystem::Type::BeamWeapons); + if (keys.engineering_select_missile_system.getDown()) selectSystem(ShipSystem::Type::MissileSystem); + if (keys.engineering_select_maneuvering_system.getDown()) selectSystem(ShipSystem::Type::Maneuver); + if (keys.engineering_select_impulse_system.getDown()) selectSystem(ShipSystem::Type::Impulse); + if (keys.engineering_select_warp_system.getDown()) selectSystem(ShipSystem::Type::Warp); + if (keys.engineering_select_jump_drive_system.getDown()) selectSystem(ShipSystem::Type::JumpDrive); + if (keys.engineering_select_front_shield_system.getDown()) selectSystem(ShipSystem::Type::FrontShield); + if (keys.engineering_select_rear_shield_system.getDown()) selectSystem(ShipSystem::Type::RearShield); + + if (selected_system != ShipSystem::Type::None) { // Note the code duplication with extra/powerManagement if (keys.engineering_set_power_000.getDown()) @@ -439,34 +475,43 @@ void EngineeringScreen::onUpdate() auto power_adjust = (keys.engineering_increase_power.getValue() - keys.engineering_decrease_power.getValue()) * 0.1f; if (power_adjust != 0.0f) { - power_slider->setValue(my_spaceship->systems[selected_system].power_request + power_adjust); - my_spaceship->commandSetSystemPowerRequest(selected_system, power_slider->getValue()); + auto sys = ShipSystem::get(my_spaceship->entity, selected_system); + if (sys) { + power_slider->setValue(sys->power_request + power_adjust); + my_spaceship->commandSetSystemPowerRequest(selected_system, power_slider->getValue()); + } } auto coolant_adjust = (keys.engineering_increase_coolant.getValue() - keys.engineering_decrease_coolant.getValue()) * 0.5f; if (coolant_adjust != 0.0f) { - coolant_slider->setValue(my_spaceship->systems[selected_system].coolant_request + coolant_adjust); - my_spaceship->commandSetSystemCoolantRequest(selected_system, coolant_slider->getValue()); + auto sys = ShipSystem::get(my_spaceship->entity, selected_system); + if (sys) { + coolant_slider->setValue(sys->coolant_request + coolant_adjust); + my_spaceship->commandSetSystemCoolantRequest(selected_system, coolant_slider->getValue()); + } } } } } -void EngineeringScreen::selectSystem(ESystem system) +void EngineeringScreen::selectSystem(ShipSystem::Type system) { if (my_spaceship && !my_spaceship->hasSystem(system)) return; - for(int idx=0; idxsetValue(idx == system); + system_rows[idx].button->setValue(ShipSystem::Type(idx) == system); } selected_system = system; power_slider->enable(); if (my_spaceship) { - power_slider->setValue(my_spaceship->systems[system].power_request); - coolant_slider->setValue(my_spaceship->systems[system].coolant_request); + auto sys = ShipSystem::get(my_spaceship->entity, system); + if (sys) { + power_slider->setValue(sys->power_request); + coolant_slider->setValue(sys->coolant_request); + } } } diff --git a/src/screens/crew6/engineeringScreen.h b/src/screens/crew6/engineeringScreen.h index 28fb108132..52473d9758 100644 --- a/src/screens/crew6/engineeringScreen.h +++ b/src/screens/crew6/engineeringScreen.h @@ -51,14 +51,14 @@ class EngineeringScreen : public GuiOverlay GuiElement* system_effects_container; std::vector system_effects; unsigned int system_effects_index; - ESystem selected_system; + ShipSystem::Type selected_system; float previous_energy_measurement; float previous_energy_level; float average_energy_delta; void addSystemEffect(string key, string value); - void selectSystem(ESystem system); + void selectSystem(ShipSystem::Type system); string toNearbyIntString(float value); public: diff --git a/src/screens/crew6/scienceScreen.cpp b/src/screens/crew6/scienceScreen.cpp index e0ce910b77..1f0c79b7fa 100644 --- a/src/screens/crew6/scienceScreen.cpp +++ b/src/screens/crew6/scienceScreen.cpp @@ -162,9 +162,9 @@ ScienceScreen::ScienceScreen(GuiContainer* owner, ECrewPosition crew_position) } // List each system's status. - for(int n = 0; n < SYS_COUNT; n++) + for(int n = 0; n < ShipSystem::COUNT; n++) { - info_system[n] = new GuiKeyValueDisplay(info_sidebar, "SCIENCE_SYSTEM_" + string(n), 0.75, getLocaleSystemName(ESystem(n)), "-"); + info_system[n] = new GuiKeyValueDisplay(info_sidebar, "SCIENCE_SYSTEM_" + string(n), 0.75, getLocaleSystemName(ShipSystem::Type(n)), "-"); info_system[n]->setSize(GuiElement::GuiSizeMax, 30); info_system[n]->hide(); } @@ -279,7 +279,7 @@ void ScienceScreen::onDraw(sp::RenderTarget& renderer) info_type_button->hide(); sidebar_pager->hide(); - for(int n = 0; n < SYS_COUNT; n++) + for(int n = 0; n < ShipSystem::COUNT; n++) info_system[n]->setValue("-")->hide(); if (probe) @@ -364,7 +364,7 @@ void ScienceScreen::onDraw(sp::RenderTarget& renderer) info_shield_frequency->show(); info_beam_frequency->show(); - for(int n = 0; n < SYS_COUNT; n++) + for(int n = 0; n < ShipSystem::COUNT; n++) { info_system[n]->hide(); } @@ -376,7 +376,7 @@ void ScienceScreen::onDraw(sp::RenderTarget& renderer) info_shield_frequency->hide(); info_beam_frequency->hide(); - for(int n = 0; n < SYS_COUNT; n++) + for(int n = 0; n < ShipSystem::COUNT; n++) { info_system[n]->show(); } @@ -388,7 +388,7 @@ void ScienceScreen::onDraw(sp::RenderTarget& renderer) info_shield_frequency->hide(); info_beam_frequency->hide(); - for(int n = 0; n < SYS_COUNT; n++) + for(int n = 0; n < ShipSystem::COUNT; n++) { info_system[n]->hide(); } @@ -417,10 +417,13 @@ void ScienceScreen::onDraw(sp::RenderTarget& renderer) } // Show the status of each subsystem. - for(int n = 0; n < SYS_COUNT; n++) + for(int n = 0; n < ShipSystem::COUNT; n++) { - float system_health = ship->systems[n].health; - info_system[n]->setValue(string(int(system_health * 100.0f)) + "%")->setColor(glm::u8vec4(255, 127.5f * (system_health + 1), 127.5f * (system_health + 1), 255)); + auto sys = ShipSystem::get(ship->entity, ShipSystem::Type(n)); + if (sys) { + float system_health = sys->health; + info_system[n]->setValue(string(int(system_health * 100.0f)) + "%")->setColor(glm::u8vec4(255, 127.5f * (system_health + 1), 127.5f * (system_health + 1), 255)); + } } } } diff --git a/src/screens/crew6/scienceScreen.h b/src/screens/crew6/scienceScreen.h index 19cd7acdcc..04f85e5095 100644 --- a/src/screens/crew6/scienceScreen.h +++ b/src/screens/crew6/scienceScreen.h @@ -54,7 +54,7 @@ class ScienceScreen : public GuiOverlay GuiScrollText* info_description; GuiFrequencyCurve* info_shield_frequency; GuiFrequencyCurve* info_beam_frequency; - GuiKeyValueDisplay* info_system[SYS_COUNT]; + GuiKeyValueDisplay* info_system[ShipSystem::COUNT]; GuiToggleButton* probe_view_button; P observation_point; diff --git a/src/screens/crew6/weaponsScreen.cpp b/src/screens/crew6/weaponsScreen.cpp index 4dbf64d300..a816def583 100644 --- a/src/screens/crew6/weaponsScreen.cpp +++ b/src/screens/crew6/weaponsScreen.cpp @@ -65,7 +65,7 @@ WeaponsScreen::WeaponsScreen(GuiContainer* owner) GuiElement* beam_info_box = new GuiElement(this, "BEAM_INFO_BOX"); beam_info_box->setPosition(-20, -120, sp::Alignment::BottomRight)->setSize(280, 150); (new GuiLabel(beam_info_box, "BEAM_INFO_LABEL", tr("Beam info"), 30))->addBackground()->setSize(GuiElement::GuiSizeMax, 50); - (new GuiPowerDamageIndicator(beam_info_box, "", SYS_BeamWeapons, sp::Alignment::CenterLeft))->setSize(GuiElement::GuiSizeMax, 50); + (new GuiPowerDamageIndicator(beam_info_box, "", ShipSystem::Type::BeamWeapons, sp::Alignment::CenterLeft))->setSize(GuiElement::GuiSizeMax, 50); (new GuiBeamFrequencySelector(beam_info_box, "BEAM_FREQUENCY_SELECTOR"))->setPosition(0, 0, sp::Alignment::BottomRight)->setSize(GuiElement::GuiSizeMax, 50); (new GuiBeamTargetSelector(beam_info_box, "BEAM_TARGET_SELECTOR"))->setPosition(0, -50, sp::Alignment::BottomRight)->setSize(GuiElement::GuiSizeMax, 50); @@ -106,14 +106,14 @@ void WeaponsScreen::onDraw(sp::RenderTarget& renderer) if (reactor) energy_display->setValue(string(int(reactor->energy))); front_shield_display->setValue(string(my_spaceship->getShieldPercentage(0)) + "%"); - if (my_spaceship->hasSystem(SYS_FrontShield)) + if (my_spaceship->hasSystem(ShipSystem::Type::FrontShield)) { front_shield_display->show(); } else { front_shield_display->hide(); } rear_shield_display->setValue(string(my_spaceship->getShieldPercentage(1)) + "%"); - if (my_spaceship->hasSystem(SYS_RearShield)) + if (my_spaceship->hasSystem(ShipSystem::Type::RearShield)) { rear_shield_display->show(); } else { diff --git a/src/screens/extra/damcon.cpp b/src/screens/extra/damcon.cpp index 6b0a55c5db..2a5b53da8c 100644 --- a/src/screens/extra/damcon.cpp +++ b/src/screens/extra/damcon.cpp @@ -21,9 +21,9 @@ DamageControlScreen::DamageControlScreen(GuiContainer* owner) hull_display = new GuiKeyValueDisplay(system_health_layout, "HULL", 0.8, tr("damagecontrol", "Hull"), "0%"); hull_display->setSize(GuiElement::GuiSizeMax, 40); - for(unsigned int n=0; nsetSize(GuiElement::GuiSizeMax, 40); } @@ -45,16 +45,20 @@ void DamageControlScreen::onDraw(sp::RenderTarget& renderer) hull_display->setColor(glm::u8vec4{255,255,255,255}); } - for(unsigned int n=0; nsetVisible(my_spaceship->hasSystem(ESystem(n))); - system_health[n]->setValue(string(int(my_spaceship->systems[n].health * 100)) + "%"); - if (my_spaceship->systems[n].health < 0) - system_health[n]->setColor(glm::u8vec4(255, 0, 0, 255)); - else if (my_spaceship->systems[n].health_max < 1.0f) - system_health[n]->setColor(glm::u8vec4(255, 255, 0, 255)); - else - system_health[n]->setColor(glm::u8vec4{255,255,255,255}); + auto sys = ShipSystem::get(my_spaceship->entity, ShipSystem::Type(n)); + system_health[n]->setVisible(sys); + if (sys) { + system_health[n]->setValue(string(int(sys->health * 100)) + "%"); + if (sys->health < 0) + system_health[n]->setColor(glm::u8vec4(255, 0, 0, 255)); + else if (sys->health_max < 1.0f) + system_health[n]->setColor(glm::u8vec4(255, 255, 0, 255)); + else + system_health[n]->setColor(glm::u8vec4{255,255,255,255}); + } + } } } diff --git a/src/screens/extra/damcon.h b/src/screens/extra/damcon.h index 0cfd89b321..2674bfe232 100644 --- a/src/screens/extra/damcon.h +++ b/src/screens/extra/damcon.h @@ -10,7 +10,7 @@ class DamageControlScreen : public GuiOverlay { private: GuiKeyValueDisplay* hull_display; - GuiKeyValueDisplay* system_health[SYS_COUNT]; + GuiKeyValueDisplay* system_health[ShipSystem::COUNT]; public: DamageControlScreen(GuiContainer* owner); diff --git a/src/screens/extra/powerManagement.cpp b/src/screens/extra/powerManagement.cpp index 1352f0442d..b8c1007683 100644 --- a/src/screens/extra/powerManagement.cpp +++ b/src/screens/extra/powerManagement.cpp @@ -1,6 +1,7 @@ #include "powerManagement.h" #include "missileWeaponData.h" #include "components/reactor.h" +#include "components/coolant.h" #include "playerInfo.h" #include "spaceObjects/playerSpaceship.h" @@ -15,7 +16,7 @@ PowerManagementScreen::PowerManagementScreen(GuiContainer* owner) : GuiOverlay(owner, "POWER_MANAGEMENT_SCREEN", colorConfig.background) { - selected_system = SYS_None; + selected_system = ShipSystem::Type::None; energy_display = new GuiKeyValueDisplay(this, "ENERGY_DISPLAY", 0.45, tr("Energy"), ""); energy_display->setIcon("gui/icons/energy")->setTextSize(20)->setPosition(20, 20, sp::Alignment::TopLeft)->setSize(285, 40); @@ -23,7 +24,7 @@ PowerManagementScreen::PowerManagementScreen(GuiContainer* owner) coolant_display->setIcon("gui/icons/coolant")->setTextSize(20)->setPosition(315, 20, sp::Alignment::TopLeft)->setSize(280, 40); GuiElement* layout = new GuiElement(this, ""); layout->setPosition(20, 60, sp::Alignment::TopLeft)->setSize(GuiElement::GuiSizeMax, 400)->setAttribute("layout", "horizontal"); - for(int n=0; nsetSize(290, 400); - (new GuiLabel(box, "", getLocaleSystemName(ESystem(n)), 30))->addBackground()->setAlignment(sp::Alignment::Center)->setPosition(0, 0, sp::Alignment::TopLeft)->setSize(290, 50); + (new GuiLabel(box, "", getLocaleSystemName(ShipSystem::Type(n)), 30))->addBackground()->setAlignment(sp::Alignment::Center)->setPosition(0, 0, sp::Alignment::TopLeft)->setSize(290, 50); (new GuiLabel(box, "", tr("button", "Power"), 30))->setVertical()->setAlignment(sp::Alignment::CenterLeft)->setPosition(20, 50, sp::Alignment::TopLeft)->setSize(30, 340); (new GuiLabel(box, "", tr("button", "Coolant"), 30))->setVertical()->setAlignment(sp::Alignment::CenterLeft)->setPosition(100, 50, sp::Alignment::TopLeft)->setSize(30, 340); (new GuiLabel(box, "", tr("button", "Heat"), 30))->setVertical()->setAlignment(sp::Alignment::CenterLeft)->setPosition(180, 50, sp::Alignment::TopLeft)->setSize(30, 340); @@ -46,7 +47,7 @@ PowerManagementScreen::PowerManagementScreen(GuiContainer* owner) systems[n].power_slider = new GuiSlider(box, "", 3.0, 0.0, 1.0, [n](float value) { if (my_spaceship) - my_spaceship->commandSetSystemPowerRequest(ESystem(n), value); + my_spaceship->commandSetSystemPowerRequest(ShipSystem::Type(n), value); }); systems[n].power_slider->addSnapValue(1.0, 0.1)->setPosition(50, 50, sp::Alignment::TopLeft)->setSize(55, 340); @@ -55,7 +56,7 @@ PowerManagementScreen::PowerManagementScreen(GuiContainer* owner) systems[n].coolant_slider = new GuiSlider(box, "", 10.0, 0.0, 0.0, [n](float value) { if (my_spaceship) - my_spaceship->commandSetSystemCoolantRequest(ESystem(n), value); + my_spaceship->commandSetSystemCoolantRequest(ShipSystem::Type(n), value); }); systems[n].coolant_slider->setPosition(130, 50, sp::Alignment::TopLeft)->setSize(55, 340); @@ -78,6 +79,7 @@ void PowerManagementScreen::onDraw(sp::RenderTarget& renderer) if (my_spaceship) { auto reactor = my_spaceship->entity.getComponent(); + auto coolant = my_spaceship->entity.getComponent(); if (reactor) { //Update the energy usage. if (previous_energy_measurement == 0.0f) @@ -98,21 +100,29 @@ void PowerManagementScreen::onDraw(sp::RenderTarget& renderer) } energy_display->setValue(string(int(reactor->energy)) + " (" + string(int(average_energy_delta * 60.0f)) + "/m)"); } - coolant_display->setValue(string(int(my_spaceship->max_coolant * 10)) + "%"); + coolant_display->setVisible(coolant); + if (coolant) + coolant_display->setValue(string(int(coolant->max * 100.0f / coolant->max_coolant_per_system)) + "%"); - for(int n=0; nsetVisible(my_spaceship->hasSystem(ESystem(n))); - systems[n].power_slider->setValue(my_spaceship->systems[n].power_request); - systems[n].coolant_slider->setValue(std::min(my_spaceship->systems[n].coolant_request, my_spaceship->max_coolant)); - systems[n].coolant_slider->setEnable(!my_spaceship->auto_coolant_enabled); - - float heat = my_spaceship->systems[n].heat_level; - float power = my_spaceship->systems[n].power_level; - float coolant = my_spaceship->systems[n].coolant_level; - systems[n].heat_bar->setValue(heat)->setColor(glm::u8vec4(128, 128 * (1.0f - heat), 0, 255)); - systems[n].power_bar->setValue(power)->setColor(glm::u8vec4(255, 255, 0, 255)); - systems[n].coolant_bar->setValue(coolant)->setColor(glm::u8vec4(0, 128, 255, 255)); + auto sys = ShipSystem::get(my_spaceship->entity, ShipSystem::Type(n)); + systems[n].box->setVisible(sys); + if (sys) { + systems[n].power_slider->setValue(sys->power_request); + systems[n].coolant_slider->setVisible(coolant); + if (coolant) { + systems[n].coolant_slider->setValue(std::min(sys->coolant_request, coolant->max)); + systems[n].coolant_slider->setEnable(!coolant->auto_levels); + } + + float heat = sys->heat_level; + float power = sys->power_level; + float coolant = sys->coolant_level; + systems[n].heat_bar->setValue(heat)->setColor(glm::u8vec4(128, 128 * (1.0f - heat), 0, 255)); + systems[n].power_bar->setValue(power)->setColor(glm::u8vec4(255, 255, 0, 255)); + systems[n].coolant_bar->setValue(coolant)->setColor(glm::u8vec4(0, 128, 255, 255)); + } } } } @@ -121,24 +131,24 @@ void PowerManagementScreen::onUpdate() { if (my_spaceship && isVisible()) { - if (keys.engineering_select_reactor.getDown()) selected_system = SYS_Reactor; - if (keys.engineering_select_beam_weapons.getDown()) selected_system = SYS_BeamWeapons; - if (keys.engineering_select_missile_system.getDown()) selected_system = SYS_MissileSystem; - if (keys.engineering_select_maneuvering_system.getDown()) selected_system = SYS_Maneuver; - if (keys.engineering_select_impulse_system.getDown()) selected_system = SYS_Impulse; - if (keys.engineering_select_warp_system.getDown()) selected_system = SYS_Warp; - if (keys.engineering_select_jump_drive_system.getDown()) selected_system = SYS_JumpDrive; - if (keys.engineering_select_front_shield_system.getDown()) selected_system = SYS_FrontShield; - if (keys.engineering_select_rear_shield_system.getDown()) selected_system = SYS_RearShield; + if (keys.engineering_select_reactor.getDown()) selected_system = ShipSystem::Type::Reactor; + if (keys.engineering_select_beam_weapons.getDown()) selected_system = ShipSystem::Type::BeamWeapons; + if (keys.engineering_select_missile_system.getDown()) selected_system = ShipSystem::Type::MissileSystem; + if (keys.engineering_select_maneuvering_system.getDown()) selected_system = ShipSystem::Type::Maneuver; + if (keys.engineering_select_impulse_system.getDown()) selected_system = ShipSystem::Type::Impulse; + if (keys.engineering_select_warp_system.getDown()) selected_system = ShipSystem::Type::Warp; + if (keys.engineering_select_jump_drive_system.getDown()) selected_system = ShipSystem::Type::JumpDrive; + if (keys.engineering_select_front_shield_system.getDown()) selected_system = ShipSystem::Type::FrontShield; + if (keys.engineering_select_rear_shield_system.getDown()) selected_system = ShipSystem::Type::RearShield; // Don't act if the selected system doesn't exist. if (!my_spaceship->hasSystem(selected_system)) return; // If we selected a system, check for the power/coolant modifier. - if (selected_system != SYS_None) + if (selected_system != ShipSystem::Type::None) { - GuiSlider* power_slider = systems[selected_system].power_slider; + GuiSlider* power_slider = systems[int(selected_system)].power_slider; // Note the code duplication with crew6/engineeringScreen if (keys.engineering_set_power_000.getDown()) @@ -185,16 +195,22 @@ void PowerManagementScreen::onUpdate() auto power_adjust = (keys.engineering_increase_power.getValue() - keys.engineering_decrease_power.getValue()) * 0.1f; if (power_adjust != 0.0f) { - power_slider->setValue(my_spaceship->systems[selected_system].power_request + power_adjust); - my_spaceship->commandSetSystemPowerRequest(selected_system, power_slider->getValue()); + auto sys = ShipSystem::get(my_spaceship->entity, selected_system); + if (sys) { + power_slider->setValue(sys->power_request + power_adjust); + my_spaceship->commandSetSystemPowerRequest(selected_system, power_slider->getValue()); + } } - GuiSlider* coolant_slider = systems[selected_system].coolant_slider; + GuiSlider* coolant_slider = systems[int(selected_system)].coolant_slider; auto coolant_adjust = (keys.engineering_increase_coolant.getValue() - keys.engineering_decrease_coolant.getValue()) * 0.5f; if (coolant_adjust != 0.0f) { - coolant_slider->setValue(my_spaceship->systems[selected_system].coolant_request + coolant_adjust); - my_spaceship->commandSetSystemCoolantRequest(selected_system, coolant_slider->getValue()); + auto sys = ShipSystem::get(my_spaceship->entity, selected_system); + if (sys) { + coolant_slider->setValue(sys->coolant_request + coolant_adjust); + my_spaceship->commandSetSystemCoolantRequest(selected_system, coolant_slider->getValue()); + } } } } diff --git a/src/screens/extra/powerManagement.h b/src/screens/extra/powerManagement.h index 4387e2de56..78daf9783b 100644 --- a/src/screens/extra/powerManagement.h +++ b/src/screens/extra/powerManagement.h @@ -18,7 +18,7 @@ class PowerManagementScreen : public GuiOverlay float previous_energy_measurement; float previous_energy_level; float average_energy_delta; - ESystem selected_system = SYS_None; + ShipSystem::Type selected_system = ShipSystem::Type::None; class SystemRow { @@ -30,7 +30,7 @@ class PowerManagementScreen : public GuiOverlay GuiProgressbar* power_bar; GuiProgressbar* coolant_bar; }; - SystemRow systems[SYS_COUNT]; + SystemRow systems[ShipSystem::COUNT]; public: PowerManagementScreen(GuiContainer* owner); diff --git a/src/screens/gm/tweak.cpp b/src/screens/gm/tweak.cpp index b3867a730b..4822031ae2 100644 --- a/src/screens/gm/tweak.cpp +++ b/src/screens/gm/tweak.cpp @@ -146,7 +146,7 @@ GuiTweakShip::GuiTweakShip(GuiContainer* owner) (new GuiLabel(left_col, "", tr("Turn speed:"), 30))->setSize(GuiElement::GuiSizeMax, 50); turn_speed_slider = new GuiSlider(left_col, "", 0.0, 35, 0.0, [this](float value) { - target->turn_speed = value; + //TODO: target->turn_speed = value; }); turn_speed_slider->addOverlay()->setSize(GuiElement::GuiSizeMax, 40); @@ -226,7 +226,7 @@ void GuiTweakShip::onDraw(sp::RenderTarget& renderer) jump_toggle->setValue(target->hasJumpDrive()); //TODO: impulse_speed_slider->setValue(target->impulse_max_speed); //TODO: impulse_reverse_speed_slider->setValue(target->impulse_max_reverse_speed); - turn_speed_slider->setValue(target->turn_speed); + //TODO: turn_speed_slider->setValue(target->turn_speed); //TODO: hull_max_slider->setValue(target->hull_max); can_be_destroyed_toggle->setValue(target->getCanBeDestroyed()); short_range_radar_slider->setValue(target->getShortRangeRadarRange()); @@ -614,12 +614,12 @@ GuiShipTweakSystems::GuiShipTweakSystems(GuiContainer* owner) auto right_col = new GuiElement(this, "RIGHT_LAYOUT"); right_col->setPosition(-25, 25, sp::Alignment::TopRight)->setSize(200, GuiElement::GuiSizeMax)->setAttribute("layout", "vertical"); - for(int n=0; nsetSize(GuiElement::GuiSizeMax, 30); system_damage[n] = new GuiSlider(left_col, "", -1.0, 1.0, 0.0, [this, n](float value) { - target->systems[n].health = std::min(value,target->systems[n].health_max); + //TODO target->systems[n].health = std::min(value,target->systems[n].health_max); }); system_damage[n]->setSize(GuiElement::GuiSizeMax, 30); system_damage[n]->addSnapValue(-1.0, 0.01); @@ -628,8 +628,8 @@ GuiShipTweakSystems::GuiShipTweakSystems(GuiContainer* owner) (new GuiLabel(center_col, "", tr("{system} health max").format({{"system", getLocaleSystemName(system)}}), 20))->setSize(GuiElement::GuiSizeMax, 30); system_health_max[n] = new GuiSlider(center_col, "", -1.0, 1.0, 1.0, [this, n](float value) { - target->systems[n].health_max = value; - target->systems[n].health = std::min(value,target->systems[n].health); + //TODO target->systems[n].health_max = value; + //TODO target->systems[n].health = std::min(value,target->systems[n].health); }); system_health_max[n]->setSize(GuiElement::GuiSizeMax, 30); system_health_max[n]->addSnapValue(-1.0, 0.01); @@ -638,7 +638,7 @@ GuiShipTweakSystems::GuiShipTweakSystems(GuiContainer* owner) (new GuiLabel(right_col, "", tr("{system} heat").format({{"system", getLocaleSystemName(system)}}), 20))->setSize(GuiElement::GuiSizeMax, 30); system_heat[n] = new GuiSlider(right_col, "", 0.0, 1.0, 0.0, [this, n](float value) { - target->systems[n].heat_level = value; + //TODO target->systems[n].heat_level = value; }); system_heat[n]->setSize(GuiElement::GuiSizeMax, 30); system_heat[n]->addSnapValue( 0.0, 0.01); @@ -648,11 +648,11 @@ GuiShipTweakSystems::GuiShipTweakSystems(GuiContainer* owner) void GuiShipTweakSystems::onDraw(sp::RenderTarget& renderer) { - for(int n=0; nsetValue(target->systems[n].health); - system_health_max[n]->setValue(target->systems[n].health_max); - system_heat[n]->setValue(target->systems[n].heat_level); + //TODO system_damage[n]->setValue(target->systems[n].health); + //TODO system_health_max[n]->setValue(target->systems[n].health_max); + //TODO system_heat[n]->setValue(target->systems[n].heat_level); } } @@ -682,9 +682,9 @@ GuiShipTweakSystemPowerFactors::GuiShipTweakSystemPowerFactors(GuiContainer* own (new GuiLabel(center_col, "", tr("current factor"), 20))->setSize(GuiElement::GuiSizeMax, 30); (new GuiLabel(right_col, "", tr("desired factor"), 20))->setSize(GuiElement::GuiSizeMax, 30); - for (int n = 0; n < SYS_COUNT; n++) + for (int n = 0; n < ShipSystem::COUNT; n++) { - ESystem system = ESystem(n); + ShipSystem::Type system = ShipSystem::Type(n); (new GuiLabel(left_col, "", tr("{system}").format({ {"system", getLocaleSystemName(system)} }), 20))->setSize(GuiElement::GuiSizeMax, 30); system_current_power_factor[n] = new GuiLabel(center_col, "", "", 20); system_current_power_factor[n]->setSize(GuiElement::GuiSizeMax, 30); @@ -699,12 +699,12 @@ GuiShipTweakSystemPowerFactors::GuiShipTweakSystemPowerFactors(GuiContainer* own if (converted == 0.f && end == text.c_str()) { // failed - reset text to current value. - system_power_factor[n]->setText(string(target->systems[n].power_factor, 1)); + //TODO system_power_factor[n]->setText(string(target->systems[n].power_factor, 1)); } else { // apply! - target->systems[n].power_factor = converted; + //TODO target->systems[n].power_factor = converted; } }); } @@ -716,17 +716,17 @@ void GuiShipTweakSystemPowerFactors::open(P target) { P ship = target; this->target = ship; - for (int n = 0; n < SYS_COUNT; n++) + for (int n = 0; n < ShipSystem::COUNT; n++) { - system_power_factor[n]->setText(string(this->target->systems[n].power_factor, 1)); + //TODO system_power_factor[n]->setText(string(this->target->systems[n].power_factor, 1)); } } void GuiShipTweakSystemPowerFactors::onDraw(sp::RenderTarget& target) { - for (int n = 0; n < SYS_COUNT; n++) + for (int n = 0; n < ShipSystem::COUNT; n++) { - system_current_power_factor[n]->setText(string(this->target->systems[n].power_factor, 1)); + //TODO system_current_power_factor[n]->setText(string(this->target->systems[n].power_factor, 1)); } } @@ -745,16 +745,16 @@ GuiShipTweakSystemRates::GuiShipTweakSystemRates(GuiContainer* owner, Type type) (new GuiLabel(center_col, "", tr("current rate"), 20))->setSize(GuiElement::GuiSizeMax, 30); (new GuiLabel(right_col, "", tr("desired rate"), 20))->setSize(GuiElement::GuiSizeMax, 30); - for (int n = 0; n < SYS_COUNT; n++) + for (int n = 0; n < ShipSystem::COUNT; n++) { - ESystem system = ESystem(n); + auto system = ShipSystem::Type(n); (new GuiLabel(left_col, "", tr("{system}").format({ {"system", getLocaleSystemName(system)} }), 20))->setSize(GuiElement::GuiSizeMax, 30); current_rates[n] = new GuiLabel(center_col, "", "", 20); current_rates[n]->setSize(GuiElement::GuiSizeMax, 30); desired_rates[n] = new GuiTextEntry(right_col, "", ""); desired_rates[n]->setSize(GuiElement::GuiSizeMax, 30); - desired_rates[n]->enterCallback([this, n](const string& text) + desired_rates[n]->enterCallback([this, system](const string& text) { // Perform safe conversion (typos can happen). char* end = nullptr; @@ -762,12 +762,12 @@ GuiShipTweakSystemRates::GuiShipTweakSystemRates(GuiContainer* owner, Type type) if (converted == 0.f && end == text.c_str()) { // failed - reset text to current value. - desired_rates[n]->setText(string(getRateValue(ESystem(n), this->type), 2)); + desired_rates[int(system)]->setText(string(getRateValue(system, this->type), 2)); } else { // apply! - setRateValue(ESystem(n), this->type, converted); + setRateValue(system, this->type, converted); } }); } @@ -779,22 +779,22 @@ void GuiShipTweakSystemRates::open(P target) { P ship = target; this->target = ship; - for (int n = 0; n < SYS_COUNT; n++) + for (int n = 0; n < ShipSystem::COUNT; n++) { - current_rates[n]->setText(string(getRateValue(ESystem(n), type), 2)); + current_rates[n]->setText(string(getRateValue(ShipSystem::Type(n), type), 2)); } } void GuiShipTweakSystemRates::onDraw(sp::RenderTarget& target) { - for (int n = 0; n < SYS_COUNT; n++) + for (int n = 0; n < ShipSystem::COUNT; n++) { - current_rates[n]->setText(string(getRateValue(ESystem(n), type), 2)); + current_rates[n]->setText(string(getRateValue(ShipSystem::Type(n), type), 2)); } } -float GuiShipTweakSystemRates::getRateValue(ESystem system, Type type) const +float GuiShipTweakSystemRates::getRateValue(ShipSystem::Type system, Type type) const { switch (type) { @@ -810,7 +810,7 @@ float GuiShipTweakSystemRates::getRateValue(ESystem system, Type type) const return 0.f; } -void GuiShipTweakSystemRates::setRateValue(ESystem system, Type type, float value) +void GuiShipTweakSystemRates::setRateValue(ShipSystem::Type system, Type type, float value) { switch (type) { @@ -879,13 +879,13 @@ GuiShipTweakPlayer::GuiShipTweakPlayer(GuiContainer* owner) // Display Boost/Strafe speed sliders (new GuiLabel(left_col, "", tr("Boost Speed:"), 30))->setSize(GuiElement::GuiSizeMax, 50); combat_maneuver_boost_speed_slider = new GuiSlider(left_col, "", 0.0, 1000, 0.0, [this](float value) { - target->combat_maneuver_boost_speed = value; + //TODO: target->combat_maneuver_boost_speed = value; }); combat_maneuver_boost_speed_slider->addOverlay()->setSize(GuiElement::GuiSizeMax, 40); (new GuiLabel(left_col, "", tr("Strafe Speed:"), 30))->setSize(GuiElement::GuiSizeMax, 50); combat_maneuver_strafe_speed_slider = new GuiSlider(left_col, "", 0.0, 1000, 0.0, [this](float value) { - target->combat_maneuver_strafe_speed = value; + //TODO: target->combat_maneuver_strafe_speed = value; }); combat_maneuver_strafe_speed_slider->addOverlay()->setSize(GuiElement::GuiSizeMax, 40); @@ -954,12 +954,12 @@ void GuiShipTweakPlayer::open(P target) control_code->setText(player->control_code); // Set and snap boost speed slider to current value - combat_maneuver_boost_speed_slider->setValue(player->combat_maneuver_boost_speed); - combat_maneuver_boost_speed_slider->clearSnapValues()->addSnapValue(player->combat_maneuver_boost_speed, 20.0f); + //TODO: combat_maneuver_boost_speed_slider->setValue(player->combat_maneuver_boost_speed); + //TODO: combat_maneuver_boost_speed_slider->clearSnapValues()->addSnapValue(player->combat_maneuver_boost_speed, 20.0f); // Set and snap strafe speed slider to current value - combat_maneuver_strafe_speed_slider->setValue(player->combat_maneuver_strafe_speed); - combat_maneuver_strafe_speed_slider->clearSnapValues()->addSnapValue(player->combat_maneuver_strafe_speed, 20.0f); + //TODO: combat_maneuver_strafe_speed_slider->setValue(player->combat_maneuver_strafe_speed); + //TODO: combat_maneuver_strafe_speed_slider->clearSnapValues()->addSnapValue(player->combat_maneuver_strafe_speed, 20.0f); } } @@ -1085,7 +1085,7 @@ GuiShipTweakPlayer2::GuiShipTweakPlayer2(GuiContainer* owner) void GuiShipTweakPlayer2::onDraw(sp::RenderTarget& renderer) { - coolant_slider->setValue(target->max_coolant); + //coolant_slider->setValue(target->max_coolant); max_scan_probes_slider->setValue(target->getMaxScanProbeCount()); scan_probes_slider->setValue(target->getScanProbeCount()); can_scan->setValue(target->getCanScan()); @@ -1094,7 +1094,7 @@ void GuiShipTweakPlayer2::onDraw(sp::RenderTarget& renderer) can_combat_maneuver->setValue(target->getCanCombatManeuver()); can_self_destruct->setValue(target->getCanSelfDestruct()); can_launch_probe->setValue(target->getCanLaunchProbe()); - auto_coolant_enabled->setValue(target->auto_coolant_enabled); + //auto_coolant_enabled->setValue(target->auto_coolant_enabled); auto_repair_enabled->setValue(target->auto_repair_enabled); energy_warp_per_second->setText(tr("player_tweak", "Warp (E/s): {energy_per_second}").format({ {"energy_per_second", string(target->getEnergyWarpPerSecond())} })); diff --git a/src/screens/gm/tweak.h b/src/screens/gm/tweak.h index 64f89a342a..b806b8c880 100644 --- a/src/screens/gm/tweak.h +++ b/src/screens/gm/tweak.h @@ -181,9 +181,9 @@ class GuiShipTweakSystems : public GuiTweakPage private: P target; - GuiSlider* system_damage[SYS_COUNT]; - GuiSlider* system_health_max[SYS_COUNT]; - GuiSlider* system_heat[SYS_COUNT]; + GuiSlider* system_damage[ShipSystem::COUNT]; + GuiSlider* system_health_max[ShipSystem::COUNT]; + GuiSlider* system_heat[ShipSystem::COUNT]; public: GuiShipTweakSystems(GuiContainer* owner); @@ -197,8 +197,8 @@ class GuiShipTweakSystemPowerFactors : public GuiTweakPage { private: P target; - GuiLabel* system_current_power_factor[SYS_COUNT]; - GuiTextEntry* system_power_factor[SYS_COUNT]; + GuiLabel* system_current_power_factor[ShipSystem::COUNT]; + GuiTextEntry* system_power_factor[ShipSystem::COUNT]; static string powerFactorToText(float); public: @@ -223,10 +223,10 @@ class GuiShipTweakSystemRates : public GuiTweakPage void open(P target) override; void onDraw(sp::RenderTarget& target) override; private: - float getRateValue(ESystem system, Type type) const; - void setRateValue(ESystem system, Type type, float value); - std::array current_rates; - std::array desired_rates; + float getRateValue(ShipSystem::Type system, Type type) const; + void setRateValue(ShipSystem::Type system, Type type, float value); + std::array current_rates; + std::array desired_rates; P target; Type type; diff --git a/src/shipTemplate.cpp b/src/shipTemplate.cpp index f8e582c2f2..c01a7ad923 100644 --- a/src/shipTemplate.cpp +++ b/src/shipTemplate.cpp @@ -319,14 +319,14 @@ glm::ivec2 ShipTemplate::interiorSize() return max_pos; } -ESystem ShipTemplate::getSystemAtRoom(glm::ivec2 position) +ShipSystem::Type ShipTemplate::getSystemAtRoom(glm::ivec2 position) { for(unsigned int n=0; n position.x && rooms[n].position.y <= position.y && rooms[n].position.y + rooms[n].size.y > position.y) return rooms[n].system; } - return SYS_None; + return ShipSystem::Type::None; } void ShipTemplate::setCollisionData(P object) @@ -371,37 +371,37 @@ std::vector ShipTemplate::getTemplateNameList(TemplateType type) return ret; } -string getSystemName(ESystem system) +string getSystemName(ShipSystem::Type system) { switch(system) { - case SYS_Reactor: return "Reactor"; - case SYS_BeamWeapons: return "Beam Weapons"; - case SYS_MissileSystem: return "Missile System"; - case SYS_Maneuver: return "Maneuvering"; - case SYS_Impulse: return "Impulse Engines"; - case SYS_Warp: return "Warp Drive"; - case SYS_JumpDrive: return "Jump Drive"; - case SYS_FrontShield: return "Front Shield Generator"; - case SYS_RearShield: return "Rear Shield Generator"; + case ShipSystem::Type::Reactor: return "Reactor"; + case ShipSystem::Type::BeamWeapons: return "Beam Weapons"; + case ShipSystem::Type::MissileSystem: return "Missile System"; + case ShipSystem::Type::Maneuver: return "Maneuvering"; + case ShipSystem::Type::Impulse: return "Impulse Engines"; + case ShipSystem::Type::Warp: return "Warp Drive"; + case ShipSystem::Type::JumpDrive: return "Jump Drive"; + case ShipSystem::Type::FrontShield: return "Front Shield Generator"; + case ShipSystem::Type::RearShield: return "Rear Shield Generator"; default: return "UNKNOWN"; } } -string getLocaleSystemName(ESystem system) +string getLocaleSystemName(ShipSystem::Type system) { switch(system) { - case SYS_Reactor: return tr("system", "Reactor"); - case SYS_BeamWeapons: return tr("system", "Beam Weapons"); - case SYS_MissileSystem: return tr("system", "Missile System"); - case SYS_Maneuver: return tr("system", "Maneuvering"); - case SYS_Impulse: return tr("system", "Impulse Engines"); - case SYS_Warp: return tr("system", "Warp Drive"); - case SYS_JumpDrive: return tr("system", "Jump Drive"); - case SYS_FrontShield: return tr("system", "Front Shield Generator"); - case SYS_RearShield: return tr("system", "Rear Shield Generator"); + case ShipSystem::Type::Reactor: return tr("system", "Reactor"); + case ShipSystem::Type::BeamWeapons: return tr("system", "Beam Weapons"); + case ShipSystem::Type::MissileSystem: return tr("system", "Missile System"); + case ShipSystem::Type::Maneuver: return tr("system", "Maneuvering"); + case ShipSystem::Type::Impulse: return tr("system", "Impulse Engines"); + case ShipSystem::Type::Warp: return tr("system", "Warp Drive"); + case ShipSystem::Type::JumpDrive: return tr("system", "Jump Drive"); + case ShipSystem::Type::FrontShield: return tr("system", "Front Shield Generator"); + case ShipSystem::Type::RearShield: return tr("system", "Rear Shield Generator"); default: return "UNKNOWN"; } @@ -498,10 +498,10 @@ void ShipTemplate::setWeaponStorage(EMissileWeapons weapon, int amount) void ShipTemplate::addRoom(glm::ivec2 position, glm::ivec2 size) { - rooms.push_back(ShipRoomTemplate(position, size, SYS_None)); + rooms.push_back(ShipRoomTemplate(position, size, ShipSystem::Type::None)); } -void ShipTemplate::addRoomSystem(glm::ivec2 position, glm::ivec2 size, ESystem system) +void ShipTemplate::addRoomSystem(glm::ivec2 position, glm::ivec2 size, ShipSystem::Type system) { rooms.push_back(ShipRoomTemplate(position, size, system)); } diff --git a/src/shipTemplate.h b/src/shipTemplate.h index 9906379e0e..1a2ab6c19b 100644 --- a/src/shipTemplate.h +++ b/src/shipTemplate.h @@ -8,6 +8,7 @@ #include "modelData.h" #include "scriptInterfaceMagic.h" #include "multiplayer.h" +#include "components/shipsystem.h" #include "beamTemplate.h" #include "missileWeaponData.h" @@ -15,32 +16,18 @@ constexpr static int max_beam_weapons = 16; constexpr static int max_weapon_tubes = 16; constexpr static int max_shield_count = 8; -enum ESystem -{ - SYS_None = -1, - SYS_Reactor = 0, - SYS_BeamWeapons, - SYS_MissileSystem, - SYS_Maneuver, - SYS_Impulse, - SYS_Warp, - SYS_JumpDrive, - SYS_FrontShield, - SYS_RearShield, - SYS_COUNT -}; /* Define script conversion function for the ESystem enum. */ -template<> void convert::param(lua_State* L, int& idx, ESystem& es); +template<> void convert::param(lua_State* L, int& idx, ShipSystem::Type& es); class ShipRoomTemplate { public: glm::ivec2 position; glm::ivec2 size; - ESystem system; + ShipSystem::Type system; - ShipRoomTemplate(glm::ivec2 position, glm::ivec2 size, ESystem system) : position(position), size(size), system(system) {} + ShipRoomTemplate(glm::ivec2 position, glm::ivec2 size, ShipSystem::Type system) : position(position), size(size), system(system) {} }; class ShipDoorTemplate { @@ -186,7 +173,7 @@ class ShipTemplate : public PObject void setCloaking(bool enabled); void setWeaponStorage(EMissileWeapons weapon, int amount); void addRoom(glm::ivec2 position, glm::ivec2 size); - void addRoomSystem(glm::ivec2 position, glm::ivec2 size, ESystem system); + void addRoomSystem(glm::ivec2 position, glm::ivec2 size, ShipSystem::Type system); void addDoor(glm::ivec2 position, bool horizontal); void setRadarTrace(string trace); void setLongRangeRadarRange(float range); @@ -196,7 +183,7 @@ class ShipTemplate : public PObject P copy(string new_name); glm::ivec2 interiorSize(); - ESystem getSystemAtRoom(glm::ivec2 position); + ShipSystem::Type getSystemAtRoom(glm::ivec2 position); void setCollisionData(P object); public: @@ -204,9 +191,9 @@ class ShipTemplate : public PObject static std::vector getAllTemplateNames(); static std::vector getTemplateNameList(TemplateType type); }; -string getSystemName(ESystem system); -string getLocaleSystemName(ESystem system); -REGISTER_MULTIPLAYER_ENUM(ESystem); +string getSystemName(ShipSystem::Type system); +string getLocaleSystemName(ShipSystem::Type system); +REGISTER_MULTIPLAYER_ENUM(ShipSystem::Type); /* Define script conversion function for the ShipTemplate::TemplateType enum. */ template<> void convert::param(lua_State* L, int& idx, ShipTemplate::TemplateType& tt); diff --git a/src/shipTemplate.hpp b/src/shipTemplate.hpp index e9dfb054e8..8eed2d79be 100644 --- a/src/shipTemplate.hpp +++ b/src/shipTemplate.hpp @@ -2,29 +2,29 @@ #define _SHIPTEMPLATE_HPP_ /* Define script conversion function for the ESystem enum. */ -template<> void convert::param(lua_State* L, int& idx, ESystem& es) +template<> void convert::param(lua_State* L, int& idx, ShipSystem::Type& es) { string str = string(luaL_checkstring(L, idx++)).lower(); if (str == "reactor") - es = SYS_Reactor; + es = ShipSystem::Type::Reactor; else if (str == "beamweapons") - es = SYS_BeamWeapons; + es = ShipSystem::Type::BeamWeapons; else if (str == "missilesystem") - es = SYS_MissileSystem; + es = ShipSystem::Type::MissileSystem; else if (str == "maneuver") - es = SYS_Maneuver; + es = ShipSystem::Type::Maneuver; else if (str == "impulse") - es = SYS_Impulse; + es = ShipSystem::Type::Impulse; else if (str == "warp") - es = SYS_Warp; + es = ShipSystem::Type::Warp; else if (str == "jumpdrive") - es = SYS_JumpDrive; + es = ShipSystem::Type::JumpDrive; else if (str == "frontshield") - es = SYS_FrontShield; + es = ShipSystem::Type::FrontShield; else if (str == "rearshield") - es = SYS_RearShield; + es = ShipSystem::Type::RearShield; else - es = SYS_None; + es = ShipSystem::Type::None; } /* Define script conversion function for the ShipTemplate::TemplateType enum. */ diff --git a/src/spaceObjects/cpuShip.cpp b/src/spaceObjects/cpuShip.cpp index c6c53ff107..8a8d093343 100644 --- a/src/spaceObjects/cpuShip.cpp +++ b/src/spaceObjects/cpuShip.cpp @@ -10,6 +10,7 @@ #include "nebula.h" #include "random.h" #include "multiplayer_server.h" +#include "components/maneuveringthrusters.h" #include "scriptInterface.h" @@ -103,7 +104,6 @@ CpuShip::CpuShip() orders = AI_Idle; setRotation(random(0, 360)); - target_rotation = getRotation(); comms_script_name = "comms_ship.lua"; @@ -126,9 +126,6 @@ void CpuShip::update(float delta) if (!game_server) return; - for(int n=0; ncanSwitchAI())) { shipAIFactoryFunc_t f = ShipAIFactory::getAIFactory(new_ai_name); @@ -161,7 +158,8 @@ void CpuShip::orderIdle() void CpuShip::orderRoaming() { - target_rotation = getRotation(); + auto thrusters = entity.getComponent(); + if (thrusters) thrusters->stop(); orders = AI_Roaming; order_target = NULL; order_target_location = glm::vec2(0, 0); @@ -170,7 +168,8 @@ void CpuShip::orderRoaming() void CpuShip::orderRoamingAt(glm::vec2 position) { - target_rotation = getRotation(); + auto thrusters = entity.getComponent(); + if (thrusters) thrusters->stop(); orders = AI_Roaming; order_target = NULL; order_target_location = position; @@ -193,7 +192,8 @@ void CpuShip::orderRetreat(P object) void CpuShip::orderStandGround() { - target_rotation = getRotation(); + auto thrusters = entity.getComponent(); + if (thrusters) thrusters->stop(); orders = AI_StandGround; order_target = NULL; order_target_location = glm::vec2(0, 0); diff --git a/src/spaceObjects/playerSpaceship.cpp b/src/spaceObjects/playerSpaceship.cpp index 84ee965d35..5c9dded289 100644 --- a/src/spaceObjects/playerSpaceship.cpp +++ b/src/spaceObjects/playerSpaceship.cpp @@ -11,11 +11,13 @@ #include "random.h" #include "components/reactor.h" +#include "components/coolant.h" #include "components/beamweapon.h" #include "components/warpdrive.h" #include "components/jumpdrive.h" #include "components/shields.h" #include "components/missiletubes.h" +#include "components/maneuveringthrusters.h" #include "systems/jumpsystem.h" #include "systems/docking.h" #include "systems/missilesystem.h" @@ -343,8 +345,6 @@ PlayerSpaceship::PlayerSpaceship() comms_open_delay = 0.0; shield_calibration_delay = 0.0; auto_repair_enabled = false; - auto_coolant_enabled = false; - max_coolant = max_coolant_per_system; scan_probe_stock = max_scan_probes; alert_level = AL_Normal; shields_active = false; @@ -356,7 +356,6 @@ PlayerSpaceship::PlayerSpaceship() for(unsigned int faction_id = 0; faction_id < factionInfo.size(); faction_id++) setScannedStateForFaction(faction_id, SS_FullScan); - updateMemberReplicationUpdateDelay(&target_rotation, 0.1); registerMemberReplication(&can_scan); registerMemberReplication(&can_hack); registerMemberReplication(&can_combat_maneuver); @@ -373,8 +372,6 @@ PlayerSpaceship::PlayerSpaceship() registerMemberReplication(&shields_active); registerMemberReplication(&shield_calibration_delay, 0.5); registerMemberReplication(&auto_repair_enabled); - registerMemberReplication(&max_coolant); - registerMemberReplication(&auto_coolant_enabled); registerMemberReplication(&comms_state); registerMemberReplication(&comms_open_delay, 1.0); registerMemberReplication(&comms_reply_message); @@ -403,31 +400,6 @@ PlayerSpaceship::PlayerSpaceship() registerMemberReplication(&self_destruct_code_show_position[n]); } - // Initialize each subsystem to be powered with no coolant or heat. - for(unsigned int n = 0; n < SYS_COUNT; n++) - { - SDL_assert(n < default_system_power_factors.size()); - systems[n].health = 1.0f; - systems[n].power_level = 1.0f; - systems[n].power_rate_per_second = ShipSystemLegacy::default_power_rate_per_second; - systems[n].power_request = 1.0f; - systems[n].coolant_level = 0.0f; - systems[n].coolant_rate_per_second = ShipSystemLegacy::default_coolant_rate_per_second; - systems[n].heat_level = 0.0f; - systems[n].heat_rate_per_second = ShipSystemLegacy::default_heat_rate_per_second; - systems[n].power_factor = default_system_power_factors[n]; - - registerMemberReplication(&systems[n].power_level); - registerMemberReplication(&systems[n].power_rate_per_second, .5f); - registerMemberReplication(&systems[n].power_request); - registerMemberReplication(&systems[n].coolant_level); - registerMemberReplication(&systems[n].coolant_rate_per_second, .5f); - registerMemberReplication(&systems[n].coolant_request); - registerMemberReplication(&systems[n].heat_level, 1.0); - registerMemberReplication(&systems[n].heat_rate_per_second, .5f); - registerMemberReplication(&systems[n].power_factor); - } - if (game_server) { if (gameGlobalInfo->insertPlayerShip(this) < 0) @@ -462,28 +434,9 @@ void PlayerSpaceship::update(float delta) // subsystem effectiveness when determining the tick rate. if (shield_calibration_delay > 0) { - shield_calibration_delay -= delta * (getSystemEffectiveness(SYS_FrontShield) + getSystemEffectiveness(SYS_RearShield)) / 2.0f; - } - - // Automate cooling if auto_coolant_enabled is true. Distributes coolant to - // subsystems proportionally to their share of the total generated heat. - if (auto_coolant_enabled) - { - float total_heat = 0.0; - - for(int n = 0; n < SYS_COUNT; n++) - { - if (!hasSystem(ESystem(n))) continue; - total_heat += systems[n].heat_level; - } - if (total_heat > 0.0f) - { - for(int n = 0; n < SYS_COUNT; n++) - { - if (!hasSystem(ESystem(n))) continue; - systems[n].coolant_request = max_coolant * systems[n].heat_level / total_heat; - } - } + auto front = ShipSystem::get(entity, ShipSystem::Type::FrontShield); + auto rear = ShipSystem::get(entity, ShipSystem::Type::RearShield); + shield_calibration_delay -= delta * ((front ? front->getSystemEffectiveness() : 0) + (rear ? rear->getSystemEffectiveness() : 0)) / 2.0f; } // Actions performed on the server only. @@ -539,75 +492,6 @@ void PlayerSpaceship::update(float delta) // Consume power based on subsystem requests and state. auto reactor = entity.getComponent(); - if (reactor) { - reactor->energy += delta * getNetSystemEnergyUsage(); - // Cap energy at the max_energy_level. - reactor->energy = std::clamp(reactor->energy, 0.0f, reactor->max_energy); - } - - // Check how much coolant we have requested in total, and if that's beyond the - // amount of coolant we have, see how much we need to adjust our request. - float total_coolant_request = 0.0f; - for(int n = 0; n < SYS_COUNT; n++) - { - if (!hasSystem(ESystem(n))) continue; - total_coolant_request += systems[n].coolant_request; - } - float coolant_request_factor = 1.0f; - if (total_coolant_request > max_coolant) - coolant_request_factor = max_coolant / total_coolant_request; - - for(int n = 0; n < SYS_COUNT; n++) - { - if (!hasSystem(ESystem(n))) continue; - - if (systems[n].power_request > systems[n].power_level) - { - systems[n].power_level += delta * systems[n].power_rate_per_second; - if (systems[n].power_level > systems[n].power_request) - systems[n].power_level = systems[n].power_request; - } - else if (systems[n].power_request < systems[n].power_level) - { - systems[n].power_level -= delta * systems[n].power_rate_per_second; - if (systems[n].power_level < systems[n].power_request) - systems[n].power_level = systems[n].power_request; - } - - float coolant_request = systems[n].coolant_request * coolant_request_factor; - if (coolant_request > systems[n].coolant_level) - { - systems[n].coolant_level += delta * systems[n].coolant_rate_per_second; - if (systems[n].coolant_level > coolant_request) - systems[n].coolant_level = coolant_request; - } - else if (coolant_request < systems[n].coolant_level) - { - systems[n].coolant_level -= delta * systems[n].coolant_rate_per_second; - if (systems[n].coolant_level < coolant_request) - systems[n].coolant_level = coolant_request; - } - - // Add heat to overpowered subsystems. - addHeat(ESystem(n), delta * systems[n].getHeatingDelta() * systems[n].heat_rate_per_second); - } - - // If reactor health is worse than -90% and overheating, it explodes, - // destroying the ship and damaging a 0.5U radius. - auto hull = entity.getComponent(); - if (hull && hull->allow_destruction && systems[SYS_Reactor].health < -0.9f && systems[SYS_Reactor].heat_level == 1.0f) - { - ExplosionEffect* e = new ExplosionEffect(); - e->setSize(1000.0f); - e->setPosition(getPosition()); - e->setRadarSignatureInfo(0.0, 0.4, 0.4); - - DamageInfo info(this, DT_Kinetic, getPosition()); - SpaceObject::damageArea(getPosition(), 500, 30, 60, info, 0.0); - - destroy(); - return; - } // If the ship has less than 10 energy, drop shields automatically. if (reactor && reactor->energy < 10.0f) @@ -730,41 +614,17 @@ void PlayerSpaceship::takeHullDamage(float damage_amount, DamageInfo& info) void PlayerSpaceship::setMaxCoolant(float coolant) { - max_coolant = std::max(coolant, 0.0f); -} - -void PlayerSpaceship::setSystemCoolantRequest(ESystem system, float request) -{ - request = std::max(0.0f, std::min(request, std::min((float) max_coolant_per_system, max_coolant))); - systems[system].coolant_request = request; + //TODO } -void PlayerSpaceship::addHeat(ESystem system, float amount) +void PlayerSpaceship::setSystemCoolantRequest(ShipSystem::Type system, float request) { - // Add heat to a subsystem if it's present. - if (!hasSystem(system)) return; - - systems[system].heat_level += amount; - - if (systems[system].heat_level > 1.0f) - { - float overheat = systems[system].heat_level - 1.0f; - systems[system].heat_level = 1.0f; - - if (gameGlobalInfo->use_system_damage) - { - // Heat damage is specified as damage per second while overheating. - // Calculate the amount of overheat back to a time, and use that to - // calculate the actual damage taken. - systems[system].health -= overheat / systems[system].heat_rate_per_second * damage_per_second_on_overheat; - - if (systems[system].health < -1.0f) - systems[system].health = -1.0f; - } - } - - if (systems[system].heat_level < 0.0f) - systems[system].heat_level = 0.0f; + auto coolant = entity.getComponent(); + if (!coolant) return; + request = std::clamp(request, 0.0f, std::min((float) coolant->max_coolant_per_system, coolant->max)); + auto sys = ShipSystem::get(entity, system); + if (sys) + sys->coolant_request = request; } void PlayerSpaceship::playSoundOnMainScreen(string sound_name) @@ -776,37 +636,6 @@ void PlayerSpaceship::playSoundOnMainScreen(string sound_name) broadcastServerCommand(packet); } -float PlayerSpaceship::getNetSystemEnergyUsage() -{ - // Get the net delta of energy draw for subsystems. - float net_power = 0.0; - - // Determine each subsystem's energy draw. - for(int n = 0; n < SYS_COUNT; n++) - { - - if (!hasSystem(ESystem(n))) continue; - - const auto& system = systems[n]; - // Factor the subsystem's health into energy generation. - auto power_user_factor = system.getPowerUserFactor(); - if (power_user_factor < 0) - { - float f = getSystemEffectiveness(ESystem(n)); - if (f > 1.0f) - f = (1.0f + f) / 2.0f; - net_power -= power_user_factor * f; - } - else - { - net_power -= power_user_factor * system.power_level; - } - } - - // Return the net subsystem energy draw. - return net_power; -} - int PlayerSpaceship::getRepairCrewCount() { // Count and return the number of repair crews on this ship. @@ -1131,7 +960,7 @@ bool PlayerSpaceship::getCanDock() return entity.hasComponent(); } -ESystem PlayerSpaceship::getBeamSystemTarget() { return SYS_None; /* TODO */ } +ShipSystem::Type PlayerSpaceship::getBeamSystemTarget() { return ShipSystem::Type::None; /* TODO */ } string PlayerSpaceship::getBeamSystemTargetName() { return ""; /* TODO */ } void PlayerSpaceship::onReceiveClientCommand(int32_t client_id, sp::io::DataBuffer& packet) @@ -1143,14 +972,18 @@ void PlayerSpaceship::onReceiveClientCommand(int32_t client_id, sp::io::DataBuff switch(command) { - case CMD_TARGET_ROTATION: - turnSpeed = 0; - packet >> target_rotation; - break; - case CMD_TURN_SPEED: - target_rotation = getRotation(); - packet >> turnSpeed; - break; + case CMD_TARGET_ROTATION:{ + float f; + packet >> f; + auto thrusters = entity.getComponent(); + if (thrusters) { thrusters->stop(); thrusters->target = f; } + }break; + case CMD_TURN_SPEED:{ + float f; + packet >> f; + auto thrusters = entity.getComponent(); + if (thrusters) { thrusters->stop(); thrusters->rotation_request = f; } + }break; case CMD_IMPULSE:{ auto engine = entity.getComponent(); if (engine) @@ -1269,20 +1102,20 @@ void PlayerSpaceship::onReceiveClientCommand(int32_t client_id, sp::io::DataBuff break; case CMD_SET_SYSTEM_POWER_REQUEST: { - ESystem system; + ShipSystem::Type system; float request; packet >> system >> request; - if (system < SYS_COUNT && request >= 0.0f && request <= 3.0f) - systems[system].power_request = request; + auto sys = ShipSystem::get(entity, system); + if (sys && request >= 0.0f && request <= 3.0f) + sys->power_request = request; } break; case CMD_SET_SYSTEM_COOLANT_REQUEST: { - ESystem system; + ShipSystem::Type system; float request; packet >> system >> request; - if (system < SYS_COUNT && request >= 0.0f && request <= 10.0f) - setSystemCoolantRequest(system, request); + setSystemCoolantRequest(system, request); } break; case CMD_DOCK: @@ -1439,11 +1272,11 @@ void PlayerSpaceship::onReceiveClientCommand(int32_t client_id, sp::io::DataBuff break; case CMD_SET_BEAM_SYSTEM_TARGET: { - ESystem system; + ShipSystem::Type system; packet >> system; auto beamweapons = entity.getComponent(); if (beamweapons) - beamweapons->system_target = (ESystem)std::clamp((int)system, 0, (int)(SYS_COUNT - 1)); + beamweapons->system_target = (ShipSystem::Type)std::clamp((int)system, 0, (int)(ShipSystem::COUNT - 1)); } break; case CMD_SET_SHIELD_FREQUENCY: @@ -1534,16 +1367,18 @@ void PlayerSpaceship::onReceiveClientCommand(int32_t client_id, sp::io::DataBuff { float request_amount; packet >> request_amount; - if (request_amount >= 0.0f && request_amount <= 1.0f) - combat_maneuver_boost_request = request_amount; + auto combat = entity.getComponent(); + if (combat) + combat->boost.request = request_amount; } break; case CMD_COMBAT_MANEUVER_STRAFE: { float request_amount; packet >> request_amount; - if (request_amount >= -1.0f && request_amount <= 1.0f) - combat_maneuver_strafe_request = request_amount; + auto combat = entity.getComponent(); + if (combat) + combat->strafe.request = request_amount; } break; case CMD_LAUNCH_PROBE: @@ -1597,7 +1432,7 @@ void PlayerSpaceship::onReceiveClientCommand(int32_t client_id, sp::io::DataBuff case CMD_HACKING_FINISHED: { int32_t id; - string target_system; + ShipSystem::Type target_system; packet >> id >> target_system; P obj = game_server->getObjectById(id); if (obj) @@ -1741,18 +1576,20 @@ void PlayerSpaceship::commandScan(P object) sendClientCommand(packet); } -void PlayerSpaceship::commandSetSystemPowerRequest(ESystem system, float power_request) +void PlayerSpaceship::commandSetSystemPowerRequest(ShipSystem::Type system, float power_request) { sp::io::DataBuffer packet; - systems[system].power_request = power_request; + auto sys = ShipSystem::get(entity, system); + if (sys) sys->power_request = power_request; packet << CMD_SET_SYSTEM_POWER_REQUEST << system << power_request; sendClientCommand(packet); } -void PlayerSpaceship::commandSetSystemCoolantRequest(ESystem system, float coolant_request) +void PlayerSpaceship::commandSetSystemCoolantRequest(ShipSystem::Type system, float coolant_request) { sp::io::DataBuffer packet; - systems[system].coolant_request = coolant_request; + auto sys = ShipSystem::get(entity, system); + if (sys) sys->coolant_request = coolant_request; packet << CMD_SET_SYSTEM_COOLANT_REQUEST << system << coolant_request; sendClientCommand(packet); } @@ -1829,7 +1666,7 @@ void PlayerSpaceship::commandSetBeamFrequency(int32_t frequency) sendClientCommand(packet); } -void PlayerSpaceship::commandSetBeamSystemTarget(ESystem system) +void PlayerSpaceship::commandSetBeamSystemTarget(ShipSystem::Type system) { sp::io::DataBuffer packet; packet << CMD_SET_BEAM_SYSTEM_TARGET << system; @@ -1887,7 +1724,9 @@ void PlayerSpaceship::commandConfirmDestructCode(int8_t index, uint32_t code) void PlayerSpaceship::commandCombatManeuverBoost(float amount) { - combat_maneuver_boost_request = amount; + auto combat = entity.getComponent(); + if (!combat) return; + combat->boost.request = amount; sp::io::DataBuffer packet; packet << CMD_COMBAT_MANEUVER_BOOST << amount; sendClientCommand(packet); @@ -1895,7 +1734,9 @@ void PlayerSpaceship::commandCombatManeuverBoost(float amount) void PlayerSpaceship::commandCombatManeuverStrafe(float amount) { - combat_maneuver_strafe_request = amount; + auto combat = entity.getComponent(); + if (!combat) return; + combat->strafe.request = amount; sp::io::DataBuffer packet; packet << CMD_COMBAT_MANEUVER_STRAFE << amount; sendClientCommand(packet); @@ -1930,7 +1771,7 @@ void PlayerSpaceship::commandSetAlertLevel(EAlertLevel level) sendClientCommand(packet); } -void PlayerSpaceship::commandHackingFinished(P target, string target_system) +void PlayerSpaceship::commandHackingFinished(P target, ShipSystem::Type target_system) { sp::io::DataBuffer packet; packet << CMD_HACKING_FINISHED; @@ -2031,12 +1872,13 @@ string PlayerSpaceship::getExportLine() result += ":setCanSelfDestruct(" + string(can_self_destruct, true) + ")"; if (can_launch_probe != ship_template->can_launch_probe) result += ":setCanLaunchProbe(" + string(can_launch_probe, true) + ")"; - if (auto_coolant_enabled) - result += ":setAutoCoolant(true)"; + //if (auto_coolant_enabled) + // result += ":setAutoCoolant(true)"; if (auto_repair_enabled) result += ":commandSetAutoRepair(true)"; // Update power factors, only for the systems where it changed. + /* for (unsigned int sys_index = 0; sys_index < SYS_COUNT; ++sys_index) { auto system = static_cast(sys_index); @@ -2067,6 +1909,7 @@ string PlayerSpaceship::getExportLine() } } } + */ if (std::fabs(getEnergyShieldUsePerSecond() - default_energy_shield_use_per_second) > std::numeric_limits::epsilon()) { diff --git a/src/spaceObjects/playerSpaceship.h b/src/spaceObjects/playerSpaceship.h index 18d6e28a6f..b148d16df3 100644 --- a/src/spaceObjects/playerSpaceship.h +++ b/src/spaceObjects/playerSpaceship.h @@ -36,9 +36,6 @@ class PlayerSpaceship : public SpaceShip public: // Power consumption and generation base rates constexpr static float default_energy_shield_use_per_second = 1.5f; - // Total coolant - constexpr static float max_coolant_per_system = 10.0f; - float max_coolant; // Overheat subsystem damage rate constexpr static float damage_per_second_on_overheat = 0.08f; // Base time it takes to perform an action @@ -92,7 +89,6 @@ class PlayerSpaceship : public SpaceShip float shield_calibration_delay; // Ship automation features, mostly for single-person ships like fighters bool auto_repair_enabled; - bool auto_coolant_enabled; // Whether shields are up (true) or down bool shields_active; // Password to join a ship. Default is empty. @@ -233,7 +229,7 @@ class PlayerSpaceship : public SpaceShip void addCustomMessageWithCallback(ECrewPosition position, string name, string caption, ScriptSimpleCallback callback); void removeCustom(string name); - ESystem getBeamSystemTarget(); + ShipSystem::Type getBeamSystemTarget(); string getBeamSystemTargetName(); // Client command functions virtual void onReceiveClientCommand(int32_t client_id, sp::io::DataBuffer& packet) override; @@ -253,8 +249,8 @@ class PlayerSpaceship : public SpaceShip void commandMainScreenSetting(EMainScreenSetting mainScreen); void commandMainScreenOverlay(EMainScreenOverlay mainScreen); void commandScan(P object); - void commandSetSystemPowerRequest(ESystem system, float power_level); - void commandSetSystemCoolantRequest(ESystem system, float coolant_level); + void commandSetSystemPowerRequest(ShipSystem::Type system, float power_level); + void commandSetSystemCoolantRequest(ShipSystem::Type system, float coolant_level); void commandDock(P station); void commandUndock(); void commandAbortDock(); @@ -265,7 +261,7 @@ class PlayerSpaceship : public SpaceShip void commandSendCommPlayer(string message); void commandSetAutoRepair(bool enabled); void commandSetBeamFrequency(int32_t frequency); - void commandSetBeamSystemTarget(ESystem system); + void commandSetBeamSystemTarget(ShipSystem::Type system); void commandSetShieldFrequency(int32_t frequency); void commandAddWaypoint(glm::vec2 position); void commandRemoveWaypoint(int32_t index); @@ -279,7 +275,7 @@ class PlayerSpaceship : public SpaceShip void commandScanDone(); void commandScanCancel(); void commandSetAlertLevel(EAlertLevel level); - void commandHackingFinished(P target, string target_system); + void commandHackingFinished(P target, ShipSystem::Type target_system); void commandCustomFunction(string name); virtual void onReceiveServerCommand(sp::io::DataBuffer& packet) override; @@ -289,10 +285,10 @@ class PlayerSpaceship : public SpaceShip // Ship status functions virtual void takeHullDamage(float damage_amount, DamageInfo& info) override; - void setSystemCoolantRequest(ESystem system, float request); + void setSystemCoolantRequest(ShipSystem::Type system, float request); void setMaxCoolant(float coolant); - float getMaxCoolant() { return max_coolant; } - void setAutoCoolant(bool active) { auto_coolant_enabled = active; } + float getMaxCoolant() { return 10.0f; } //TODO + void setAutoCoolant(bool active) {} //TODO int getRepairCrewCount(); void setRepairCrewCount(int amount); EAlertLevel getAlertLevel() { return alert_level; } @@ -305,13 +301,10 @@ class PlayerSpaceship : public SpaceShip // Ship update functions virtual void update(float delta) override; - virtual void addHeat(ESystem system, float amount) override; // Call on the server to play a sound on the main screen. void playSoundOnMainScreen(string sound_name); - float getNetSystemEnergyUsage(); - // Ship's log functions void addToShipLog(string message, glm::u8vec4 color); void addToShipLogBy(string message, P target); diff --git a/src/spaceObjects/spaceObject.cpp b/src/spaceObjects/spaceObject.cpp index 89e5e82993..c6cad47935 100644 --- a/src/spaceObjects/spaceObject.cpp +++ b/src/spaceObjects/spaceObject.cpp @@ -382,12 +382,12 @@ bool SpaceObject::canBeHackedBy(P other) return false; } -std::vector > SpaceObject::getHackingTargets() +std::vector > SpaceObject::getHackingTargets() { - return std::vector >(); + return std::vector >(); } -void SpaceObject::hackFinished(P source, string target) +void SpaceObject::hackFinished(P source, ShipSystem::Type target) { } @@ -729,7 +729,7 @@ template<> void convert::param(lua_State* L, int& idx, DamageInfo& d if (!lua_isstring(L, idx)) return; - convert::param(L, idx, di.system_target); + convert::param(L, idx, di.system_target); } template<> void convert::param(lua_State* L, int& idx, EScannedState& ss) diff --git a/src/spaceObjects/spaceObject.h b/src/spaceObjects/spaceObject.h index d9f361e1f5..8a335a2ccb 100644 --- a/src/spaceObjects/spaceObject.h +++ b/src/spaceObjects/spaceObject.h @@ -10,6 +10,7 @@ #include "graphics/renderTarget.h" #include "ecs/entity.h" #include "components/radar.h" +#include "components/shipsystem.h" #include @@ -27,14 +28,14 @@ class DamageInfo EDamageType type; glm::vec2 location{0, 0}; int frequency; - ESystem system_target; + ShipSystem::Type system_target; DamageInfo() - : instigator(), type(DT_Energy), location(0, 0), frequency(-1), system_target(SYS_None) + : instigator(), type(DT_Energy), location(0, 0), frequency(-1), system_target(ShipSystem::Type::None) {} DamageInfo(P instigator, EDamageType type, glm::vec2 location) - : instigator(instigator), type(type), location(location), frequency(-1), system_target(SYS_None) + : instigator(instigator), type(type), location(location), frequency(-1), system_target(ShipSystem::Type::None) {} }; @@ -180,8 +181,8 @@ class SpaceObject : public MultiplayerObject void setScannedByFaction(string faction_name, bool scanned); virtual void scannedBy(P other); virtual bool canBeHackedBy(P other); - virtual std::vector > getHackingTargets(); - virtual void hackFinished(P source, string target); + virtual std::vector > getHackingTargets(); + virtual void hackFinished(P source, ShipSystem::Type target); virtual void takeDamage(float damage_amount, DamageInfo info) {} virtual std::unordered_map getGMInfo() { return std::unordered_map(); } virtual string getExportLine() { return ""; } diff --git a/src/spaceObjects/spaceship.cpp b/src/spaceObjects/spaceship.cpp index 4a9a19d093..48a81a6809 100644 --- a/src/spaceObjects/spaceship.cpp +++ b/src/spaceObjects/spaceship.cpp @@ -19,6 +19,7 @@ #include "components/collision.h" #include "components/docking.h" #include "components/impulse.h" +#include "components/maneuveringthrusters.h" #include "components/warpdrive.h" #include "components/jumpdrive.h" #include "components/reactor.h" @@ -169,67 +170,14 @@ REGISTER_SCRIPT_SUBCLASS_NO_CREATE(SpaceShip, ShipTemplateBasedObject) REGISTER_SCRIPT_CLASS_FUNCTION(SpaceShip, setScanStateByFaction); } -std::array SpaceShip::default_system_power_factors{ - /*SYS_Reactor*/ -25.f, - /*SYS_BeamWeapons*/ 3.f, - /*SYS_MissileSystem*/ 1.f, - /*SYS_Maneuver*/ 2.f, - /*SYS_Impulse*/ 4.f, - /*SYS_Warp*/ 5.f, - /*SYS_JumpDrive*/ 5.f, - /*SYS_FrontShield*/ 5.f, - /*SYS_RearShield*/ 5.f, -}; - SpaceShip::SpaceShip(string multiplayerClassName, float multiplayer_significant_range) : ShipTemplateBasedObject(50, multiplayerClassName, multiplayer_significant_range) { - target_rotation = getRotation(); wormhole_alpha = 0.f; - turn_speed = 10.f; - combat_maneuver_charge = 1.f; - combat_maneuver_boost_request = 0.f; - combat_maneuver_boost_active = 0.f; - combat_maneuver_strafe_request = 0.f; - combat_maneuver_strafe_active = 0.f; - combat_maneuver_boost_speed = 0.0f; - combat_maneuver_strafe_speed = 0.0f; target_id = -1; - turnSpeed = 0.0f; - registerMemberReplication(&target_rotation, 1.5f); - registerMemberReplication(&turnSpeed, 0.1f); registerMemberReplication(&wormhole_alpha, 0.5f); registerMemberReplication(&target_id); - registerMemberReplication(&turn_speed); - registerMemberReplication(&combat_maneuver_charge, 0.5f); - registerMemberReplication(&combat_maneuver_boost_request); - registerMemberReplication(&combat_maneuver_boost_active, 0.2f); - registerMemberReplication(&combat_maneuver_strafe_request); - registerMemberReplication(&combat_maneuver_strafe_active, 0.2f); - registerMemberReplication(&combat_maneuver_boost_speed); - registerMemberReplication(&combat_maneuver_strafe_speed); - - for(unsigned int n=0; nimpulse_sound_file; } - turn_speed = ship_template->turn_speed; - combat_maneuver_boost_speed = ship_template->combat_maneuver_boost_speed; - combat_maneuver_strafe_speed = ship_template->combat_maneuver_strafe_speed; + if (ship_template->turn_speed) { + auto& thrusters = entity.getOrAddComponent(); + thrusters.speed = ship_template->turn_speed; + } + if (ship_template->combat_maneuver_boost_speed || ship_template->combat_maneuver_strafe_speed) { + auto& thrusters = entity.getOrAddComponent(); + thrusters.boost.speed = ship_template->combat_maneuver_boost_speed; + thrusters.strafe.speed = ship_template->combat_maneuver_strafe_speed; + } if (ship_template->warp_speed > 0.0f) { auto& warp = entity.getOrAddComponent(); @@ -349,9 +303,9 @@ void SpaceShip::updateDynamicRadarSignature() DynamicRadarSignatureInfo signature_delta; // For each ship system ... - for(int n = 0; n < SYS_COUNT; n++) + for(int n = 0; n < ShipSystem::COUNT; n++) { - ESystem ship_system = static_cast(n); + auto ship_system = static_cast(n); // ... increase the biological band based on system heat, offset by // coolant. @@ -364,7 +318,7 @@ void SpaceShip::updateDynamicRadarSignature() ); // ... adjust the electrical band if system power allocation is not 100%. - if (ship_system == SYS_JumpDrive) + if (ship_system == ShipSystem::Type::JumpDrive) { auto jump = entity.getComponent(); if (jump && jump->charge < jump->max_distance) { @@ -411,87 +365,9 @@ void SpaceShip::update(float delta) { ShipTemplateBasedObject::update(delta); - auto physics = entity.getComponent(); - - float rotationDiff; - if (fabs(turnSpeed) < 0.0005f) { - rotationDiff = angleDifference(getRotation(), target_rotation); - } else { - rotationDiff = turnSpeed; - } - - if (physics) { - if (rotationDiff > 1.0f) - physics->setAngularVelocity(turn_speed * getSystemEffectiveness(SYS_Maneuver)); - else if (rotationDiff < -1.0f) - physics->setAngularVelocity(-turn_speed * getSystemEffectiveness(SYS_Maneuver)); - else - physics->setAngularVelocity(rotationDiff * turn_speed * getSystemEffectiveness(SYS_Maneuver)); - } - - if (combat_maneuver_boost_active > combat_maneuver_boost_request) - { - combat_maneuver_boost_active -= delta; - if (combat_maneuver_boost_active < combat_maneuver_boost_request) - combat_maneuver_boost_active = combat_maneuver_boost_request; - } - if (combat_maneuver_boost_active < combat_maneuver_boost_request) - { - combat_maneuver_boost_active += delta; - if (combat_maneuver_boost_active > combat_maneuver_boost_request) - combat_maneuver_boost_active = combat_maneuver_boost_request; - } - if (combat_maneuver_strafe_active > combat_maneuver_strafe_request) - { - combat_maneuver_strafe_active -= delta; - if (combat_maneuver_strafe_active < combat_maneuver_strafe_request) - combat_maneuver_strafe_active = combat_maneuver_strafe_request; - } - if (combat_maneuver_strafe_active < combat_maneuver_strafe_request) - { - combat_maneuver_strafe_active += delta; - if (combat_maneuver_strafe_active > combat_maneuver_strafe_request) - combat_maneuver_strafe_active = combat_maneuver_strafe_request; - } - - // If the ship is making a combat maneuver ... - if (combat_maneuver_boost_active != 0.0f || combat_maneuver_strafe_active != 0.0f) - { - // ... consume its combat maneuver boost. - combat_maneuver_charge -= fabs(combat_maneuver_boost_active) * delta / combat_maneuver_boost_max_time; - combat_maneuver_charge -= fabs(combat_maneuver_strafe_active) * delta / combat_maneuver_strafe_max_time; - - // Use boost only if we have boost available. - if (combat_maneuver_charge <= 0.0f) - { - combat_maneuver_charge = 0.0f; - combat_maneuver_boost_request = 0.0f; - combat_maneuver_strafe_request = 0.0f; - }else if (physics) - { - auto forward = vec2FromAngle(getRotation()); - physics->setVelocity(physics->getVelocity() + forward * combat_maneuver_boost_speed * combat_maneuver_boost_active); - physics->setVelocity(physics->getVelocity() + vec2FromAngle(getRotation() + 90) * combat_maneuver_strafe_speed * combat_maneuver_strafe_active); - } - // If the ship isn't making a combat maneuver, recharge its boost. - }else if (combat_maneuver_charge < 1.0f) - { - combat_maneuver_charge += (delta / combat_maneuver_charge_time) * (getSystemEffectiveness(SYS_Maneuver) + getSystemEffectiveness(SYS_Impulse)) / 2.0f; - if (combat_maneuver_charge > 1.0f) - combat_maneuver_charge = 1.0f; - } - - // Add heat to systems consuming combat maneuver boost. - addHeat(SYS_Impulse, fabs(combat_maneuver_boost_active) * delta * heat_per_combat_maneuver_boost); - addHeat(SYS_Maneuver, fabs(combat_maneuver_strafe_active) * delta * heat_per_combat_maneuver_strafe); - - for(int n=0; n(); + if (thrusters) model_info.engine_scale = std::abs(getAngularVelocity() / thrusters->speed); auto impulse = entity.getComponent(); if (impulse) model_info.engine_scale = std::max(model_info.engine_scale, std::abs(impulse->actual)); @@ -644,33 +520,24 @@ bool SpaceShip::canBeHackedBy(P other) return (!(this->isFriendly(other)) && this->isFriendOrFoeIdentifiedBy(other)) ; } -std::vector> SpaceShip::getHackingTargets() +std::vector> SpaceShip::getHackingTargets() { - std::vector> results; - for(unsigned int n=0; n> results; + for(unsigned int n=0; nhacked_level); } return results; } -void SpaceShip::hackFinished(P source, string target) +void SpaceShip::hackFinished(P source, ShipSystem::Type target) { - for(unsigned int n=0; nhacked_level = std::min(1.0f, sys->hacked_level + 0.5f); } float SpaceShip::getShieldDamageFactor(DamageInfo& info, int shield_index) @@ -714,24 +581,27 @@ void SpaceShip::takeHullDamage(float damage_amount, DamageInfo& info) auto hull = entity.getComponent(); if (gameGlobalInfo->use_system_damage && hull) { - if (info.system_target != SYS_None) + if (auto sys = ShipSystem::get(entity, info.system_target)) { //Target specific system float system_damage = (damage_amount / hull->max) * 2.0f; if (info.type == DT_Energy) system_damage *= 3.0f; //Beam weapons do more system damage, as they penetrate the hull easier. - systems[info.system_target].health -= system_damage; - if (systems[info.system_target].health < -1.0f) - systems[info.system_target].health = -1.0f; + sys->health -= system_damage; + if (sys->health < -1.0f) + sys->health = -1.0f; for(int n=0; n<2; n++) { - ESystem random_system = ESystem(irandom(0, SYS_COUNT - 1)); + auto random_system = ShipSystem::Type(irandom(0, ShipSystem::COUNT - 1)); //Damage the system compared to the amount of hull damage you would do. If we have less hull strength you get more system damage. float system_damage = (damage_amount / hull->max) * 1.0f; - systems[random_system].health -= system_damage; - if (systems[random_system].health < -1.0f) - systems[random_system].health = -1.0f; + sys = ShipSystem::get(entity, random_system); + if (sys) { + sys->health -= system_damage; + if (sys->health < -1.0f) + sys->health = -1.0f; + } } if (info.type == DT_Energy) @@ -739,14 +609,18 @@ void SpaceShip::takeHullDamage(float damage_amount, DamageInfo& info) else damage_amount *= 0.5f; }else{ - ESystem random_system = ESystem(irandom(0, SYS_COUNT - 1)); //Damage the system compared to the amount of hull damage you would do. If we have less hull strength you get more system damage. float system_damage = (damage_amount / hull->max) * 3.0f; if (info.type == DT_Energy) system_damage *= 2.5f; //Beam weapons do more system damage, as they penetrate the hull easier. - systems[random_system].health -= system_damage; - if (systems[random_system].health < -1.0f) - systems[random_system].health = -1.0f; + + auto random_system = ShipSystem::Type(irandom(0, ShipSystem::COUNT - 1)); + sys = ShipSystem::get(entity, random_system); + if (sys) { + sys->health -= system_damage; + if (sys->health < -1.0f) + sys->health = -1.0f; + } } } @@ -780,65 +654,9 @@ void SpaceShip::destroyedByDamage(DamageInfo& info) } } -bool SpaceShip::hasSystem(ESystem system) -{ - switch(system) - { - case SYS_None: - case SYS_COUNT: - return false; - case SYS_Warp: - return entity.hasComponent(); - case SYS_JumpDrive: - return entity.hasComponent(); - case SYS_MissileSystem: - return entity.hasComponent(); - case SYS_FrontShield: - return entity.hasComponent(); - case SYS_RearShield: - { - auto shields = entity.getComponent(); - if (shields && shields->count > 1) - return true; - return false; - } - case SYS_Reactor: - return entity.hasComponent(); - case SYS_BeamWeapons: - return entity.hasComponent(); - case SYS_Maneuver: - return turn_speed > 0.0f; - case SYS_Impulse: - return entity.hasComponent(); - } - return true; -} - -float SpaceShip::getSystemEffectiveness(ESystem system) +bool SpaceShip::hasSystem(ShipSystem::Type system) { - float power = systems[system].power_level; - - // Substract the hacking from the power, making double hacked systems run at 25% efficiency. - power = std::max(0.0f, power - systems[system].hacked_level * 0.75f); - - // Degrade all systems except the reactor once energy level drops below 10. - if (system != SYS_Reactor) - { - auto reactor = entity.getComponent(); - if (reactor) { - if (reactor->energy < 10.0f && reactor->energy > 0.0f && power > 0.0f) - power = std::min(power * reactor->energy / 10.0f, power); - else if (reactor->energy <= 0.0f || power <= 0.0f) - power = 0.0f; - } - } - - // Degrade damaged systems. - if (gameGlobalInfo && gameGlobalInfo->use_system_damage) - return std::max(0.0f, power * systems[system].health); - - // If a system cannot be damaged, excessive heat degrades it. - return std::max(0.0f, power * (1.0f - systems[system].heat_level)); + return ShipSystem::get(entity, system) != nullptr; } float SpaceShip::getBeamWeaponArc(int index) { return 0.0f; /* TODO */ } @@ -1053,8 +871,8 @@ string SpaceShip::getScriptExportModificationsOnTemplate() // ret += ":setImpulseMaxSpeed(" + string(impulse_max_speed, 1) + ")"; //if (impulse_max_reverse_speed != ship_template->impulse_reverse_speed) // ret += ":setImpulseMaxReverseSpeed(" + string(impulse_max_reverse_speed, 1) + ")"; - if (turn_speed != ship_template->turn_speed) - ret += ":setRotationMaxSpeed(" + string(turn_speed, 1) + ")"; + //if (turn_speed != ship_template->turn_speed) + // ret += ":setRotationMaxSpeed(" + string(turn_speed, 1) + ")"; //if (has_jump_drive != ship_template->has_jump_drive) // ret += ":setJumpDrive(" + string(has_jump_drive ? "true" : "false") + ")"; //if (jump_drive_min_distance != ship_template->jump_drive_min_distance diff --git a/src/spaceObjects/spaceship.h b/src/spaceObjects/spaceship.h index 4f1691c03a..eb08f2563e 100644 --- a/src/spaceObjects/spaceship.h +++ b/src/spaceObjects/spaceship.h @@ -38,80 +38,10 @@ struct Speeds template<> int convert::returnType(lua_State* L, const Speeds &speeds); -class ShipSystemLegacy -{ -public: - static constexpr float power_factor_rate = 0.08f; - static constexpr float default_heat_rate_per_second = 0.05f; - static constexpr float default_power_rate_per_second = 0.3f; - static constexpr float default_coolant_rate_per_second = 1.2f; - float health; //1.0-0.0, where 0.0 is fully broken. - float health_max; //1.0-0.0, where 0.0 is fully broken. - float power_level; //0.0-3.0, default 1.0 - float power_request; - float heat_level; //0.0-1.0, system will damage at 1.0 - float coolant_level; //0.0-10.0 - float coolant_request; - float hacked_level; //0.0-1.0 - float power_factor; - float coolant_rate_per_second{}; - float heat_rate_per_second{}; - float power_rate_per_second{}; - - float getHeatingDelta() const - { - return powf(1.7f, power_level - 1.0f) - (1.01f + coolant_level * 0.1f); - } - - float getPowerUserFactor() const - { - return power_factor * power_factor_rate; - } -}; - class SpaceShip : public ShipTemplateBasedObject { public: constexpr static int max_frequency = 20; - constexpr static float combat_maneuver_charge_time = 20.0f; /*< Amount of time it takes to fully charge the combat maneuver system */ - constexpr static float combat_maneuver_boost_max_time = 3.0f; /*< Amount of time we can boost with a fully charged combat maneuver system */ - constexpr static float combat_maneuver_strafe_max_time = 3.0f; /*< Amount of time we can strafe with a fully charged combat maneuver system */ - constexpr static float heat_per_combat_maneuver_boost = 0.2f; - constexpr static float heat_per_combat_maneuver_strafe = 0.2f; - constexpr static float unhack_time = 180.0f; //It takes this amount of time to go from 100% hacked to 0% hacked for systems. - - ShipSystemLegacy systems[SYS_COUNT]; - static std::array default_system_power_factors; - /*! - *[input] Ship will try to aim to this rotation. (degrees) - */ - float target_rotation; - - /*! - *[input] Ship will rotate in this velocity. ([-1,1], overrides target_rotation) - */ - float turnSpeed; - - /*! - * [config] Speed of rotation, in deg/second - */ - float turn_speed; - - /*! - * [output] How much charge there is in the combat maneuvering system (0.0-1.0) - */ - float combat_maneuver_charge; - /*! - * [input] How much boost we want at this moment (0.0-1.0) - */ - float combat_maneuver_boost_request; - float combat_maneuver_boost_active; - - float combat_maneuver_strafe_request; - float combat_maneuver_strafe_active; - - float combat_maneuver_boost_speed; /*< [config] Speed to indicate how fast we will fly forwards with a full boost */ - float combat_maneuver_strafe_speed; /*< [config] Speed to indicate how fast we will fly sideways with a full strafe */ float wormhole_alpha; //Used for displaying the Warp-postprocessor @@ -169,9 +99,6 @@ class SpaceShip : public ShipTemplateBasedObject /// Function to use energy. Only player ships currently model energy use. bool useEnergy(float amount); - /// Dummy virtual function to add heat on a system. The player ship class has an actual implementation of this as only player ships model heat right now. - virtual void addHeat(ESystem system, float amount) {} - virtual bool canBeScannedBy(P other) override { return getScannedStateFor(other) != SS_FullScan; } virtual int scanningComplexity(P other) override; virtual int scanningChannelDepth(P other) override; @@ -187,20 +114,13 @@ class SpaceShip : public ShipTemplateBasedObject bool isFullyScannedByFaction(int faction_id); virtual bool canBeHackedBy(P other) override; - virtual std::vector > getHackingTargets() override; - virtual void hackFinished(P source, string target) override; + virtual std::vector > getHackingTargets() override; + virtual void hackFinished(P source, ShipSystem::Type target) override; /*! * Check if ship has certain system */ - bool hasSystem(ESystem system); - - /*! - * Check effectiveness of system. - * If system has more / less power or is damages, this can influence the effectiveness. - * \return float 0. to 1. - */ - float getSystemEffectiveness(ESystem system); + bool hasSystem(ShipSystem::Type system); virtual void applyTemplateValues() override; @@ -219,35 +139,35 @@ class SpaceShip : public ShipTemplateBasedObject void setMaxEnergy(float amount); float getEnergy(); void setEnergy(float amount); - float getSystemHackedLevel(ESystem system) { if (system >= SYS_COUNT) return 0.0; if (system <= SYS_None) return 0.0; return systems[system].hacked_level; } - void setSystemHackedLevel(ESystem system, float hacked_level) { if (system >= SYS_COUNT) return; if (system <= SYS_None) return; systems[system].hacked_level = std::min(1.0f, std::max(0.0f, hacked_level)); } - float getSystemHealth(ESystem system) { if (system >= SYS_COUNT) return 0.0; if (system <= SYS_None) return 0.0; return systems[system].health; } - void setSystemHealth(ESystem system, float health) { if (system >= SYS_COUNT) return; if (system <= SYS_None) return; systems[system].health = std::min(1.0f, std::max(-1.0f, health)); } - float getSystemHealthMax(ESystem system) { if (system >= SYS_COUNT) return 0.0; if (system <= SYS_None) return 0.0; return systems[system].health_max; } - void setSystemHealthMax(ESystem system, float health_max) { if (system >= SYS_COUNT) return; if (system <= SYS_None) return; systems[system].health_max = std::min(1.0f, std::max(-1.0f, health_max)); } - float getSystemHeat(ESystem system) { if (system >= SYS_COUNT) return 0.0; if (system <= SYS_None) return 0.0; return systems[system].heat_level; } - void setSystemHeat(ESystem system, float heat) { if (system >= SYS_COUNT) return; if (system <= SYS_None) return; systems[system].heat_level = std::min(1.0f, std::max(0.0f, heat)); } - float getSystemHeatRate(ESystem system) const { if (system >= SYS_COUNT) return 0.f; if (system <= SYS_None) return 0.f; return systems[system].heat_rate_per_second; } - void setSystemHeatRate(ESystem system, float rate) { if (system >= SYS_COUNT) return; if (system <= SYS_None) return; systems[system].heat_rate_per_second = rate; } - - float getSystemPower(ESystem system) { if (system >= SYS_COUNT) return 0.0; if (system <= SYS_None) return 0.0; return systems[system].power_level; } - void setSystemPower(ESystem system, float power) { if (system >= SYS_COUNT) return; if (system <= SYS_None) return; systems[system].power_level = std::min(3.0f, std::max(0.0f, power)); } - float getSystemPowerRate(ESystem system) const { if (system >= SYS_COUNT) return 0.f; if (system <= SYS_None) return 0.f; return systems[system].power_rate_per_second; } - void setSystemPowerRate(ESystem system, float rate) { if (system >= SYS_COUNT) return; if (system <= SYS_None) return; systems[system].power_rate_per_second = rate; } - float getSystemPowerUserFactor(ESystem system) { if (system >= SYS_COUNT) return 0.f; if (system <= SYS_None) return 0.f; return systems[system].getPowerUserFactor(); } - float getSystemPowerFactor(ESystem system) { if (system >= SYS_COUNT) return 0.f; if (system <= SYS_None) return 0.f; return systems[system].power_factor; } - void setSystemPowerFactor(ESystem system, float factor) { if (system >= SYS_COUNT) return; if (system <= SYS_None) return; systems[system].power_factor = factor; } - float getSystemCoolant(ESystem system) { if (system >= SYS_COUNT) return 0.0; if (system <= SYS_None) return 0.0; return systems[system].coolant_level; } - void setSystemCoolant(ESystem system, float coolant) { if (system >= SYS_COUNT) return; if (system <= SYS_None) return; systems[system].coolant_level = std::min(1.0f, std::max(0.0f, coolant)); } + float getSystemHackedLevel(ShipSystem::Type system) { return 0.0f; } //TODO + void setSystemHackedLevel(ShipSystem::Type system, float hacked_level) {} //TODO + float getSystemHealth(ShipSystem::Type system) { return 0.0f; } //TODO + void setSystemHealth(ShipSystem::Type system, float health) {} //TODO + float getSystemHealthMax(ShipSystem::Type system) { return 0.0f; } //TODO + void setSystemHealthMax(ShipSystem::Type system, float health_max) {} //TODO + float getSystemHeat(ShipSystem::Type system) { return 0.0f; } //TODO + void setSystemHeat(ShipSystem::Type system, float heat) {} //TODO + float getSystemHeatRate(ShipSystem::Type system) const { return 0.0f; } //TODO + void setSystemHeatRate(ShipSystem::Type system, float rate) {} //TODO + + float getSystemPower(ShipSystem::Type system) { return 0.0f; } //TODO + void setSystemPower(ShipSystem::Type system, float power) {} //TODO + float getSystemPowerRate(ShipSystem::Type system) const { return 0.0f; } //TODO + void setSystemPowerRate(ShipSystem::Type system, float rate) {} //TODO + float getSystemPowerUserFactor(ShipSystem::Type system) { return 0.0f; } //TODO + float getSystemPowerFactor(ShipSystem::Type system) { return 0.0f; } //TODO + void setSystemPowerFactor(ShipSystem::Type system, float factor) {} //TODO + float getSystemCoolant(ShipSystem::Type system) { return 0.0f; } //TODO + void setSystemCoolant(ShipSystem::Type system, float coolant) {} //TODO Speeds getImpulseMaxSpeed(); void setImpulseMaxSpeed(float forward_speed, std::optional reverse_speed); - float getSystemCoolantRate(ESystem system) const { if (system >= SYS_COUNT) return 0.f; if (system <= SYS_None) return 0.f; return systems[system].coolant_rate_per_second; } - void setSystemCoolantRate(ESystem system, float rate) { if (system >= SYS_COUNT) return; if (system <= SYS_None) return; systems[system].coolant_rate_per_second = rate; } - float getRotationMaxSpeed() { return turn_speed; } - void setRotationMaxSpeed(float speed) { turn_speed = speed; } + float getSystemCoolantRate(ShipSystem::Type system) const { return 0.0f; } //TODO + void setSystemCoolantRate(ShipSystem::Type system, float rate) {} //TODO + float getRotationMaxSpeed() { return 0.0f; } //TODO + void setRotationMaxSpeed(float speed) { } //TODO Speeds getAcceleration(); void setAcceleration(float acceleration, std::optional reverse_acceleration); - void setCombatManeuver(float boost, float strafe) { combat_maneuver_boost_speed = boost; combat_maneuver_strafe_speed = strafe; } + void setCombatManeuver(float boost, float strafe) { } //TODO bool hasJumpDrive() { return false; } //TODO void setJumpDrive(bool has_jump) {} //TODO void setJumpDriveRange(float min, float max) {} //TODO diff --git a/src/systems/coolantsystem.cpp b/src/systems/coolantsystem.cpp new file mode 100644 index 0000000000..271a8e905f --- /dev/null +++ b/src/systems/coolantsystem.cpp @@ -0,0 +1,57 @@ +#include "coolantsystem.h" +#include "ecs/query.h" +#include "components/coolant.h" +#include "components/shipsystem.h" + + +void CoolantSystem::update(float delta) +{ + for(auto[entity, coolant] : sp::ecs::Query()) { + // Automate cooling if auto_coolant_enabled is true. Distributes coolant to + // subsystems proportionally to their share of the total generated heat. + if (coolant.auto_levels) { + float total_heat = 0.0f; + for(int n = 0; n < ShipSystem::COUNT; n++) { + auto sys = ShipSystem::get(entity, ShipSystem::Type(n)); + if (!sys) continue; + total_heat += sys->heat_level; + } + if (total_heat > 0.0f) { + for(int n = 0; n < ShipSystem::COUNT; n++) { + auto sys = ShipSystem::get(entity, ShipSystem::Type(n)); + if (!sys) continue; + sys->coolant_request = coolant.max * sys->heat_level / total_heat; + } + } + } + + // Check how much coolant we have requested in total, and if that's beyond the + // amount of coolant we have, see how much we need to adjust our request. + float total_coolant_request = 0.0f; + for(int n = 0; n < ShipSystem::COUNT; n++) { + auto sys = ShipSystem::get(entity, ShipSystem::Type(n)); + if (sys) total_coolant_request += sys->coolant_request; + } + float coolant_request_factor = 1.0f; + if (total_coolant_request > coolant.max) + coolant_request_factor = coolant.max / total_coolant_request; + + for(int n = 0; n < ShipSystem::COUNT; n++) { + auto sys = ShipSystem::get(entity, ShipSystem::Type(n)); + if (!sys) continue; + + float coolant_request = sys->coolant_request * coolant_request_factor; + if (coolant_request > sys->coolant_level) { + sys->coolant_level += delta * sys->coolant_change_rate_per_second; + if (sys->coolant_level > coolant_request) + sys->coolant_level = coolant_request; + } + else if (coolant_request < sys->coolant_level) + { + sys->coolant_level -= delta * sys->coolant_change_rate_per_second; + if (sys->coolant_level < coolant_request) + sys->coolant_level = coolant_request; + } + } + } +} \ No newline at end of file diff --git a/src/systems/coolantsystem.h b/src/systems/coolantsystem.h new file mode 100644 index 0000000000..239792f85a --- /dev/null +++ b/src/systems/coolantsystem.h @@ -0,0 +1,11 @@ +#pragma once + +#include "ecs/system.h" +#include "systems/collision.h" + + +class CoolantSystem : public sp::ecs::System +{ +public: + void update(float delta) override; +}; diff --git a/src/systems/energysystem.cpp b/src/systems/energysystem.cpp new file mode 100644 index 0000000000..bc8c9fb12d --- /dev/null +++ b/src/systems/energysystem.cpp @@ -0,0 +1,62 @@ +#include "energysystem.h" +#include "ecs/query.h" +#include "components/coolant.h" +#include "components/reactor.h" +#include "components/hull.h" +#include "spaceObjects/spaceObject.h" +#include "spaceObjects/explosionEffect.h" + + +void EnergySystem::update(float delta) +{ + for(auto[entity, reactor] : sp::ecs::Query()) { + // Consume power based on subsystem requests and state. + float net_power = 0.0; + // Determine each subsystem's energy draw. + for(int n = 0; n < ShipSystem::COUNT; n++) + { + const auto sys = ShipSystem::get(entity, ShipSystem::Type(n)); + if (!sys) continue; + // Factor the subsystem's health into energy generation. + auto power_user_factor = sys->power_factor * sys->power_factor_rate; + + if (power_user_factor < 0) + { + float f = sys->getSystemEffectiveness(); + if (f > 1.0f) + f = (1.0f + f) / 2.0f; + net_power -= power_user_factor * f; + } + else + { + net_power -= power_user_factor * sys->power_level; + } + } + + reactor.energy += delta * net_power; + // Cap energy at the max_energy_level. + reactor.energy = std::clamp(reactor.energy, 0.0f, reactor.max_energy); + + // If reactor health is worse than -90% and overheating, it explodes, + // destroying the ship and damaging a 0.5U radius. + if (reactor.health < -0.9f && reactor.heat_level == 1.0f) + { + auto hull = entity.getComponent(); + if (hull && hull->allow_destruction) { + auto obj_ptr = entity.getComponent(); + if (obj_ptr) { + auto obj = *obj_ptr; + auto e = new ExplosionEffect(); + e->setSize(1000.0f); + e->setPosition(obj->getPosition()); + e->setRadarSignatureInfo(0.0, 0.4, 0.4); + + DamageInfo info(obj, DT_Kinetic, obj->getPosition()); + SpaceObject::damageArea(obj->getPosition(), 500, 30, 60, info, 0.0); + + obj->destroy(); + } + } + } + } +} \ No newline at end of file diff --git a/src/systems/energysystem.h b/src/systems/energysystem.h new file mode 100644 index 0000000000..cff678d930 --- /dev/null +++ b/src/systems/energysystem.h @@ -0,0 +1,11 @@ +#pragma once + +#include "ecs/system.h" +#include "systems/collision.h" + + +class EnergySystem : public sp::ecs::System +{ +public: + void update(float delta) override; +}; diff --git a/src/systems/impulse.cpp b/src/systems/impulse.cpp index 522f22ec4d..5cc18d10fc 100644 --- a/src/systems/impulse.cpp +++ b/src/systems/impulse.cpp @@ -48,6 +48,6 @@ void ImpulseSystem::update(float delta) // Determine forward direction and velocity. auto forward = vec2FromAngle(ship->getRotation()); - physics.setVelocity(forward * (impulse.actual * cap_speed * ship->getSystemEffectiveness(SYS_Impulse))); + physics.setVelocity(forward * (impulse.actual * cap_speed * impulse.getSystemEffectiveness())); } } diff --git a/src/systems/shipsystemssystem.cpp b/src/systems/shipsystemssystem.cpp new file mode 100644 index 0000000000..5b3a6bafd9 --- /dev/null +++ b/src/systems/shipsystemssystem.cpp @@ -0,0 +1,57 @@ +#include "shipsystemssystem.h" +#include "components/reactor.h" +#include "components/beamweapon.h" +#include "components/missiletubes.h" +#include "components/maneuveringthrusters.h" +#include "components/jumpdrive.h" +#include "components/warpdrive.h" +#include "components/impulse.h" +#include "components/shields.h" + + +void ShipSystemsSystem::update(float delta) +{ + for(auto [entity, system] : sp::ecs::Query()) + updateSystem(system, delta); + for(auto [entity, system] : sp::ecs::Query()) + updateSystem(system, delta); + for(auto [entity, system] : sp::ecs::Query()) + updateSystem(system, delta); + for(auto [entity, system] : sp::ecs::Query()) + updateSystem(system, delta); + for(auto [entity, system] : sp::ecs::Query()) + updateSystem(system, delta); + for(auto [entity, system] : sp::ecs::Query()) + updateSystem(system, delta); + for(auto [entity, system] : sp::ecs::Query()) + updateSystem(system, delta); + for(auto [entity, system] : sp::ecs::Query()) { + updateSystem(system.front_system, delta); + if (system.count > 1) + updateSystem(system.rear_system, delta); + } +} + +void ShipSystemsSystem::updateSystem(ShipSystem& system, float delta) +{ + system.health = std::min(1.0f, system.health + delta * system.auto_repair_per_second); + + system.hacked_level = std::max(0.0f, system.hacked_level - delta / unhack_time); + system.health = std::min(system.health, system.health_max); + + // Add heat to overpowered subsystems. + system.addHeat(delta * system.getHeatingDelta() * system.heat_add_rate_per_second); + + if (system.power_request > system.power_level) + { + system.power_level += delta * system.power_change_rate_per_second; + if (system.power_level > system.power_request) + system.power_level = system.power_request; + } + else if (system.power_request < system.power_level) + { + system.power_level -= delta * system.power_change_rate_per_second; + if (system.power_level < system.power_request) + system.power_level = system.power_request; + } +} diff --git a/src/systems/shipsystemssystem.h b/src/systems/shipsystemssystem.h new file mode 100644 index 0000000000..09f6a5c65b --- /dev/null +++ b/src/systems/shipsystemssystem.h @@ -0,0 +1,16 @@ +#pragma once + +#include "ecs/system.h" +#include "ecs/query.h" +#include "components/shipsystem.h" + + +class ShipSystemsSystem : public sp::ecs::System +{ +public: + constexpr static float unhack_time = 180.0f; //It takes this amount of time to go from 100% hacked to 0% hacked for systems. + + void update(float delta) override; +private: + void updateSystem(ShipSystem& system, float delta); +}; From 9327ee1d0bd02bac27fcefc060217c2d23da2253 Mon Sep 17 00:00:00 2001 From: Daid Date: Thu, 15 Dec 2022 16:52:48 +0100 Subject: [PATCH 021/320] Small bugfixes, it actually runs, surprising as I did not test much yet. --- src/ai/ai.cpp | 8 ++------ src/spaceObjects/playerSpaceship.cpp | 4 ++++ src/systems/maneuvering.cpp | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp index 86d437829a..5f64c1bf48 100644 --- a/src/ai/ai.cpp +++ b/src/ai/ai.cpp @@ -595,12 +595,8 @@ void ShipAI::flyTowards(glm::vec2 target, float keep_distance) float rotation_diff = fabs(angleDifference(target_rotation, owner->getRotation())); auto warp = owner->entity.getComponent(); - if (warp && rotation_diff < 30.0f && distance > 2000.0f) - { - warp->request = 1.0; - }else{ - warp->request = 0.0; - } + if (warp) + warp->request = (rotation_diff < 30.0f && distance > 2000.0f) ? 1.0f : 0.0f; auto jump = owner->entity.getComponent(); if (distance > 10000 && jump && jump->delay <= 0.0f && jump->charge >= jump->max_distance) { diff --git a/src/spaceObjects/playerSpaceship.cpp b/src/spaceObjects/playerSpaceship.cpp index 5c9dded289..313fe9c5a7 100644 --- a/src/spaceObjects/playerSpaceship.cpp +++ b/src/spaceObjects/playerSpaceship.cpp @@ -587,6 +587,10 @@ void PlayerSpaceship::applyTemplateValues() // template. setRepairCrewCount(ship_template->repair_crew_count); + if (entity) { + entity.getOrAddComponent(); + } + // Set the ship's capabilities. can_scan = ship_template->can_scan; can_hack = ship_template->can_hack; diff --git a/src/systems/maneuvering.cpp b/src/systems/maneuvering.cpp index 4d0bfb7e41..3aecee9d4b 100644 --- a/src/systems/maneuvering.cpp +++ b/src/systems/maneuvering.cpp @@ -12,8 +12,8 @@ void ManeuveringSystem::update(float delta) float rotationDiff = 0.0f; if (thrusters.rotation_request != std::numeric_limits::min()) rotationDiff = thrusters.rotation_request; - if (thrusters.rotation_request) - rotationDiff = angleDifference(transform.getRotation(), thrusters.rotation_request); + if (thrusters.target != std::numeric_limits::min()) + rotationDiff = angleDifference(transform.getRotation(), thrusters.target); if (rotationDiff > 1.0f) physics.setAngularVelocity(thrusters.speed * thrusters.getSystemEffectiveness()); From 8732cea3ebb77c85211022cb890acea29d57302c Mon Sep 17 00:00:00 2001 From: Daid Date: Fri, 16 Dec 2022 11:54:31 +0100 Subject: [PATCH 022/320] Move some shield related variables to the shield component --- src/components/reactor.h | 2 +- src/components/shields.h | 6 ++ src/hardware/hardwareController.cpp | 2 +- src/screenComponents/shieldFreqencySelect.cpp | 6 +- src/screenComponents/shieldsEnableButton.cpp | 21 ++++--- src/screens/gm/tweak.cpp | 4 +- src/spaceObjects/playerSpaceship.cpp | 63 +++++-------------- src/spaceObjects/playerSpaceship.h | 22 ++----- src/spaceObjects/spaceship.cpp | 2 +- src/systems/beamweapon.cpp | 2 +- src/systems/docking.cpp | 2 +- src/systems/energysystem.cpp | 3 +- src/systems/shieldsystem.cpp | 14 ++++- src/systems/warpsystem.cpp | 12 ++-- 14 files changed, 73 insertions(+), 88 deletions(-) diff --git a/src/components/reactor.h b/src/components/reactor.h index 4d607ea08d..b6b892a3ef 100644 --- a/src/components/reactor.h +++ b/src/components/reactor.h @@ -11,5 +11,5 @@ class Reactor : public ShipSystem { // Runtime float energy = 1000.0f; - bool use_energy(float amount) { if (amount > energy) return false; energy -= amount; return true; } + bool useEnergy(float amount) { if (amount > energy) return false; energy -= amount; return true; } }; \ No newline at end of file diff --git a/src/components/shields.h b/src/components/shields.h index eb335378a3..fb81647191 100644 --- a/src/components/shields.h +++ b/src/components/shields.h @@ -9,8 +9,14 @@ class Shields { static constexpr size_t max_count = 8; bool active = true; + + // Time in seconds it takes to recalibrate shields + float calibration_time = 25.0f; + float calibration_delay = 0.0f; int frequency = -1; // Current frequency of the shield. -1 indicates that these shields have no frequency. + float energy_use_per_second = 1.5f; + int count = 0; struct Shield { float level = 0.0f; diff --git a/src/hardware/hardwareController.cpp b/src/hardware/hardwareController.cpp index f98424507e..ee8fadc4b3 100644 --- a/src/hardware/hardwareController.cpp +++ b/src/hardware/hardwareController.cpp @@ -370,7 +370,7 @@ bool HardwareController::getVariableValue(string variable_name, float& value) SHIP_VARIABLE("Shield6", ship->getShieldPercentage(6)); SHIP_VARIABLE("Shield7", ship->getShieldPercentage(7)); //SHIP_VARIABLE("Energy", ship->energy_level * 100 / ship->max_energy_level); - SHIP_VARIABLE("ShieldsUp", ship->shields_active ? 1.0f : 0.0f); + //SHIP_VARIABLE("ShieldsUp", ship->shields_active ? 1.0f : 0.0f); //SHIP_VARIABLE("Impulse", ship->current_impulse * ship->getSystemEffectiveness(SYS_Impulse)); //SHIP_VARIABLE("Warp", ship->current_warp * ship->getSystemEffectiveness(SYS_Warp)); //SHIP_VARIABLE("Docking", ship->docking_state == DS_Docking ? 1.0f : 0.0f); diff --git a/src/screenComponents/shieldFreqencySelect.cpp b/src/screenComponents/shieldFreqencySelect.cpp index d24fdd9a07..276c12b81a 100644 --- a/src/screenComponents/shieldFreqencySelect.cpp +++ b/src/screenComponents/shieldFreqencySelect.cpp @@ -1,6 +1,7 @@ #include #include "shieldFreqencySelect.h" #include "playerInfo.h" +#include "components/shields.h" #include "spaceObjects/playerSpaceship.h" #include "screenComponents/shieldsEnableButton.h" @@ -36,8 +37,9 @@ void GuiShieldFrequencySelect::onDraw(sp::RenderTarget& renderer) { if (my_spaceship) { - calibrate_button->setEnable(my_spaceship->shield_calibration_delay <= 0.0f); - new_frequency->setEnable(my_spaceship->shield_calibration_delay <= 0.0f); + auto shields = my_spaceship->entity.getComponent(); + calibrate_button->setEnable(shields && shields->calibration_delay <= 0.0f); + new_frequency->setEnable(shields && shields->calibration_delay <= 0.0f); } GuiElement::onDraw(renderer); } diff --git a/src/screenComponents/shieldsEnableButton.cpp b/src/screenComponents/shieldsEnableButton.cpp index ddf6f55a30..d82c6f8c6e 100644 --- a/src/screenComponents/shieldsEnableButton.cpp +++ b/src/screenComponents/shieldsEnableButton.cpp @@ -15,11 +15,14 @@ GuiShieldsEnableButton::GuiShieldsEnableButton(GuiContainer* owner, string id) : GuiElement(owner, id) { button = new GuiToggleButton(this, id + "_BUTTON", "Shields: ON", [](bool value) { - if (my_spaceship) - my_spaceship->commandSetShields(!my_spaceship->shields_active); + if (my_spaceship) { + auto shields = my_spaceship->entity.getComponent(); + if (shields) + my_spaceship->commandSetShields(!shields->active); + } }); button->setSize(GuiElement::GuiSizeMax, GuiElement::GuiSizeMax); - bar = new GuiProgressbar(this, id + "_BAR", 0.0, PlayerSpaceship::shield_calibration_time, 0); + bar = new GuiProgressbar(this, id + "_BAR", 0.0, 25.0f, 0.0f); bar->setSize(GuiElement::GuiSizeMax, GuiElement::GuiSizeMax); (new GuiLabel(bar, id + "_CALIBRATING_LABEL", tr("shields","Calibrating"), 30))->setSize(GuiElement::GuiSizeMax, GuiElement::GuiSizeMax); @@ -35,11 +38,12 @@ void GuiShieldsEnableButton::onDraw(sp::RenderTarget& target) button->hide(); bar->hide(); } - else if (my_spaceship->shield_calibration_delay > 0.0f) + else if (shields->calibration_delay > 0.0f) { button->hide(); bar->show(); - bar->setValue(my_spaceship->shield_calibration_delay); + bar->setRange(0, shields->calibration_time); + bar->setValue(shields->calibration_delay); } else { @@ -59,8 +63,11 @@ void GuiShieldsEnableButton::onUpdate() { if (my_spaceship && isVisible()) { - if (keys.weapons_toggle_shields.getDown()) - my_spaceship->commandSetShields(!my_spaceship->shields_active); + if (keys.weapons_toggle_shields.getDown()) { + auto shields = my_spaceship->entity.getComponent(); + if (shields) + my_spaceship->commandSetShields(!shields->active); + } if (keys.weapons_enable_shields.getDown()) my_spaceship->commandSetShields(true); if (keys.weapons_disable_shields.getDown()) diff --git a/src/screens/gm/tweak.cpp b/src/screens/gm/tweak.cpp index 4822031ae2..d6366a0d43 100644 --- a/src/screens/gm/tweak.cpp +++ b/src/screens/gm/tweak.cpp @@ -1056,7 +1056,7 @@ GuiShipTweakPlayer2::GuiShipTweakPlayer2(GuiContainer* owner) // Can combat maneuver bool can_combat_maneuver = new GuiToggleButton(right_col, "", tr("button", "Can combat maneuver"), [this](bool value) { - target->setCanCombatManeuver(value); + //target->setCanCombatManeuver(value); }); can_combat_maneuver->setSize(GuiElement::GuiSizeMax, 40); @@ -1091,7 +1091,7 @@ void GuiShipTweakPlayer2::onDraw(sp::RenderTarget& renderer) can_scan->setValue(target->getCanScan()); can_hack->setValue(target->getCanHack()); can_dock->setValue(target->getCanDock()); - can_combat_maneuver->setValue(target->getCanCombatManeuver()); + //can_combat_maneuver->setValue(target->getCanCombatManeuver()); can_self_destruct->setValue(target->getCanSelfDestruct()); can_launch_probe->setValue(target->getCanLaunchProbe()); //auto_coolant_enabled->setValue(target->auto_coolant_enabled); diff --git a/src/spaceObjects/playerSpaceship.cpp b/src/spaceObjects/playerSpaceship.cpp index 313fe9c5a7..bba56dea13 100644 --- a/src/spaceObjects/playerSpaceship.cpp +++ b/src/spaceObjects/playerSpaceship.cpp @@ -343,11 +343,9 @@ PlayerSpaceship::PlayerSpaceship() jump_indicator = 0.0; comms_state = CS_Inactive; comms_open_delay = 0.0; - shield_calibration_delay = 0.0; auto_repair_enabled = false; scan_probe_stock = max_scan_probes; alert_level = AL_Normal; - shields_active = false; control_code = ""; setFactionId(1); @@ -358,19 +356,15 @@ PlayerSpaceship::PlayerSpaceship() registerMemberReplication(&can_scan); registerMemberReplication(&can_hack); - registerMemberReplication(&can_combat_maneuver); registerMemberReplication(&can_self_destruct); registerMemberReplication(&can_launch_probe); registerMemberReplication(&hull_damage_indicator, 0.5); registerMemberReplication(&jump_indicator, 0.5); - registerMemberReplication(&energy_shield_use_per_second, .5f); registerMemberReplication(&main_screen_setting); registerMemberReplication(&main_screen_overlay); registerMemberReplication(&scanning_delay, 0.5); registerMemberReplication(&scanning_complexity); registerMemberReplication(&scanning_depth); - registerMemberReplication(&shields_active); - registerMemberReplication(&shield_calibration_delay, 0.5); registerMemberReplication(&auto_repair_enabled); registerMemberReplication(&comms_state); registerMemberReplication(&comms_open_delay, 1.0); @@ -430,15 +424,6 @@ void PlayerSpaceship::update(float delta) if (jump_indicator > 0) jump_indicator -= delta; - // If shields are calibrating, tick the calibration delay. Factor shield - // subsystem effectiveness when determining the tick rate. - if (shield_calibration_delay > 0) - { - auto front = ShipSystem::get(entity, ShipSystem::Type::FrontShield); - auto rear = ShipSystem::get(entity, ShipSystem::Type::RearShield); - shield_calibration_delay -= delta * ((front ? front->getSystemEffectiveness() : 0) + (rear ? rear->getSystemEffectiveness() : 0)) / 2.0f; - } - // Actions performed on the server only. if (game_server) { @@ -486,19 +471,6 @@ void PlayerSpaceship::update(float delta) comms_state = CS_ChannelBroken; } - // Consume power if shields are enabled. - if (shields_active) - useEnergy(delta * getEnergyShieldUsePerSecond()); - - // Consume power based on subsystem requests and state. - auto reactor = entity.getComponent(); - - // If the ship has less than 10 energy, drop shields automatically. - if (reactor && reactor->energy < 10.0f) - { - shields_active = false; - } - if (scanning_target) { // If the scan setting or a target's scan complexity is none/0, @@ -589,12 +561,13 @@ void PlayerSpaceship::applyTemplateValues() if (entity) { entity.getOrAddComponent(); + if (!ship_template->can_combat_maneuver) + entity.removeComponent(); } // Set the ship's capabilities. can_scan = ship_template->can_scan; can_hack = ship_template->can_hack; - can_combat_maneuver = ship_template->can_combat_maneuver; can_self_destruct = ship_template->can_self_destruct; can_launch_probe = ship_template->can_launch_probe; if (!on_new_player_ship_called) @@ -1055,16 +1028,15 @@ void PlayerSpaceship::onReceiveClientCommand(int32_t client_id, sp::io::DataBuff bool active; packet >> active; - if (shield_calibration_delay <= 0.0f && active != shields_active) - { - shields_active = active; - if (active) - { - playSoundOnMainScreen("sfx/shield_up.wav"); - } - else + auto shields = entity.getComponent(); + if (shields) { + if (shields->calibration_delay <= 0.0f && active != shields->active) { - playSoundOnMainScreen("sfx/shield_down.wav"); + shields->active = active; + if (active) + playSoundOnMainScreen("sfx/shield_up.wav"); + else + playSoundOnMainScreen("sfx/shield_down.wav"); } } } @@ -1284,15 +1256,14 @@ void PlayerSpaceship::onReceiveClientCommand(int32_t client_id, sp::io::DataBuff } break; case CMD_SET_SHIELD_FREQUENCY: - if (shield_calibration_delay <= 0.0f) { int32_t new_frequency; packet >> new_frequency; auto shields = entity.getComponent(); - if (shields && new_frequency != shields->frequency) + if (shields && shields->calibration_delay <= 0.0f && new_frequency != shields->frequency) { shields->frequency = new_frequency; - shield_calibration_delay = shield_calibration_time; + shields->calibration_delay = shields->calibration_time; shields->active = false; if (shields->frequency < 0) shields->frequency = 0; @@ -1870,8 +1841,8 @@ string PlayerSpaceship::getExportLine() result += ":setCanHack(" + string(can_hack, true) + ")"; //if (can_dock != ship_template->can_dock) // result += ":setCanDock(" + string(can_dock, true) + ")"; - if (can_combat_maneuver != ship_template->can_combat_maneuver) - result += ":setCanCombatManeuver(" + string(can_combat_maneuver, true) + ")"; + //if (can_combat_maneuver != ship_template->can_combat_maneuver) + // result += ":setCanCombatManeuver(" + string(can_combat_maneuver, true) + ")"; if (can_self_destruct != ship_template->can_self_destruct) result += ":setCanSelfDestruct(" + string(can_self_destruct, true) + ")"; if (can_launch_probe != ship_template->can_launch_probe) @@ -1915,10 +1886,8 @@ string PlayerSpaceship::getExportLine() } */ - if (std::fabs(getEnergyShieldUsePerSecond() - default_energy_shield_use_per_second) > std::numeric_limits::epsilon()) - { - result += ":setEnergyShieldUsePerSecond(" + string(getEnergyShieldUsePerSecond(), 2) + ")"; - } + //if (std::fabs(getEnergyShieldUsePerSecond() - default_energy_shield_use_per_second) > std::numeric_limits::epsilon()) + // result += ":setEnergyShieldUsePerSecond(" + string(getEnergyShieldUsePerSecond(), 2) + ")"; //if (std::fabs(getEnergyWarpPerSecond() - default_energy_warp_per_second) > std::numeric_limits::epsilon()) // result += ":setEnergyWarpPerSecond(" + string(getEnergyWarpPerSecond(), 2) + ")"; diff --git a/src/spaceObjects/playerSpaceship.h b/src/spaceObjects/playerSpaceship.h index b148d16df3..b7c7835ee4 100644 --- a/src/spaceObjects/playerSpaceship.h +++ b/src/spaceObjects/playerSpaceship.h @@ -34,12 +34,9 @@ enum EAlertLevel class PlayerSpaceship : public SpaceShip { public: - // Power consumption and generation base rates - constexpr static float default_energy_shield_use_per_second = 1.5f; // Overheat subsystem damage rate constexpr static float damage_per_second_on_overheat = 0.08f; // Base time it takes to perform an action - constexpr static float shield_calibration_time = 25.0f; constexpr static float comms_channel_open_time = 2.0; constexpr static float scan_probe_charge_time = 10.0f; constexpr static float max_scanning_delay = 6.0; @@ -85,12 +82,8 @@ class PlayerSpaceship : public SpaceShip // Visual indicators of hull damage and in-progress jumps float hull_damage_indicator; float jump_indicator; - // Time in seconds it takes to recalibrate shields - float shield_calibration_delay; // Ship automation features, mostly for single-person ships like fighters bool auto_repair_enabled; - // Whether shields are up (true) or down - bool shields_active; // Password to join a ship. Default is empty. string control_code; @@ -107,7 +100,6 @@ class PlayerSpaceship : public SpaceShip CommsScriptInterface comms_script_interface; // Server only // Ship's log container std::vector ships_log; - float energy_shield_use_per_second = default_energy_shield_use_per_second; public: std::vector custom_functions; @@ -128,8 +120,6 @@ class PlayerSpaceship : public SpaceShip // Capable of hacking a target bool can_hack = true; - // Capable of combat maneuvers - bool can_combat_maneuver = true; // Capable of self-destruction bool can_self_destruct = true; @@ -202,8 +192,8 @@ class PlayerSpaceship : public SpaceShip bool getCanHack() { return can_hack; } void setCanDock(bool enabled); bool getCanDock(); - void setCanCombatManeuver(bool enabled) { can_combat_maneuver = enabled; } - bool getCanCombatManeuver() { return can_combat_maneuver; } + void setCanCombatManeuver(bool enabled) { } //TODO + bool getCanCombatManeuver() { return true; } // TODO void setCanSelfDestruct(bool enabled) { can_self_destruct = enabled; } bool getCanSelfDestruct() { return can_self_destruct && self_destruct_size > 0 && self_destruct_damage > 0; } void setCanLaunchProbe(bool enabled) { can_launch_probe = enabled; } @@ -294,8 +284,8 @@ class PlayerSpaceship : public SpaceShip EAlertLevel getAlertLevel() { return alert_level; } // Flow rate controls. - float getEnergyShieldUsePerSecond() const { return energy_shield_use_per_second; } - void setEnergyShieldUsePerSecond(float rate) { energy_shield_use_per_second = rate; } + float getEnergyShieldUsePerSecond() const { return 0.0f; } //TODO + void setEnergyShieldUsePerSecond(float rate) { } //TODO float getEnergyWarpPerSecond() const { return 0.0f; } //TODO void setEnergyWarpPerSecond(float rate) {} //TODO @@ -316,8 +306,8 @@ class PlayerSpaceship : public SpaceShip bool hasPlayerAtPosition(ECrewPosition position); // Ship shields functions - virtual bool getShieldsActive() override { return shields_active; } - void setShieldsActive(bool active) { shields_active = active; } + virtual bool getShieldsActive() override { return true; } //TODO + void setShieldsActive(bool active) { } // Waypoint functions int getWaypointCount() { return waypoints.size(); } diff --git a/src/spaceObjects/spaceship.cpp b/src/spaceObjects/spaceship.cpp index 48a81a6809..3f7c0bd4fd 100644 --- a/src/spaceObjects/spaceship.cpp +++ b/src/spaceObjects/spaceship.cpp @@ -399,7 +399,7 @@ bool SpaceShip::useEnergy(float amount) // If it doesn't, return false. auto reactor = entity.getComponent(); if (reactor) - return reactor->use_energy(amount); + return reactor->useEnergy(amount); return true; } diff --git a/src/systems/beamweapon.cpp b/src/systems/beamweapon.cpp index defa644899..265bd15a27 100644 --- a/src/systems/beamweapon.cpp +++ b/src/systems/beamweapon.cpp @@ -74,7 +74,7 @@ void BeamWeaponSystem::update(float delta) // If the target is in the beam's arc and range, the beam has cooled // down, and the beam can consume enough energy to fire ... - if (distance < mount.range && mount.cooldown <= 0.0f && fabsf(angle_diff) < mount.arc / 2.0f && (!reactor || reactor->use_energy(mount.energy_per_beam_fire))) + if (distance < mount.range && mount.cooldown <= 0.0f && fabsf(angle_diff) < mount.arc / 2.0f && (!reactor || reactor->useEnergy(mount.energy_per_beam_fire))) { // ... add heat to the beam and zap the target. beamsys.addHeat(mount.heat_per_beam_fire); diff --git a/src/systems/docking.cpp b/src/systems/docking.cpp index 9c24fb94c3..86ba2252f9 100644 --- a/src/systems/docking.cpp +++ b/src/systems/docking.cpp @@ -87,7 +87,7 @@ void DockingSystem::update(float delta) // set to share its energy with docked ships, transfer energy from the // mothership to docked ships until the mothership runs out of energy // or the docked ship doesn't require any. - if (!other_reactor || other_reactor->use_energy(energy_request)) + if (!other_reactor || other_reactor->useEnergy(energy_request)) my_reactor->energy += energy_request; } } diff --git a/src/systems/energysystem.cpp b/src/systems/energysystem.cpp index bc8c9fb12d..ec1896eb23 100644 --- a/src/systems/energysystem.cpp +++ b/src/systems/energysystem.cpp @@ -5,6 +5,7 @@ #include "components/hull.h" #include "spaceObjects/spaceObject.h" #include "spaceObjects/explosionEffect.h" +#include "multiplayer_server.h" void EnergySystem::update(float delta) @@ -39,7 +40,7 @@ void EnergySystem::update(float delta) // If reactor health is worse than -90% and overheating, it explodes, // destroying the ship and damaging a 0.5U radius. - if (reactor.health < -0.9f && reactor.heat_level == 1.0f) + if (reactor.health < -0.9f && reactor.heat_level == 1.0f && game_server) { auto hull = entity.getComponent(); if (hull && hull->allow_destruction) { diff --git a/src/systems/shieldsystem.cpp b/src/systems/shieldsystem.cpp index 4e58983b0b..dd57681adc 100644 --- a/src/systems/shieldsystem.cpp +++ b/src/systems/shieldsystem.cpp @@ -2,13 +2,25 @@ #include "components/shields.h" #include "components/docking.h" +#include "components/reactor.h" #include "ecs/query.h" void ShieldSystem::update(float delta) { - for(auto [entity, shields] : sp::ecs::Query()) + for(auto [entity, shields, reactor] : sp::ecs::Query>()) { + // If shields are calibrating, tick the calibration delay. Factor shield + // subsystem effectiveness when determining the tick rate. + if (shields.calibration_delay > 0.0) { + shields.calibration_delay -= delta * (shields.front_system.getSystemEffectiveness() * shields.rear_system.getSystemEffectiveness()) * 0.5f; + shields.active = false; + } + if (shields.active && reactor) { + // Consume power if shields are enabled. + if (!reactor->useEnergy(delta * shields.energy_use_per_second)) + shields.active = false; + } for(int n=0; n, sp::Transform, sp::Physics, SpaceObject*>()) + for(auto [entity, warp, impulse, position, physics] : sp::ecs::Query, sp::Transform, sp::Physics>()) { if (warp.request > 0 || warp.current > 0) { @@ -45,10 +43,10 @@ void WarpSystem::update(float delta) // If warping, consume energy at a rate of 120% the warp request. // If shields are up, that rate is increased by an additional 50%. auto energy_use = warp.energy_warp_per_second * delta * warp.getSystemEffectiveness() * powf(warp.current, 1.3f); - auto ship = dynamic_cast(obj); - if (ship && ship->getShieldsActive()) + auto shields = entity.getComponent(); + if (shields && shields->active) energy_use *= 1.7f; - if (!reactor->use_energy(energy_use)) + if (!reactor->useEnergy(energy_use)) warp.request = 0; } } From e9c700fbbd8f7297c11c3727f3e04f27935c7d23 Mon Sep 17 00:00:00 2001 From: Daid Date: Wed, 21 Dec 2022 11:56:12 +0100 Subject: [PATCH 023/320] Factions to ECS, this breaks a few things right now. But got to break some eggs. --- CMakeLists.txt | 2 + src/components/faction.cpp | 59 ++++++++++ src/components/faction.h | 44 +++++++ src/factionInfo.cpp | 126 +++++++-------------- src/factionInfo.h | 53 +++------ src/gameGlobalInfo.cpp | 12 +- src/gameGlobalInfo.h | 7 +- src/menus/autoConnectScreen.cpp | 2 +- src/scienceDatabase.cpp | 28 ++--- src/screenComponents/indicatorOverlays.cpp | 17 +-- src/screenComponents/radarView.cpp | 3 +- src/screens/crew6/relayScreen.cpp | 15 ++- src/screens/crew6/scienceScreen.cpp | 6 +- src/screens/gm/gameMasterScreen.cpp | 16 +-- src/screens/gm/objectCreationView.cpp | 8 +- src/spaceObjects/cpuShip.cpp | 28 ++--- src/spaceObjects/playerSpaceship.cpp | 10 +- src/spaceObjects/spaceObject.cpp | 101 ++++++++++------- src/spaceObjects/spaceObject.h | 23 ++-- src/spaceObjects/spaceship.cpp | 51 ++++----- src/spaceObjects/spaceship.h | 6 +- 21 files changed, 328 insertions(+), 289 deletions(-) create mode 100644 src/components/faction.cpp create mode 100644 src/components/faction.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 665f86559a..8d12dc4336 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -351,6 +351,8 @@ set(MAIN_SOURCES src/spaceObjects/shipTemplateBasedObject.cpp src/spaceObjects/planet.cpp src/spaceObjects/zone.cpp + src/components/faction.h + src/components/faction.cpp src/components/radar.h src/components/hull.h src/components/rendering.h diff --git a/src/components/faction.cpp b/src/components/faction.cpp new file mode 100644 index 0000000000..35db0cb933 --- /dev/null +++ b/src/components/faction.cpp @@ -0,0 +1,59 @@ +#include "components/faction.h" +#include "ecs/query.h" + + +static FactionInfo default_faction_info; + + +sp::ecs::Entity Faction::find(const string& name) +{ + for(auto [entity, info] : sp::ecs::Query()) { + if (info.name == name) + return entity; + } + return {}; +} + +FactionInfo& Faction::getInfo(sp::ecs::Entity entity) +{ + auto faction = entity.getComponent(); + if (faction) { + auto info = faction->entity.getComponent(); + if (info) + return *info; + } + return default_faction_info; +} + +FactionRelation Faction::getRelation(sp::ecs::Entity a, sp::ecs::Entity b) +{ + auto fia = Faction::getInfo(a); + auto fb = b.getComponent(); + if (fb) + return fia.getRelation(fb->entity); + return fia.getRelation({}); +} + +FactionRelation FactionInfo::getRelation(sp::ecs::Entity faction_entity) +{ + for(auto it : relations) + if (it.first == faction_entity) + return it.second; + return FactionRelation::Neutral; +} + +void FactionInfo::setRelation(sp::ecs::Entity faction_entity, FactionRelation relation) +{ + for(auto& it : relations) { + if (it.first == faction_entity) { + it.second = relation; + return; + } + } + relations.push_back({faction_entity, relation}); +} + +FactionInfo* FactionInfo::find(const string& name) +{ + return Faction::find(name).getComponent(); +} diff --git a/src/components/faction.h b/src/components/faction.h new file mode 100644 index 0000000000..1b1f4b5a26 --- /dev/null +++ b/src/components/faction.h @@ -0,0 +1,44 @@ +#pragma once + +#include "ecs/entity.h" +#include +#include + +class FactionInfo; + +enum class FactionRelation +{ + Friendly, + Neutral, + Enemy +}; + +// Component to set our current faction, +// a faction is an entity with the FactionInfo component +class Faction +{ +public: + sp::ecs::Entity entity; + + static sp::ecs::Entity find(const string& name); + static FactionInfo& getInfo(sp::ecs::Entity entity); + static FactionRelation getRelation(sp::ecs::Entity a, sp::ecs::Entity b); +}; + +class FactionInfo +{ +public: + glm::u8vec4 gm_color = {255,255,255,255}; + string name; + string locale_name; + string description; + + float reputation_points = 0.0f; + + std::vector> relations; + + FactionRelation getRelation(sp::ecs::Entity faction_entity); + void setRelation(sp::ecs::Entity faction_entity, FactionRelation relation); + + static FactionInfo* find(const string& name); +}; diff --git a/src/factionInfo.cpp b/src/factionInfo.cpp index 1f277dd2ae..f6ac039145 100644 --- a/src/factionInfo.cpp +++ b/src/factionInfo.cpp @@ -1,26 +1,25 @@ #include "factionInfo.h" +#include "components/faction.h" #include "scriptInterface.h" +#include "ecs/query.h" #include "multiplayer_server.h" - -REGISTER_SCRIPT_CLASS(FactionInfo) +REGISTER_SCRIPT_CLASS_NAMED(FactionInfoLegacy, "FactionInfo") { - REGISTER_SCRIPT_CLASS_FUNCTION(FactionInfo, setName); - REGISTER_SCRIPT_CLASS_FUNCTION(FactionInfo, setLocaleName); - REGISTER_SCRIPT_CLASS_FUNCTION(FactionInfo, setGMColor); - REGISTER_SCRIPT_CLASS_FUNCTION(FactionInfo, setDescription); - REGISTER_SCRIPT_CLASS_FUNCTION(FactionInfo, setEnemy); - REGISTER_SCRIPT_CLASS_FUNCTION(FactionInfo, setFriendly); + REGISTER_SCRIPT_CLASS_FUNCTION(FactionInfoLegacy, setName); + REGISTER_SCRIPT_CLASS_FUNCTION(FactionInfoLegacy, setLocaleName); + REGISTER_SCRIPT_CLASS_FUNCTION(FactionInfoLegacy, setGMColor); + REGISTER_SCRIPT_CLASS_FUNCTION(FactionInfoLegacy, setDescription); + REGISTER_SCRIPT_CLASS_FUNCTION(FactionInfoLegacy, setEnemy); + REGISTER_SCRIPT_CLASS_FUNCTION(FactionInfoLegacy, setFriendly); } -std::array, 32> factionInfo; - static int getFactionInfo(lua_State* L) { auto name = luaL_checkstring(L, 1); - for(unsigned int n = 0; n < factionInfo.size(); n++) - if (factionInfo[n] && factionInfo[n]->getName() == name) - return convert>::returnType(L, factionInfo[n]); + for(auto [entity, info] : sp::ecs::Query()) + if (info.name == name) + return convert>::returnType(L, *entity.getComponent()); return 0; } /// P getFactionInfo(string faction_name) @@ -28,104 +27,59 @@ static int getFactionInfo(lua_State* L) REGISTER_SCRIPT_FUNCTION(getFactionInfo); -REGISTER_MULTIPLAYER_CLASS(FactionInfo, "FactionInfo"); -FactionInfo::FactionInfo() +REGISTER_MULTIPLAYER_CLASS(FactionInfoLegacy, "FactionInfo"); +FactionInfoLegacy::FactionInfoLegacy() : MultiplayerObject("FactionInfo") { - index = 255; - gm_color = {255,255,255,255}; - enemy_mask = 0; - friend_mask = 0; - - registerMemberReplication(&index); - registerMemberReplication(&gm_color); - registerMemberReplication(&name); - registerMemberReplication(&locale_name); - registerMemberReplication(&description); - registerMemberReplication(&enemy_mask); - registerMemberReplication(&friend_mask); - - if (game_server) { - for(size_t n=0; n(); + entity.addComponent(this); } -FactionInfo::~FactionInfo() +FactionInfoLegacy::~FactionInfoLegacy() { + entity.destroy(); } -void FactionInfo::update(float delta) +void FactionInfoLegacy::update(float delta) { - if (index != 255) - factionInfo[index] = this; } -void FactionInfo::setEnemy(P other) +void FactionInfoLegacy::setName(string name) { entity.getOrAddComponent().name = name; } +void FactionInfoLegacy::setLocaleName(string name) { entity.getOrAddComponent().locale_name = name; } +string FactionInfoLegacy::getName() { return entity.getOrAddComponent().name; } +string FactionInfoLegacy::getLocaleName() { return entity.getOrAddComponent().locale_name; } +string FactionInfoLegacy::getDescription() { return entity.getOrAddComponent().description; } +void FactionInfoLegacy::setGMColor(int r, int g, int b) { entity.getOrAddComponent().gm_color = glm::u8vec4(r, g, b, 255); } +glm::u8vec4 FactionInfoLegacy::getGMColor() { return entity.getOrAddComponent().gm_color; } +void FactionInfoLegacy::setDescription(string description) { entity.getOrAddComponent().description = description; } + +void FactionInfoLegacy::setEnemy(P other) { + auto mine = entity.getOrAddComponent(); if (!other) { - LOG(WARNING) << "Tried to set a an undefined faction to enemy with " << name; + LOG(WARNING) << "Tried to set a an undefined faction to enemy with " << mine.name; return; } + auto their = other->entity.getOrAddComponent(); - friend_mask &=~(1U << other->index); - other->friend_mask &=~(1U << index); - enemy_mask |= (1 << other->index); - other->enemy_mask |= (1 << index); + //TODO } -void FactionInfo::setFriendly(P other) +void FactionInfoLegacy::setFriendly(P other) { + auto mine = entity.getOrAddComponent(); if (!other) { - LOG(WARNING) << "Tried to set a an undefined faction to friendly with " << name; + LOG(WARNING) << "Tried to set a an undefined faction to friendly with " << mine.name; return; } + auto their = other->entity.getOrAddComponent(); - friend_mask |= (1U << other->index); - other->friend_mask |= (1U << index); - enemy_mask &=~(1 << other->index); - other->enemy_mask &=~(1 << index); -} - -EFactionVsFactionState FactionInfo::getState(P other) -{ - if (!other) return FVF_Neutral; - if (enemy_mask & (1 << other->index)) return FVF_Enemy; - if (friend_mask & (1 << other->index)) return FVF_Friendly; - return FVF_Neutral; -} - -EFactionVsFactionState FactionInfo::getState(uint8_t idx0, uint8_t idx1) -{ - if (idx0 >= factionInfo.size()) return FVF_Neutral; - if (idx1 >= factionInfo.size()) return FVF_Neutral; - if (!factionInfo[idx0] || !factionInfo[idx1]) return FVF_Neutral; - return factionInfo[idx0]->getState(factionInfo[idx1]); -} - -unsigned int FactionInfo::findFactionId(string name) -{ - for(unsigned int n = 0; n < factionInfo.size(); n++) - if (factionInfo[n] && factionInfo[n]->name == name) - return n; - LOG(ERROR) << "Failed to find faction: " << name; - return 0; + //TODO } -void FactionInfo::reset() +void FactionInfoLegacy::reset() { - for(unsigned int n = 0; n < factionInfo.size(); n++) - if (factionInfo[n]) - factionInfo[n]->destroy(); } diff --git a/src/factionInfo.h b/src/factionInfo.h index fccad30255..d1dfed5916 100644 --- a/src/factionInfo.h +++ b/src/factionInfo.h @@ -6,82 +6,63 @@ #include "multiplayer.h" #include #include +#include "ecs/entity.h" +#include "components/faction.h" -class FactionInfo; -extern std::array, 32> factionInfo; - -enum EFactionVsFactionState -{ - FVF_Friendly, - FVF_Neutral, - FVF_Enemy -}; - -class FactionInfo : public MultiplayerObject, public Updatable +class FactionInfoLegacy : public MultiplayerObject, public Updatable { public: - FactionInfo(); - virtual ~FactionInfo(); + sp::ecs::Entity entity; + + FactionInfoLegacy(); + virtual ~FactionInfoLegacy(); virtual void update(float delta) override; /*! * \brief Set name of faction. * \param Name Name of the faction */ - void setName(string name) { this->name = name; if (locale_name == "") locale_name = name; } - void setLocaleName(string name) { this->locale_name = name; } + void setName(string name); + void setLocaleName(string name); /*! * \brief Get name of faction. * \return String Name of the faction */ - string getName() { return this->name; } - string getLocaleName() { return this->locale_name; } + string getName(); + string getLocaleName(); /*! * \brief Get description of faction. * \return String description of the faction */ - string getDescription() {return this->description;} + string getDescription(); /*! * \brief Set color of faction on GM screen. * \param r Red component. * \param g Green component. * \param b Blue component. */ - void setGMColor(int r, int g, int b) { gm_color = glm::u8vec4(r, g, b, 255); } - glm::u8vec4 getGMColor() { return gm_color; } + void setGMColor(int r, int g, int b); + glm::u8vec4 getGMColor(); /*! * \brief Set description of faction. * \param description */ - void setDescription(string description) { this->description = description; } + void setDescription(string description); /*! * \brief Add another faction that this faction sees as an enemy. * \param faction info object. */ - void setEnemy(P other); + void setEnemy(P other); /*! * \brief Add another faction that this faction sees as a friendly. * \param faction info object. */ - void setFriendly(P other); - - EFactionVsFactionState getState(P other); - - static EFactionVsFactionState getState(uint8_t idx0, uint8_t idx1); - static unsigned int findFactionId(string name); + void setFriendly(P other); static void reset(); //Destroy all FactionInfo objects -protected: - uint8_t index; - glm::u8vec4 gm_color; - string name; - string locale_name; - string description; - uint32_t enemy_mask; - uint32_t friend_mask; }; #endif//FACTION_INFO_H diff --git a/src/gameGlobalInfo.cpp b/src/gameGlobalInfo.cpp index ae719cc036..d28777860a 100644 --- a/src/gameGlobalInfo.cpp +++ b/src/gameGlobalInfo.cpp @@ -19,7 +19,6 @@ GameGlobalInfo::GameGlobalInfo() SDL_assert(!gameGlobalInfo); callsign_counter = 0; - victory_faction = -1; gameGlobalInfo = this; for(int n=0; ndestroy(); @@ -176,14 +171,9 @@ void GameGlobalInfo::reset() engine->getObject("scenario")->destroy(); foreach(Script, s, script_list) - { s->destroy(); - } - for(unsigned int n=0; n reputation_points; EScanningComplexity scanning_complexity; //Hacking difficulty ranges from 0 to 3 int hacking_difficulty; @@ -94,12 +93,12 @@ class GameGlobalInfo : public MultiplayerObject, public Updatable * \brief Set a faction to victorious. * \param string Name of the faction that won. */ - void setVictory(string faction_name) { victory_faction = FactionInfo::findFactionId(faction_name); } + void setVictory(string faction_name) { victory_faction = Faction::find(faction_name); } /*! * \brief Get ID of faction that won. * \param int */ - int getVictoryFactionId() { return victory_faction; } + FactionInfo* getVictoryFaction() { if (!victory_faction) return nullptr; return victory_faction.getComponent(); } void addScript(P