Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 41 additions & 34 deletions scripts/api/entity/shiptemplatebasedobject.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,27 @@ function Entity:setTemplate(template_name)
error("Failed to find template: " .. tostring(template_name), 2)
end
-- print("Setting template:" .. template_name)

-- Convert old hull component setters to health + hull for backward compatibility
if template.hull and type(template.hull) == "table" then
-- Create health component from hull data
local hull_data = template.hull
comp.health = {
current = hull_data.current or 100.0,
max = hull_data.max or 100.0,
allow_destruction = hull_data.allow_destruction,
damaged_by_energy = hull_data.damaged_by_energy,
damaged_by_kinetic = hull_data.damaged_by_kinetic,
damaged_by_emp = hull_data.damaged_by_emp,
on_destruction = hull_data.on_destruction,
on_taking_damage = hull_data.on_taking_damage
}
-- Create hull as empty marker component
comp.hull = {}
end

for key, value in next, template, nil do
if string.sub(key, 1, 2) ~= "__" then
if string.sub(key, 1, 2) ~= "__" and key ~= "hull" then
comp[key] = value
end
end
Expand Down Expand Up @@ -91,47 +110,35 @@ end
function Entity:getTypeName()
return self.components.typename.type_name
end
--- Returns this STBO's hull points.
--- Example: stbo:getHull()
--- DEPRECATED: Returns this entity's health points.
--- Example: entity:getHull()
function Entity:getHull()
if self.components.hull then return self.components.hull.current end
return 0
return self:getHealth()
end
--- Returns this STBO's maximum limit of hull points.
--- Example: stbo:getHullMax()
--- DEPRECATED: Returns this entity's maximum limit of health points.
--- Example: entity:getHullMax()
function Entity:getHullMax()
if self.components.hull then return self.components.hull.max end
return 0
return self:getHealthMax()
end
--- Sets this STBO's hull points.
--- Adds the Hull marker component to the entity.
--- DEPRECATED: If passed an amount, also sets this entity's current health value.
--- If set to a value larger than the maximum, this sets the value to the limit.
--- If set to a value less than 0, this sets the value to 0.
--- Note that setting this value to 0 doesn't immediately destroy the STBO.
--- Example: stbo:setHull(100) -- sets the hull point limit to either 100, or the limit if less than 100
--- Note that setting this value to 0 doesn't immediately destroy the entity.
--- Example: entity:setHull(100) -- sets the hull point limit to either 100, or the limit if less than 100
function Entity:setHull(amount)
if self.components.hull then self.components.hull.current = amount end
self.components.hull = {}
self:setHealth(amount)
return self
end
--- Sets this STBO's maximum limit of hull points.
--- Note that SpaceStations can't repair their own hull, so this only changes the percentage of remaining hull.
--- Example: stbo:setHullMax(100) -- sets the hull point limit to 100
--- Adds the Hull marker component to the entity.
--- DEPRECATED: If passed an amount, also sets this entity's maximum limit of health points.
--- Example: entity:setHullMax(100) -- sets the hull point limit to 100
function Entity:setHullMax(amount)
if self.components.hull then self.components.hull.max = amount end
self.components.hull = {}
self:setHealthMax(amount)
return self
end
--- Defines whether this STBO can be destroyed by damage.
--- Defaults to true.
--- Example: stbo:setCanBeDestroyed(false) -- prevents the STBO from being destroyed by damage
function Entity:setCanBeDestroyed(allow_destroy)
if self.components.hull then self.components.hull.allow_destruction = allow_destroy end
return self
end
--- Returns whether the STBO can be destroyed by damage.
--- Example: stbo:getCanBeDestroyed()
function Entity:getCanBeDestroyed()
if self.components.hull then return self.components.hull.allow_destruction end
return false
end
--- Returns the shield points for this STBO's shield segment with the given index.
--- Shield segments are 0-indexed.
--- Example for a ship with two shield segments:
Expand Down Expand Up @@ -283,12 +290,12 @@ end
--- [DEPRECATED]
--- Use ShipTemplateBasedObject:getShieldLevel() with an index value.
function Entity:getFrontShield()
return self.getShieldLevel(0)
return self:getShieldLevel(0)
end
--- [DEPRECATED]
--- Use ShipTemplateBasedObject:setShieldsMax().
function Entity:getFrontShieldMax()
return self.getShieldMax(0)
return self:getShieldMax(0)
end
--- [DEPRECATED]
--- Use ShipTemplateBasedObject:setShieldLevel() with an index value.
Expand All @@ -305,12 +312,12 @@ end
--- [DEPRECATED]
--- Use ShipTemplateBasedObject:getShieldLevel() with an index value.
function Entity:getRearShield()
return self.getShieldLevel(1)
return self:getShieldLevel(1)
end
--- [DEPRECATED]
--- Use ShipTemplateBasedObject:setShieldsMax().
function Entity:getRearShieldMax()
return self.getShieldMax(1)
return self:getShieldMax(1)
end
--- [DEPRECATED]
--- Use ShipTemplateBasedObject:setShieldLevel() with an index value.
Expand Down
44 changes: 42 additions & 2 deletions scripts/api/entity/spaceobject.lua
Original file line number Diff line number Diff line change
Expand Up @@ -458,12 +458,52 @@ function Entity:isScannedByFaction(faction_name)
end
return false
end
--- Returns this entity's health points.
--- Example: entity:getHealth()
function Entity:getHealth()
if self.components.health then return self.components.health.current end
return 0
end
--- Returns this entity's maximum limit of health points.
--- Example: entity:getHealthMax()
function Entity:getHealthMax()
if self.components.health then return self.components.health.max end
return 0
end
--- Sets this entity's health points.
--- If set to a value larger than the maximum, this sets the value to the limit.
--- If set to a value less than 0, this sets the value to 0.
--- Note that setting this value to 0 doesn't immediately destroy the entity.
--- Example: entity:setHealth(100) -- sets the health point limit to either 100, or the limit if less than 100
function Entity:setHealth(amount)
if self.components.health then self.components.health.current = amount end
return self
end
--- Sets this entity's maximum limit of health points.
--- Example: entity:setHealthMax(100) -- sets the health point limit to 100
function Entity:setHealthMax(amount)
if self.components.health then self.components.health.max = amount end
return self
end
--- Defines whether this entity can be destroyed by damage.
--- Defaults to true.
--- Example: entity:setCanBeDestroyed(false) -- prevents the entity from being destroyed by damage
function Entity:setCanBeDestroyed(allow_destroy)
if self.components.health then self.components.health.allow_destruction = allow_destroy end
return self
end
--- Returns whether the entity can be destroyed by damage.
--- Example: entity:getCanBeDestroyed()
function Entity:getCanBeDestroyed()
if self.components.health then return self.components.health.allow_destruction end
return false
end
--- Defines a function to call when this SpaceObject is destroyed by any means.
--- Example:
--- -- Prints to the console window or logging file when this SpaceObject is destroyed
--- obj:onDestroyed(function() print("Object destroyed!") end)
function Entity:onDestroyed(callback)
--TODO: Cases where we do not have hull
if self.components.hull then self.components.hull.on_destruction = callback end
--TODO: Cases where we do not have health
if self.components.health then self.components.health.on_destruction = callback end
return self
end
6 changes: 4 additions & 2 deletions src/ai/ai.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "components/impulse.h"
#include "components/warpdrive.h"
#include "components/jumpdrive.h"
#include "components/health.h"
#include "components/hull.h"
#include "components/beamweapon.h"
#include "components/missiletubes.h"
Expand Down Expand Up @@ -527,8 +528,8 @@ void ShipAI::runOrders()
}
if (bay->flags & DockingBay::Repair)
{
auto hull = owner.getComponent<Hull>();
if (hull && hull->current < hull->max)
auto health = owner.getComponent<Health>();
if (health && health->current < health->max)
allow_undock = false;
}
}
Expand Down Expand Up @@ -837,6 +838,7 @@ sp::ecs::Entity ShipAI::findBestTarget(glm::vec2 position, float radius)
auto owner_position = ot->getPosition();
for(auto entity : sp::CollisionSystem::queryArea(position - glm::vec2(radius, radius), position + glm::vec2(radius, radius)))
{
// Seek only entities with Hull components.
if (!entity.hasComponent<Hull>() || Faction::getRelation(owner, entity) != FactionRelation::Enemy || entity == target)
continue;
if (RadarBlockSystem::isRadarBlockedFrom(owner_position, entity, short_range))
Expand Down
36 changes: 36 additions & 0 deletions src/components/health.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#pragma once

#include "script/callback.h"
#include "systems/damage.h"

// Component for entities that can take damage and be destroyed.
// This component tracks current and max health values for all damageable
// entities, and implements damage and destruction callbacks.
// Entities are typically destroyed if daamaged while at zero health.
// Destructability can be disabled to prevent player ship destruction in LARP
// scenarios or tutorials.
//
// For UI display purposes, player-facing interfaces by default display the
// health of entities ONLY if they have both Health and Hull components.
// Entities that have only Health can be targeted but don't show health values
// in player UI.
class Health
{
public:
float current = 100.0f;
float max = 100.0f;
bool allow_destruction = true;
int damaged_by_flags = (1 << int(DamageType::Energy)) | (1 << int(DamageType::Kinetic));
float damage_indicator = 0.0f; // Visual damage flash timer (1.5s)

sp::script::Callback on_destruction;
sp::script::Callback on_taking_damage;
};

// Component indicates that an entity lacks a hull or health value, but an
// area damage effect (i.e. explosion) in the area still destroys it.
class DestroyedByAreaDamage
{
public:
int damaged_by_flags = (1 << int(DamageType::Energy)) | (1 << int(DamageType::Kinetic));
};
31 changes: 10 additions & 21 deletions src/components/hull.h
Original file line number Diff line number Diff line change
@@ -1,27 +1,16 @@
#pragma once

#include "script/callback.h"
#include "systems/damage.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.
// Marker component to indicate that this entity has a hull and can take hull
// damage. Entity health, presented as hull integrity, is tracked in the Health
// component.
// If an entity has the Hull component, it gains certain ship-like properties:
// - Automatic health regeneration from DockingBay entities with the
// DockingBay::Repair flag (as hull repairs)
// - Can be targeted by AI
// - Can be selected on Relay and Science radars
// - With Health component, display of health values as hull percentage/points
// in user interfaces
class Hull
{
public:
float current = 100.0f;
float max = 100.0f;
bool allow_destruction = true;
int damaged_by_flags = (1 << int(DamageType::Energy)) | (1 << int(DamageType::Kinetic));
float damage_indicator = 0.0f;

sp::script::Callback on_destruction;
sp::script::Callback on_taking_damage;
};

// Not having actual hull, but an explosion in the area will destroy this entity.
class DestroyedByAreaDamage
{
public:
int damaged_by_flags = (1 << int(DamageType::Energy)) | (1 << int(DamageType::Kinetic));
};
3 changes: 2 additions & 1 deletion src/hardware/hardwareController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "playerInfo.h"
#include "ecs/query.h"

#include "components/health.h"
#include "components/hull.h"
#include "components/shields.h"
#include "components/reactor.h"
Expand Down Expand Up @@ -377,7 +378,7 @@ bool HardwareController::getVariableValue(string variable_name, float& value)
value = bool(ship) ? 1.0f : 0.0f;
return true;
}
SHIP_VARIABLE("Hull", Hull, 100.0f * c->current / c->max);
SHIP_VARIABLE("Hull", Health, 100.0f * c->current / c->max);
SHIP_VARIABLE("FrontShield", Shields, c->entries.size() > 0 ? c->entries[0].percentage() : 0.0f);
SHIP_VARIABLE("RearShield", Shields, c->entries.size() > 1 ? c->entries[1].percentage() : 0.0f);
SHIP_VARIABLE("Shield0", Shields, c->entries.size() > 0 ? c->entries[0].percentage() : 0.0f);
Expand Down
8 changes: 8 additions & 0 deletions src/multiplayer/health.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include "multiplayer/health.h"
#include "multiplayer.h"

