Implement buttons for up to 10 heroes. Patch by Clockwork-Muse, fixes #3000.

This was SVN commit r18361.
This commit is contained in:
elexis 2016-06-11 13:46:04 +00:00
parent 759aaa2264
commit d7d1d8ccb5
2 changed files with 129 additions and 60 deletions

View file

@ -143,9 +143,9 @@ var g_ShowGuarded = false;
var g_AdditionalHighlight = [];
/**
* Blink the hero selection if that entity has lost health since the last turn.
* Display data of the current players heroes.
*/
var g_PreviousHeroHitPoints;
var g_Heroes = [];
/**
* Unit classes to be checked for the idle-worker-hotkey.
@ -269,6 +269,9 @@ function init(initData, hotloadData)
gameSpeed.onSelectionChange = function() { changeGameSpeed(+this.list_data[this.selected]); };
initMenuPosition();
for (let slot in Engine.GetGUIObjectByName("unitHeroPanel").children)
initGUIHeroes(slot);
// Populate player selection dropdown
let playerNames = [translate("Observer")];
let playerIDs = [-1];
@ -320,6 +323,29 @@ function initHotkeyTooltips()
"session.fulltradeswap");
}
function initGUIHeroes(slot)
{
let button = Engine.GetGUIObjectByName("unitHeroButton[" + slot + "]");
button.onPress = function()
{
let hero = g_Heroes.find(hero => hero.slot !== undefined && hero.slot == slot);
if (!hero)
return;
if (!Engine.HotkeyIsPressed("selection.add"))
g_Selection.reset();
g_Selection.addList([hero.ent]);
};
button.onDoublePress = function() {
let hero = g_Heroes.find(hero => hero.slot !== undefined && hero.slot == slot);
if (hero)
selectAndMoveTo(getEntityOrHolder(hero.ent));
};
}
function initializeMusic()
{
initMusic();
@ -726,7 +752,9 @@ function updateGUIObjects()
if (g_ShowGuarding || g_ShowGuarded)
updateAdditionalHighlight();
updateHero();
updateHeroes();
displayHeroes();
updateGroups();
updateDebug();
updatePlayerDisplay();
@ -802,67 +830,106 @@ function updateGUIStatusBar(nameOfBar, points, maxPoints, direction)
}
function updateHero()
function updateHeroes()
{
let unitHeroPanel = Engine.GetGUIObjectByName("unitHeroPanel");
let heroButton = Engine.GetGUIObjectByName("unitHeroButton");
let playerState = GetSimState().players[g_ViewedPlayer];
if (!playerState || playerState.heroes.length <= 0)
let heroes = playerState ? playerState.heroes : [];
g_Heroes = g_Heroes.filter(hero => heroes.find(ent => ent == hero.ent));
for (let ent of heroes)
{
g_PreviousHeroHitPoints = undefined;
unitHeroPanel.hidden = true;
return;
let heroState = GetExtendedEntityState(ent);
let template = GetTemplateData(heroState.template);
let hero = g_Heroes.find(hero => ent == hero.ent);
if (!hero)
{
hero = {
"ent": ent,
"tooltip": undefined,
"sprite": "stretched:session/portraits/" + template.icon,
"maxHitpoints": undefined,
"currentHitpoints": heroState.hitpoints,
"previousHitpoints": undefined
};
g_Heroes.push(hero);
}
hero.tooltip = createHeroTooltip(heroState, template);
hero.previousHitpoints = hero.currentHitpoints;
hero.currentHitpoints = heroState.hitpoints;
hero.maxHitpoints = heroState.maxHitpoints;
}
}
let heroImage = Engine.GetGUIObjectByName("unitHeroImage");
let heroState = GetExtendedEntityState(playerState.heroes[0]);
let template = GetTemplateData(heroState.template);
heroImage.sprite = "stretched:session/portraits/" + template.icon;
let hero = playerState.heroes[0];
function createHeroTooltip(heroState, template)
{
let tooltip = "[font=\"sans-bold-16\"]" + template.name.specific + "[/font]" + "\n" +
sprintf(translate("%(label)s %(current)s / %(max)s"), {
"label": "[font=\"sans-bold-13\"]" + translate("Health:") + "[/font]",
"current": Math.ceil(heroState.hitpoints),
"max": Math.ceil(heroState.maxHitpoints)
});
heroButton.onpress = function()
{
if (!Engine.HotkeyIsPressed("selection.add"))
g_Selection.reset();
g_Selection.addList([hero]);
};
heroButton.ondoublepress = function() { selectAndMoveTo(getEntityOrHolder(hero)); };
unitHeroPanel.hidden = false;
// Setup tooltip
let tooltip = "[font=\"sans-bold-16\"]" + template.name.specific + "[/font]";
let healthLabel = "[font=\"sans-bold-13\"]" + translate("Health:") + "[/font]";
tooltip += "\n" + sprintf(translate("%(label)s %(current)s / %(max)s"), {
"label": healthLabel,
"current": Math.ceil(heroState.hitpoints),
"max": Math.ceil(heroState.maxHitpoints)
});
if (heroState.attack)
tooltip += "\n" + getAttackTooltip(heroState);
tooltip += "\n" + getArmorTooltip(heroState.armour);
if (template.tooltip)
tooltip += "\n" + template.tooltip;
heroButton.tooltip = tooltip;
return tooltip;
}
// update heros health bar
updateGUIStatusBar("heroHealthBar", heroState.hitpoints, heroState.maxHitpoints);
function displayHeroes()
{
let buttons = Engine.GetGUIObjectByName("unitHeroPanel").children;
let heroHP = {
"hitpoints": heroState.hitpoints,
"player": g_ViewedPlayer
};
buttons.forEach((button, slot) =>
{
if (button.hidden || g_Heroes.some(hero => hero.slot !== undefined && hero.slot == slot))
return;
if (!g_PreviousHeroHitPoints)
g_PreviousHeroHitPoints = heroHP;
button.hidden = true;
stopColorFade("heroHitOverlay[" + slot + "]");
// if the health of the hero changed since the last update, trigger the animation
if (g_PreviousHeroHitPoints.player == heroHP.player && g_PreviousHeroHitPoints.hitpoints > heroHP.hitpoints)
startColorFade("heroHitOverlay", 100, 0, colorFade_attackUnit, true, smoothColorFadeRestart_attackUnit);
});
g_PreviousHeroHitPoints = heroHP;
// The slot identifies the button, displayIndex determines its position.
for (let displayIndex = 0; displayIndex < Math.min(g_Heroes.length, buttons.length); ++displayIndex)
{
let hero = g_Heroes[displayIndex];
// Find the first unused slot if new, otherwise reuse previous.
let slot = hero.slot === undefined ?
buttons.findIndex(button => button.hidden) :
hero.slot;
let heroButton = Engine.GetGUIObjectByName("unitHeroButton[" + slot + "]");
heroButton.tooltip = hero.tooltip;
updateGUIStatusBar("heroHealthBar[" + slot + "]", hero.currentHitpoints, hero.maxHitpoints);
if (hero.slot === undefined)
{
let heroImage = Engine.GetGUIObjectByName("unitHeroImage[" + slot + "]");
heroImage.sprite = hero.sprite;
heroButton.hidden = false;
hero.slot = slot;
}
// If the health of the hero changed since the last update, trigger the animation.
if (hero.previousHitpoints > hero.currentHitpoints)
startColorFade("heroHitOverlay[" + slot + "]", 100, 0,
colorFade_attackUnit, true, smoothColorFadeRestart_attackUnit);
// TODO: Instead of instant position changes, animate button movement.
setPanelObjectPosition(heroButton, displayIndex, buttons.length);
}
}
function updateGroups()

View file

@ -2,20 +2,22 @@
<object
name="unitHeroPanel"
size="0 36 50 93"
hidden="true"
hidden="false"
>
<object name="unitHeroButton" size="0 0 50 50" type="button" style="iconButton"
tooltip_style="sessionToolTip">
<object name="unitHeroImage" size="5 5 100%-5 100%-5" type="image" ghost="true"/>
<object name="heroHitOverlay" hidden="true" type="image" ghost="true" size="5 5 100%-5 100%-5"/>
</object>
<!-- Hero Health bar -->
<object size="3 100%-7 100%-3 100%-2" name="heroHealthSection" ghost="true">
<object size="0 0 100% 5" name="heroHealth" 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"/>
<object type="image" sprite="healthForeground" ghost="true" name="heroHealthBar"/>
<object type="image" sprite="statsBarShaderHorizontal" ghost="true"/>
<repeat count="10" var="n">
<object name="unitHeroButton[n]" size="0 0 50 50" type="button" hidden="true" style="iconButton" tooltip_style="sessionToolTip">
<object name="unitHeroImage[n]" size="5 5 100%-5 100%-5" type="image" ghost="true"/>
<object name="heroHitOverlay[n]" hidden="true" type="image" ghost="true" size="5 5 100%-5 100%-5"/>
<!-- Hero Health bar -->
<object size="3 100%-7 100%-3 100%-2" name="heroHealthSection[n]" ghost="true">
<object size="0 0 100% 5" name="heroHealth[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"/>
<object type="image" sprite="healthForeground" ghost="true" name="heroHealthBar[n]"/>
<object type="image" sprite="statsBarShaderHorizontal" ghost="true"/>
</object>
</object>
</object>
</object>
</repeat>
</object>