mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-07-24 12:32:28 +00:00
Health.js cleanup: add tests, add an "IsInjured" function, use this.hitpoints everywhere
Continuation of D1769. Differential Revision: https://code.wildfiregames.com/D1828 This was SVN commit r22298.
This commit is contained in:
@@ -254,7 +254,7 @@ GuiInterface.prototype.GetEntityState = function(player, ent)
|
|||||||
{
|
{
|
||||||
ret.hitpoints = cmpHealth.GetHitpoints();
|
ret.hitpoints = cmpHealth.GetHitpoints();
|
||||||
ret.maxHitpoints = cmpHealth.GetMaxHitpoints();
|
ret.maxHitpoints = cmpHealth.GetMaxHitpoints();
|
||||||
ret.needsRepair = cmpHealth.IsRepairable() && cmpHealth.GetHitpoints() < cmpHealth.GetMaxHitpoints();
|
ret.needsRepair = cmpHealth.IsRepairable() && cmpHealth.IsInjured();
|
||||||
ret.needsHeal = !cmpHealth.IsUnhealable();
|
ret.needsHeal = !cmpHealth.IsUnhealable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,14 @@ Health.prototype.GetMaxHitpoints = function()
|
|||||||
return this.maxHitpoints;
|
return this.maxHitpoints;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {boolean} Whether the units are injured. Dead units are not considered injured.
|
||||||
|
*/
|
||||||
|
Health.prototype.IsInjured = function()
|
||||||
|
{
|
||||||
|
return this.hitpoints > 0 && this.hitpoints < this.GetMaxHitpoints();
|
||||||
|
};
|
||||||
|
|
||||||
Health.prototype.SetHitpoints = function(value)
|
Health.prototype.SetHitpoints = function(value)
|
||||||
{
|
{
|
||||||
// If we're already dead, don't allow resurrection
|
// If we're already dead, don't allow resurrection
|
||||||
@@ -94,7 +102,7 @@ Health.prototype.SetHitpoints = function(value)
|
|||||||
|
|
||||||
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||||
if (cmpRangeManager)
|
if (cmpRangeManager)
|
||||||
cmpRangeManager.SetEntityFlag(this.entity, "injured", this.hitpoints < this.GetMaxHitpoints());
|
cmpRangeManager.SetEntityFlag(this.entity, "injured", this.IsInjured());
|
||||||
|
|
||||||
this.RegisterHealthChanged(old);
|
this.RegisterHealthChanged(old);
|
||||||
};
|
};
|
||||||
@@ -107,8 +115,7 @@ Health.prototype.IsRepairable = function()
|
|||||||
Health.prototype.IsUnhealable = function()
|
Health.prototype.IsUnhealable = function()
|
||||||
{
|
{
|
||||||
return this.template.Unhealable == "true" ||
|
return this.template.Unhealable == "true" ||
|
||||||
this.GetHitpoints() <= 0 ||
|
this.hitpoints <= 0 || !this.IsInjured();
|
||||||
this.GetHitpoints() >= this.GetMaxHitpoints();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Health.prototype.GetIdleRegenRate = function()
|
Health.prototype.GetIdleRegenRate = function()
|
||||||
@@ -144,8 +151,8 @@ Health.prototype.CheckRegenTimer = function()
|
|||||||
{
|
{
|
||||||
// check if we need a timer
|
// check if we need a timer
|
||||||
if (this.GetRegenRate() == 0 && this.GetIdleRegenRate() == 0 ||
|
if (this.GetRegenRate() == 0 && this.GetIdleRegenRate() == 0 ||
|
||||||
this.GetHitpoints() == this.GetMaxHitpoints() && this.GetRegenRate() >= 0 && this.GetIdleRegenRate() >= 0 ||
|
!this.IsInjured() && this.GetRegenRate() >= 0 && this.GetIdleRegenRate() >= 0 ||
|
||||||
this.GetHitpoints() == 0)
|
this.hitpoints == 0)
|
||||||
{
|
{
|
||||||
// we don't need a timer, disable if one exists
|
// we don't need a timer, disable if one exists
|
||||||
if (this.regenTimer)
|
if (this.regenTimer)
|
||||||
@@ -199,7 +206,7 @@ Health.prototype.Reduce = function(amount)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we are not marked as injured, do it now
|
// If we are not marked as injured, do it now
|
||||||
if (this.hitpoints == this.GetMaxHitpoints())
|
if (!this.IsInjured())
|
||||||
{
|
{
|
||||||
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||||
if (cmpRangeManager)
|
if (cmpRangeManager)
|
||||||
@@ -256,7 +263,7 @@ Health.prototype.Increase = function(amount)
|
|||||||
if (cmpFogging)
|
if (cmpFogging)
|
||||||
cmpFogging.Activate();
|
cmpFogging.Activate();
|
||||||
|
|
||||||
if (this.hitpoints == this.GetMaxHitpoints())
|
if (!this.IsInjured())
|
||||||
return { "old": this.hitpoints, "new": this.hitpoints };
|
return { "old": this.hitpoints, "new": this.hitpoints };
|
||||||
|
|
||||||
// If we're already dead, don't allow resurrection
|
// If we're already dead, don't allow resurrection
|
||||||
@@ -266,7 +273,7 @@ Health.prototype.Increase = function(amount)
|
|||||||
let old = this.hitpoints;
|
let old = this.hitpoints;
|
||||||
this.hitpoints = Math.min(this.hitpoints + amount, this.GetMaxHitpoints());
|
this.hitpoints = Math.min(this.hitpoints + amount, this.GetMaxHitpoints());
|
||||||
|
|
||||||
if (this.hitpoints == this.GetMaxHitpoints())
|
if (!this.IsInjured())
|
||||||
{
|
{
|
||||||
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||||
if (cmpRangeManager)
|
if (cmpRangeManager)
|
||||||
@@ -350,7 +357,7 @@ Health.prototype.UpdateActor = function()
|
|||||||
{
|
{
|
||||||
if (!this.template.DamageVariants)
|
if (!this.template.DamageVariants)
|
||||||
return;
|
return;
|
||||||
let ratio = this.GetHitpoints() / this.GetMaxHitpoints();
|
let ratio = this.hitpoints / this.GetMaxHitpoints();
|
||||||
let newDamageVariant = "alive";
|
let newDamageVariant = "alive";
|
||||||
if (ratio > 0)
|
if (ratio > 0)
|
||||||
{
|
{
|
||||||
@@ -386,7 +393,7 @@ Health.prototype.OnValueModification = function(msg)
|
|||||||
let newMaxHitpoints = ApplyValueModificationsToEntity("Health/Max", +this.template.Max, this.entity);
|
let newMaxHitpoints = ApplyValueModificationsToEntity("Health/Max", +this.template.Max, this.entity);
|
||||||
if (oldMaxHitpoints != newMaxHitpoints)
|
if (oldMaxHitpoints != newMaxHitpoints)
|
||||||
{
|
{
|
||||||
let newHitpoints = this.GetHitpoints() * newMaxHitpoints/oldMaxHitpoints;
|
let newHitpoints = this.hitpoints * newMaxHitpoints/oldMaxHitpoints;
|
||||||
this.maxHitpoints = newMaxHitpoints;
|
this.maxHitpoints = newMaxHitpoints;
|
||||||
this.SetHitpoints(newHitpoints);
|
this.SetHitpoints(newHitpoints);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1426,7 +1426,7 @@ UnitAI.prototype.UnitFsmSpec = {
|
|||||||
var cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity);
|
var cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity);
|
||||||
var cmpHealth = Engine.QueryInterface(this.isGuardOf, IID_Health);
|
var cmpHealth = Engine.QueryInterface(this.isGuardOf, IID_Health);
|
||||||
if (cmpIdentity && cmpIdentity.HasClass("Support") &&
|
if (cmpIdentity && cmpIdentity.HasClass("Support") &&
|
||||||
cmpHealth && cmpHealth.GetHitpoints() < cmpHealth.GetMaxHitpoints())
|
cmpHealth && cmpHealth.IsInjured())
|
||||||
{
|
{
|
||||||
if (this.CanHeal(this.isGuardOf))
|
if (this.CanHeal(this.isGuardOf))
|
||||||
this.PushOrderFront("Heal", { "target": this.isGuardOf, "force": false });
|
this.PushOrderFront("Heal", { "target": this.isGuardOf, "force": false });
|
||||||
@@ -1716,7 +1716,7 @@ UnitAI.prototype.UnitFsmSpec = {
|
|||||||
{
|
{
|
||||||
// if nothing better to do, check if the guarded needs to be healed or repaired
|
// if nothing better to do, check if the guarded needs to be healed or repaired
|
||||||
var cmpHealth = Engine.QueryInterface(this.isGuardOf, IID_Health);
|
var cmpHealth = Engine.QueryInterface(this.isGuardOf, IID_Health);
|
||||||
if (cmpHealth && (cmpHealth.GetHitpoints() < cmpHealth.GetMaxHitpoints()))
|
if (cmpHealth && cmpHealth.IsInjured())
|
||||||
{
|
{
|
||||||
if (this.CanHeal(this.isGuardOf))
|
if (this.CanHeal(this.isGuardOf))
|
||||||
this.PushOrderFront("Heal", { "target": this.isGuardOf, "force": false });
|
this.PushOrderFront("Heal", { "target": this.isGuardOf, "force": false });
|
||||||
|
|||||||
@@ -0,0 +1,150 @@
|
|||||||
|
Engine.LoadComponentScript("interfaces/TechnologyManager.js");
|
||||||
|
Engine.LoadComponentScript("interfaces/AuraManager.js");
|
||||||
|
Engine.LoadHelperScript("Player.js");
|
||||||
|
Engine.LoadHelperScript("ValueModification.js");
|
||||||
|
|
||||||
|
Engine.LoadHelperScript("Sound.js");
|
||||||
|
Engine.LoadComponentScript("interfaces/DeathDamage.js");
|
||||||
|
|
||||||
|
Engine.LoadComponentScript("interfaces/Health.js");
|
||||||
|
Engine.LoadComponentScript("Health.js");
|
||||||
|
|
||||||
|
const entity_id = 5;
|
||||||
|
const corpse_id = entity_id + 1;
|
||||||
|
|
||||||
|
const health_template = {
|
||||||
|
"Max": 50,
|
||||||
|
"RegenRate": 0,
|
||||||
|
"IdleRegenRate": 0,
|
||||||
|
"DeathType": "corpse",
|
||||||
|
"Unhealable": false
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var injured_flag = false;
|
||||||
|
var corpse_entity;
|
||||||
|
|
||||||
|
function setEntityUp()
|
||||||
|
{
|
||||||
|
let cmpHealth = ConstructComponent(entity_id, "Health", health_template);
|
||||||
|
|
||||||
|
AddMock(entity_id, IID_DeathDamage, {
|
||||||
|
"CauseDeathDamage": () => {}
|
||||||
|
});
|
||||||
|
AddMock(entity_id, IID_Position, {
|
||||||
|
"IsInWorld": () => true,
|
||||||
|
"GetPosition": () => ({ "x": 0, "z": 0 }),
|
||||||
|
"GetRotation": () => ({ "x": 0, "y": 0, "z": 0 })
|
||||||
|
});
|
||||||
|
AddMock(entity_id, IID_Ownership, {
|
||||||
|
"GetOwner": () => 1
|
||||||
|
});
|
||||||
|
AddMock(entity_id, IID_Visual, {
|
||||||
|
"GetActorSeed": () => 1
|
||||||
|
});
|
||||||
|
AddMock(SYSTEM_ENTITY, IID_TemplateManager, {
|
||||||
|
"GetCurrentTemplateName": () => "test"
|
||||||
|
});
|
||||||
|
|
||||||
|
AddMock(SYSTEM_ENTITY, IID_RangeManager, {
|
||||||
|
"SetEntityFlag": (ent, flag, value) => (injured_flag = value)
|
||||||
|
});
|
||||||
|
|
||||||
|
return cmpHealth;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cmpHealth = setEntityUp();
|
||||||
|
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.GetHitpoints(), 50);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.GetMaxHitpoints(), 50);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.IsInjured(), false);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.IsUnhealable(), true);
|
||||||
|
|
||||||
|
var change = cmpHealth.Reduce(25);
|
||||||
|
TS_ASSERT_EQUALS(injured_flag, true);
|
||||||
|
|
||||||
|
TS_ASSERT_EQUALS(change.killed, false);
|
||||||
|
TS_ASSERT_EQUALS(change.change, -25);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.GetHitpoints(), 25);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.GetMaxHitpoints(), 50);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.IsInjured(), true);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.IsUnhealable(), false);
|
||||||
|
|
||||||
|
change = cmpHealth.Increase(25);
|
||||||
|
TS_ASSERT_EQUALS(injured_flag, false);
|
||||||
|
|
||||||
|
TS_ASSERT_EQUALS(change.new, 50);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.GetHitpoints(), 50);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.GetMaxHitpoints(), 50);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.IsInjured(), false);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.IsUnhealable(), true);
|
||||||
|
|
||||||
|
// Check death.
|
||||||
|
Engine.AddLocalEntity = function(template) {
|
||||||
|
corpse_entity = template;
|
||||||
|
|
||||||
|
AddMock(corpse_id, IID_Position, {
|
||||||
|
"JumpTo": () => {},
|
||||||
|
"SetYRotation": () => {},
|
||||||
|
"SetXZRotation": () => {},
|
||||||
|
});
|
||||||
|
AddMock(corpse_id, IID_Ownership, {
|
||||||
|
"SetOwner": () => {},
|
||||||
|
});
|
||||||
|
AddMock(corpse_id, IID_Visual, {
|
||||||
|
"SetActorSeed": () => {},
|
||||||
|
"SelectAnimation": () => {},
|
||||||
|
});
|
||||||
|
return corpse_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
change = cmpHealth.Reduce(50);
|
||||||
|
|
||||||
|
// Assert we create a corpse with the proper template.
|
||||||
|
TS_ASSERT_EQUALS(corpse_entity, "corpse|test");
|
||||||
|
|
||||||
|
// Check that we are not marked as injured.
|
||||||
|
TS_ASSERT_EQUALS(injured_flag, false);
|
||||||
|
|
||||||
|
TS_ASSERT_EQUALS(change.killed, true);
|
||||||
|
TS_ASSERT_EQUALS(change.change, -50);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.GetHitpoints(), 0);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.GetMaxHitpoints(), 50);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.IsInjured(), false);
|
||||||
|
|
||||||
|
// Check that we can't be revived once dead.
|
||||||
|
change = cmpHealth.Increase(25);
|
||||||
|
TS_ASSERT_EQUALS(change.new, 0);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.GetHitpoints(), 0);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.GetMaxHitpoints(), 50);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.IsInjured(), false);
|
||||||
|
|
||||||
|
// Check that we can't die twice.
|
||||||
|
change = cmpHealth.Reduce(50);
|
||||||
|
TS_ASSERT_EQUALS(change.killed, false);
|
||||||
|
TS_ASSERT_EQUALS(change.change, 0);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.GetHitpoints(), 0);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.GetMaxHitpoints(), 50);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.IsInjured(), false);
|
||||||
|
|
||||||
|
cmpHealth = setEntityUp();
|
||||||
|
|
||||||
|
// Check that we still die with > Max HP of damage.
|
||||||
|
change = cmpHealth.Reduce(60);
|
||||||
|
TS_ASSERT_EQUALS(change.killed, true);
|
||||||
|
TS_ASSERT_EQUALS(change.change, -50);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.GetHitpoints(), 0);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.GetMaxHitpoints(), 50);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.IsInjured(), false);
|
||||||
|
|
||||||
|
cmpHealth = setEntityUp();
|
||||||
|
|
||||||
|
// Check that increasing by more than required puts us at the max HP
|
||||||
|
change = cmpHealth.Reduce(30);
|
||||||
|
change = cmpHealth.Increase(30);
|
||||||
|
TS_ASSERT_EQUALS(injured_flag, false);
|
||||||
|
TS_ASSERT_EQUALS(change.new, 50);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.GetHitpoints(), 50);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.GetMaxHitpoints(), 50);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.IsInjured(), false);
|
||||||
|
TS_ASSERT_EQUALS(cmpHealth.IsUnhealable(), true);
|
||||||
Reference in New Issue
Block a user