BASIC_REPLICATION_IMPL(HealthReplication, Health)
BASIC_REPLICATION_FIELD(current);
BASIC_REPLICATION_FIELD(max);
BASIC_REPLICATION_FIELD(damage_indicator);
}
6 changes: 6 additions & 0 deletions src/multiplayer/health.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#pragma once

#include "multiplayer/basic.h"
#include "components/health.h"

BASIC_REPLICATION_CLASS(HealthReplication, Health);
7 changes: 2 additions & 5 deletions src/multiplayer/hull.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,5 @@
#include "multiplayer.h"


BASIC_REPLICATION_IMPL(HullReplication, Hull)
BASIC_REPLICATION_FIELD(current);
BASIC_REPLICATION_FIELD(max);
BASIC_REPLICATION_FIELD(damage_indicator);
}
// Hull is now a marker component with no fields to replicate
EMPTY_REPLICATION_IMPL(HullReplication, Hull)
6 changes: 4 additions & 2 deletions src/playerInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

#include "components/collision.h"
#include "components/impulse.h"
#include "components/health.h"
#include "components/hull.h"
#include "components/customshipfunction.h"
#include "components/shiplog.h"
Expand Down Expand Up @@ -953,8 +954,9 @@ void PlayerInfo::onReceiveClientCommand(int32_t client_id, sp::io::DataBuffer& p
trace.max_size = 10.0;
trace.color = {96, 192, 128, 255};
trace.flags = RadarTrace::LongRange;
auto& hull = p.addComponent<Hull>();
hull.current = hull.max = 1;
auto& health = p.addComponent<Health>();
health.current = health.max = 1;
p.addComponent<Hull>();
p.addComponent<ShareShortRangeRadar>();
auto model = "SensorBuoy/SensorBuoyMKI.model";
auto idx = irandom(1, 3);
Expand Down
5 changes: 3 additions & 2 deletions src/screenComponents/indicatorOverlays.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "components/warpdrive.h"
#include "components/jumpdrive.h"
#include "components/shields.h"
#include "components/health.h"
#include "components/hull.h"
#include "multiplayer_server.h"
#include "i18n.h"
Expand Down Expand Up @@ -80,8 +81,8 @@ void GuiIndicatorOverlays::onDraw(sp::RenderTarget& renderer)
shield_low_warning_overlay->setAlpha(0);
}

