1
0
forked from 0ad/0ad

Remove health component from relics.

Since relics ought to be undestroyable, a health component makes no
sense. This makes that the Invulnerability-flag can be removed and
relics can be captured again (after 0f91c5ac61#inline-5236).

Differential Revision: D1268
Original patch by: @temple
Reviewed by: @wraitii
Comments by: @bb, @elexis
Fixes #5007, #5847, 0f91c5ac61#inline-5236

This was SVN commit r24327.
This commit is contained in:
Freagarach 2020-12-06 07:22:51 +00:00
parent 40f3a967d9
commit 2e79c0a177
9 changed files with 120 additions and 32 deletions

View File

@ -159,6 +159,18 @@ function getCurrentHealthTooltip(entState, label)
});
}
function getCurrentCaptureTooltip(entState, label)
{
if (!entState.maxCapturePoints)
return "";
return sprintf(translate("%(captureLabel)s %(current)s / %(max)s"), {
"captureLabel": headerFont(label || translate("Capture points:")),
"current": Math.round(entState.capturePoints[entState.player]),
"max": Math.round(entState.maxCapturePoints)
});
}
/**
* Converts an resistance level into the actual reduction percentage.
*/
@ -184,10 +196,10 @@ function getResistanceTooltip(template)
if (template.resistance.ApplyStatus)
details.push(getStatusEffectsResistanceTooltip(template.resistance.ApplyStatus));
return sprintf(translate("%(label)s\n%(details)s"), {
return details.length ? sprintf(translate("%(label)s\n%(details)s"), {
"label": headerFont(translate("Resistance:")),
"details": g_Indent + details.join("\n" + g_Indent)
});
}) : "";
}
function getDamageResistanceTooltip(resistanceTypeTemplate)

View File

@ -1,14 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<object name="panelEntityButtons" size="0 36 50 93">
<object name="panelEntityButtons" size="2 38 50 93">
<!-- Displays buttons for the most important units like heroes and relics -->
<repeat count="19" var="n">
<object name="panelEntityButton[n]" size="0 0 50 50" type="button" hidden="true" style="iconButton" tooltip_style="sessionToolTip">
<!-- Placeholders storing the position for the bars -->
<object size="3 100%-5 100%-3 100%-2" name="panelEntitySectionPosTop[n]" hidden="true"/>
<object size="3 100% 100%-3 100%+5" name="panelEntitySectionPosBottom[n]" hidden="true"/>
<object name="panelEntityBackground[n]" type="image" ghost="true" size="1 1 100%-1 100%-1"/>
<object name="panelEntityImage[n]" size="5 5 100%-5 100%-5" type="image" ghost="true"/>
<object name="panelEntityHitOverlay[n]" hidden="true" type="image" ghost="true" size="5 5 100%-5 100%-5"/>
<!-- Health bar -->
<object size="3 100%-7 100%-3 100%-2" name="panelEntityHealthSection[n]" ghost="true">
<object size="3 100%-5 100%-3 100%-2" name="panelEntityHealthSection[n]" ghost="true">
<object size="0 0 100% 5" name="panelEntityHealth[n]" type="image" ghost="true">
<object type="image" sprite="barBorder" ghost="true" size="-1 -1 100%+1 100%+1"/>
<object type="image" sprite="healthBackground" ghost="true"/>
@ -17,6 +22,17 @@
</object>
</object>
<!-- Capture bar -->
<object size="3 100% 100%-3 100%+5" name="panelEntityCaptureSection[n]" ghost="true">
<object size="0 0 100% 5" name="panelEntityCapture[n]" type="image" ghost="true">
<object type="image" sprite="barBorder" ghost="true" size="-1 -1 100%+1 100%+1"/>
<repeat count="9" var="m">
<object type="image" ghost="true" name="panelEntityCaptureBar[n][m]" hidden="true"/>
</repeat>
<object type="image" sprite="statsBarShaderHorizontal" ghost="true"/>
</object>
</object>
</object>
</repeat>
</object>

View File