if (auto hull = my_spaceship.getComponent<Hull>())
hull_hit_overlay->setAlpha(128 * (hull->damage_indicator / 1.5f));
if (auto health = my_spaceship.getComponent<Health>())
hull_hit_overlay->setAlpha(128 * (health->damage_indicator / 1.5f));
}else{
shield_hit_overlay->setAlpha(0);
shield_low_warning_overlay->setAlpha(0);
Expand Down
9 changes: 6 additions & 3 deletions src/screenComponents/infoDisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "components/reactor.h"
#include "components/collision.h"
#include "components/shields.h"
#include "components/health.h"
#include "components/hull.h"
#include "components/coolant.h"
#include "playerInfo.h"
Expand Down Expand Up @@ -97,10 +98,12 @@ HullInfoDisplay::HullInfoDisplay(GuiContainer* owner, const string& id, float di

void HullInfoDisplay::onUpdate()
{
if (auto hull = my_spaceship.getComponent<Hull>())
// Show Health as Hull, and only if the entity also has Hull.
auto health = my_spaceship.getComponent<Health>();
if (health && my_spaceship.hasComponent<Hull>())
{
setValue(toNearbyIntString(100.0f * hull->current / hull->max) + "%");
if (hull->current < hull->max / 4.0f)
setValue(toNearbyIntString(100.0f * health->current / health->max) + "%");
if (health->current < health->max / 4.0f)
setBackColor(glm::u8vec4(255, 0, 0, 255));
else
setBackColor(glm::u8vec4{255,255,255,255});
Expand Down
Loading
Loading