@ -1,6 +1,6 @@
/**
* This class sets up a shortcut to a specific entity in the GUI panel.
* The button shows the portrait a tooltip with state information and a health bar.
* The button shows the portrait a tooltip with state information and a health and/or capture bar.
* Clicking the button selects and jumps to to the entity.
*/
class PanelEntity
@ -9,6 +9,7 @@ class PanelEntity
{
this.selection = selection;
this.hitpoints = undefined;
this.capturePoints = undefined;
/**
* Public property
@ -22,6 +23,7 @@ class PanelEntity
this.overlayName = "panelEntityHitOverlay[" + buttonID + "]";
this.panelEntityHealthBar = Engine.GetGUIObjectByName("panelEntityHealthBar[" + buttonID + "]");
this.panelEntityCaptureBar = Engine.GetGUIObjectByName("panelEntityCapture[" + buttonID + "]");
this.panelEntButton = Engine.GetGUIObjectByName("panelEntityButton[" + buttonID + "]");
this.panelEntButton.onPress = this.onPress.bind(this);
this.panelEntButton.onDoublePress = this.onDoublePress.bind(this);
@ -31,6 +33,17 @@ class PanelEntity
let template = GetTemplateData(entityState.template);
this.nameTooltip = setStringTags(template.name.specific, this.NameTags) + "\n";
Engine.GetGUIObjectByName("panelEntityHealthSection[" + buttonID + "]").hidden = !entityState.hitpoints;
let captureSection = Engine.GetGUIObjectByName("panelEntityCaptureSection[" + buttonID + "]");
captureSection.hidden = !entityState.capturePoints;
if (entityState.capturePoints)
{
this.capturePoints = entityState.capturePoints;
if (!entityState.hitpoints)
captureSection.size = Engine.GetGUIObjectByName("panelEntitySectionPosTop[" + buttonID + "]").size;
}
Engine.GetGUIObjectByName("panelEntityImage[" + buttonID + "]").sprite =
"stretched:" + this.PortraitDirectory + template.icon;
}
@ -48,6 +61,18 @@ class PanelEntity
setPanelObjectPosition(this.panelEntButton, i, Infinity);
let entityState = GetEntityState(this.entityID);
this.updateHitpointsBar(entityState);
this.updateCapturePointsBar(entityState);
this.panelEntButton.tooltip =
this.nameTooltip +
this.Tooltips.map(tooltip => tooltip(entityState)).filter(tip => tip).join("\n");
}
updateHitpointsBar(entityState)
{
if (!entityState.hitpoints)
return;
if (this.hitpoints != entityState.hitpoints)
{
@ -55,16 +80,44 @@ class PanelEntity
size.rright = 100 * entityState.hitpoints / entityState.maxHitpoints;
this.panelEntityHealthBar.size = size;
}
this.panelEntButton.tooltip =
this.nameTooltip +
this.Tooltips.map(tooltip => tooltip(entityState)).filter(tip => tip).join("\n");
if (this.hitpoints > entityState.hitpoints)
startColorFade(this.overlayName, 100, 0, colorFade_attackUnit, true, smoothColorFadeRestart_attackUnit);
if (entityState.hitpoints < this.hitpoints)
this.onAttacked();
this.hitpoints = entityState.hitpoints;
}
updateCapturePointsBar(entityState)
{
if (!entityState.capturePoints)
return;
let playerParts = this.panelEntityCaptureBar.children;
let setCaptureBarPart = function(player, startSize) {
let captureBar = playerParts[player];
let size = captureBar.size;
size.rleft = startSize;
size.rright = startSize + 100 * Math.max(0, Math.min(1, entityState.capturePoints[player] / entityState.maxCapturePoints));
captureBar.size = size;
captureBar.sprite = "color:" + g_DiplomacyColors.getPlayerColor(player, 128);
captureBar.hidden = false;
return size.rright;
};
let size = setCaptureBarPart(entityState.player, 0);
for (let i in entityState.capturePoints)
if (i != entityState.player)
size = setCaptureBarPart(i, size);
if (entityState.capturePoints[entityState.player] < this.capturePoints[entityState.player])
this.onAttacked();
this.capturePoints = entityState.capturePoints;
}
onAttacked()
{
startColorFade(this.overlayName, 100, 0, colorFade_attackUnit, true, smoothColorFadeRestart_attackUnit);
}
onPress()
{
if (!Engine.HotkeyIsPressed("selection.add"))
@ -85,6 +138,7 @@ PanelEntity.prototype.PortraitDirectory = "session/portraits/";
PanelEntity.prototype.Tooltips = [
getCurrentHealthTooltip,
getCurrentCaptureTooltip,
getAttackTooltip,
getResistanceTooltip,
getEntityTooltip,

View File

@ -120,6 +120,7 @@ function displaySingle(entState)
let showHealth = entState.hitpoints;
let showResource = entState.resourceSupply;
let showCapture = entState.capturePoints;
let healthSection = Engine.GetGUIObjectByName("healthSection");
let captureSection = Engine.GetGUIObjectByName("captureSection");
@ -145,11 +146,13 @@ function displaySingle(entState)
captureSection.size = showResource ? sectionPosMiddle.size : sectionPosBottom.size;
resourceSection.size = showResource ? sectionPosBottom.size : sectionPosMiddle.size;
}
else
else if (showResource)
{
captureSection.size = sectionPosBottom.size;
resourceSection.size = sectionPosTop.size;
}
else if (showCapture)
captureSection.size = sectionPosTop.size;
// CapturePoints
captureSection.hidden = !entState.capturePoints;

View File

@ -155,7 +155,7 @@ var g_UnitActions =
},
"getActionInfo": function(entState, targetState)
{
if (!entState.attack || !targetState.hitpoints)
if (!entState.attack || !targetState.capturePoints)
return false;
return {

View File

@ -20,9 +20,6 @@ Trigger.prototype.InitCaptureTheRelic = function()
{
this.relics[i] = TriggerHelper.SpawnUnits(pickRandom(potentialSpawnPoints), catafalqueTemplates[i], 1, 0)[0];
let cmpResistance = Engine.QueryInterface(this.relics[i], IID_Resistance);
cmpResistance.SetInvulnerability(true);
let cmpPositionRelic = Engine.QueryInterface(this.relics[i], IID_Position);
cmpPositionRelic.SetYRotation(randomAngle());
}

View File

@ -124,7 +124,7 @@ Resistance.prototype.GetFullResistance = function()
Resistance.prototype.GetResistanceOfForm = function(entityForm)
{
let ret = {};
let template = this.template[entityForm];
let template = this.template && this.template[entityForm];
if (!template)
return ret;

View File

@ -384,13 +384,7 @@ UnitAI.prototype.UnitFsmSpec = {
},
"Order.Attack": function(msg) {
if (!this.TargetIsAlive(this.order.data.target))
{
this.FinishOrder();
return;
}
var type = this.GetBestAttackAgainst(this.order.data.target, this.order.data.allowCapture);
let type = this.GetBestAttackAgainst(this.order.data.target, this.order.data.allowCapture);
if (!type)
{
// Oops, we can't attack at all
@ -743,7 +737,7 @@ UnitAI.prototype.UnitFsmSpec = {
if (!this.CheckFormationTargetAttackRange(target))
{
if (this.TargetIsAlive(target) && this.CheckTargetVisible(target))
if (this.CanAttack(target) && this.CheckTargetVisible(target))
{
this.SetNextState("COMBAT.APPROACHING");
return;
@ -882,7 +876,7 @@ UnitAI.prototype.UnitFsmSpec = {
// TODO: on what should we base this range?
if (!this.CheckTargetRangeExplicit(msg.data.target, 0, 10))
{
if (!this.TargetIsAlive(msg.data.target) || !this.CheckTargetVisible(msg.data.target))
if (!this.CheckTargetVisible(msg.data.target))
this.FinishOrder();
else
// Out of range; move there in formation
@ -1135,7 +1129,7 @@ UnitAI.prototype.UnitFsmSpec = {
let allowCapture = this.order.data.allowCapture;
if (!this.CheckFormationTargetAttackRange(target))
{
if (this.TargetIsAlive(target) && this.CheckTargetVisible(target))
if (this.CanAttack(target) && this.CheckTargetVisible(target))
{
this.SetNextState("COMBAT.APPROACHING");
return true;
@ -1157,7 +1151,7 @@ UnitAI.prototype.UnitFsmSpec = {
let allowCapture = this.order.data.allowCapture;
if (!this.CheckFormationTargetAttackRange(target))
{
if (this.TargetIsAlive(target) && this.CheckTargetVisible(target))
if (this.CanAttack(target) && this.CheckTargetVisible(target))
{
this.SetNextState("COMBAT.APPROACHING");
return;
@ -1396,7 +1390,7 @@ UnitAI.prototype.UnitFsmSpec = {
}
// if we already are targeting another unit still alive, finish with it first
if (this.order && (this.order.type == "WalkAndFight" || this.order.type == "Attack"))
if (this.order.data.target != msg.data.attacker && this.TargetIsAlive(msg.data.attacker))
if (this.order.data.target != msg.data.attacker && this.CanAttack(msg.data.attacker))
return;
var cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity);
@ -1665,7 +1659,7 @@ UnitAI.prototype.UnitFsmSpec = {
},
"Timer": function(msg) {
if (!this.TargetIsAlive(this.isGuardOf))
if (!this.ShouldGuard(this.isGuardOf))
{
this.FinishOrder();
return;
@ -1707,7 +1701,7 @@ UnitAI.prototype.UnitFsmSpec = {
},
"Timer": function(msg) {
if (!this.TargetIsAlive(this.isGuardOf))
if (!this.ShouldGuard(this.isGuardOf))
{
this.FinishOrder();
return;
@ -5187,6 +5181,16 @@ UnitAI.prototype.Guard = function(target, queued)
this.AddOrder("Guard", { "target": target, "force": false }, queued);
};
/**
* @return {boolean} - Whether it makes sense to guard the given entity.
*/
UnitAI.prototype.ShouldGuard = function(target)
{
return this.TargetIsAlive(target) ||
Engine.QueryInterface(target, IID_Capturable) ||
Engine.QueryInterface(target, IID_StatusEffectsReceiver);
};
UnitAI.prototype.AddGuard = function(target)
{
if (!this.CanGuard())

View File

@ -10,6 +10,7 @@
<Height>2.0</Height>
<Square width="5.0" depth="12.0"/>
</Footprint>
<Health disable=""/>
<Identity>
<Classes datatype="tokens">-Organic -ConquestCritical</Classes>
<VisibleClasses datatype="tokens">Relic</VisibleClasses>
@ -26,6 +27,7 @@
<Position>
<Anchor>pitch-roll</Anchor>
</Position>
<Resistance replace=""/>
<ResourceGatherer disable=""/>
<Selectable>
<Overlay>