Ticket #3000: heropanel.patch

File heropanel.patch, 8.7 KB (added by Stephen Imhoff, 8 years ago)
  • binaries/data/mods/public/gui/session/session.js

    From 9f0fbc4cef08f4fff7bccf70e3714e2da9ed62d4 Mon Sep 17 00:00:00 2001
    From: "Stephen A. Imhoff" <clockwork-muse@outlook.com>
    Date: Sat, 14 May 2016 11:03:03 +0900
    Subject: [PATCH] heros
    
    ---
     binaries/data/mods/public/gui/session/session.js   | 124 ++++++++++++++-------
     .../gui/session/session_objects/hero_icon.xml      |  27 ++---
     2 files changed, 98 insertions(+), 53 deletions(-)
    
    diff --git a/binaries/data/mods/public/gui/session/session.js b/binaries/data/mods/public/gui/session/session.js
    index 125c58d..f3e0a2c 100644
    a b const g_DefaultPopulationColor = "white";  
    88const g_PopulationAlertColor = "orange";
    99
    1010/**
     11 * Maximum number of heroes to display (must stay in sync with hero_icon.xml).
     12 */
     13const g_HeroPanelCount = 10;
     14
     15/**
    1116 * A random file will be played. TODO: more variety
    1217 */
    1318const g_Ambient = [ "audio/ambient/dayscape/day_temperate_gen_03.ogg" ];
    var g_AdditionalHighlight = [];  
    145150/**
    146151 * Blink the hero selection if that entity has lost health since the last turn.
    147152 */
    148 var g_PreviousHeroHitPoints;
     153var g_PreviousHeroes = [];
    149154
    150155/**
    151156 * Unit classes to be checked for the idle-worker-hotkey.
    function updateGUIObjects()  
    712717    if (g_ShowGuarding || g_ShowGuarded)
    713718        updateAdditionalHighlight();
    714719
    715     updateHero();
     720    updateHeroes();
    716721    updateGroups();
    717722    updateDebug();
    718723    updatePlayerDisplay();
    function updateGUIStatusBar(nameOfBar, points, maxPoints, direction)  
    788793}
    789794
    790795
    791 function updateHero()
     796function updateHeroes()
    792797{
    793798    let unitHeroPanel = Engine.GetGUIObjectByName("unitHeroPanel");
    794     let heroButton = Engine.GetGUIObjectByName("unitHeroButton");
    795 
    796799    let playerState = GetSimState().players[g_ViewedPlayer];
    797800    if (!playerState || playerState.heroes.length <= 0)
    798801    {
    799         g_PreviousHeroHitPoints = undefined;
     802        g_PreviousHeroes = [];
    800803        unitHeroPanel.hidden = true;
    801804        return;
    802805    }
    803806
    804     let heroImage = Engine.GetGUIObjectByName("unitHeroImage");
    805     let heroState = GetExtendedEntityState(playerState.heroes[0]);
    806     let template = GetTemplateData(heroState.template);
    807     heroImage.sprite = "stretched:session/portraits/" + template.icon;
    808     let hero = playerState.heroes[0];
     807    unitHeroPanel.hidden = false;
    809808
    810     heroButton.onpress = function()
     809    let usedSlots = [];
     810    for(let i = 0; i < g_HeroPanelCount; ++i)
     811        usedSlots.push(false);
     812       
     813    let mapped = playerState.heroes.map(ent =>
     814        {
     815            // Map to current button, if available.
     816            if (g_PreviousHeroes[ent])
     817                return {
     818                    "ent": ent,
     819                    "index": g_PreviousHeroes[ent].displayIndex,
     820                    "previous": g_PreviousHeroes[ent] };
     821            // Using the panel count places new heroes at the end of the list.
     822            return {
     823                "ent": ent,
     824                "index": g_HeroPanelCount };
     825        }).sort((l, r) => l.index == r.index ? l.ent - r.ent : l.index - r.index);
     826   
     827    let heroes = [];
     828   
     829    for (let displayIndex = 0; displayIndex < Math.min(g_HeroPanelCount, mapped.length); ++displayIndex)
    811830    {
    812         if (!Engine.HotkeyIsPressed("selection.add"))
    813             g_Selection.reset();
    814         g_Selection.addList([hero]);
    815     };
    816     heroButton.ondoublepress = function() { selectAndMoveTo(getEntityOrHolder(hero)); };
    817     unitHeroPanel.hidden = false;
     831        let hero = mapped[displayIndex];
     832        // Find the first unused one if new, otherwise reuse previous.
     833        let buttonSlot = hero.previous === undefined ? usedSlots.findIndex(slot => !slot) : hero.previous.button;
     834        usedSlots[buttonSlot] = true;
     835       
     836        let heroButton = Engine.GetGUIObjectByName("unitHeroButton[" + buttonSlot + "]");
     837        let heroState = GetExtendedEntityState(hero.ent);
     838        let template = GetTemplateData(heroState.template);
     839       
     840        if (hero.previous === undefined)
     841        {
     842            heroButton.onpress = function()
     843            {
     844                if (!Engine.HotkeyIsPressed("selection.add"))
     845                    g_Selection.reset();
     846                g_Selection.addList([hero.ent]);
     847            };
     848            heroButton.ondoublepress = function() { selectAndMoveTo(getEntityOrHolder(hero.ent)); };
     849            heroButton.hidden = false;
     850            // Ensure no pre-existing animations.
     851            stopColorFade("heroHitOverlay[" + buttonSlot + "]");
     852            let heroImage = Engine.GetGUIObjectByName("unitHeroImage[" + buttonSlot + "]");
     853            heroImage.sprite = "stretched:session/portraits/" + template.icon;
     854        }
     855
     856        heroButton.tooltip = createHeroTooltip(heroState, template);
     857        updateGUIStatusBar("heroHealthBar[" + buttonSlot + "]", heroState.hitpoints, heroState.maxHitpoints);
     858        setPanelObjectPosition(heroButton, displayIndex, g_HeroPanelCount);
     859
     860        // if the health of the hero changed since the last update, trigger the animation
     861        if (hero.previous !== undefined && hero.previous.player == g_ViewedPlayer && hero.previous.hitpoints > heroState.hitpoints)
     862            startColorFade("heroHitOverlay[" + buttonSlot + "]", 100, 0, colorFade_attackUnit, true, smoothColorFadeRestart_attackUnit);
     863
     864        heroes[hero.ent] = {
     865            "displayIndex": displayIndex,
     866            "button": buttonSlot,
     867            "hitpoints": heroState.hitpoints,
     868            "player": g_ViewedPlayer };
     869    }
     870
     871    // In case heroes were removed and their slot/button was freed, hide it.
     872    for (let hero of g_PreviousHeroes.filter(prev => !usedSlots[prev.button]))
     873    {
     874        Engine.GetGUIObjectByName("unitHeroButton[" + hero.button + "]").hidden = true;
     875    }
    818876
     877    g_PreviousHeroes = heroes;
     878}
     879
     880function createHeroTooltip(heroState, template)
     881{
    819882    // Setup tooltip
    820883    let tooltip = "[font=\"sans-bold-16\"]" + template.name.specific + "[/font]";
    821     let healthLabel = "[font=\"sans-bold-13\"]" + translate("Health:") + "[/font]";
    822     tooltip += "\n" + sprintf(translate("%(label)s %(current)s / %(max)s"), {
    823         "label": healthLabel,
     884    tooltip += "\n" + sprintf(translate("%(label)s %(current)s / %(max)s"), {
     885        "label": "[font=\"sans-bold-13\"]" + translate("Health:") + "[/font]",
    824886        "current": Math.ceil(heroState.hitpoints),
    825887        "max": Math.ceil(heroState.maxHitpoints)
    826888    });
    function updateHero()  
    830892    tooltip += "\n" + getArmorTooltip(heroState.armour);
    831893    if (template.tooltip)
    832894        tooltip += "\n" + template.tooltip;
    833 
    834     heroButton.tooltip = tooltip;
    835 
    836     // update heros health bar
    837     updateGUIStatusBar("heroHealthBar", heroState.hitpoints, heroState.maxHitpoints);
    838 
    839     let heroHP = {
    840         "hitpoints": heroState.hitpoints,
    841         "player": g_ViewedPlayer
    842     };
    843 
    844     if (!g_PreviousHeroHitPoints)
    845         g_PreviousHeroHitPoints = heroHP;
    846 
    847     // if the health of the hero changed since the last update, trigger the animation
    848     if (g_PreviousHeroHitPoints.player == heroHP.player && g_PreviousHeroHitPoints.hitpoints > heroHP.hitpoints)
    849         startColorFade("heroHitOverlay", 100, 0, colorFade_attackUnit, true, smoothColorFadeRestart_attackUnit);
    850 
    851     g_PreviousHeroHitPoints = heroHP;
     895    return tooltip;
    852896}
    853897
    854898function updateGroups()
  • binaries/data/mods/public/gui/session/session_objects/hero_icon.xml

    diff --git a/binaries/data/mods/public/gui/session/session_objects/hero_icon.xml b/binaries/data/mods/public/gui/session/session_objects/hero_icon.xml
    index 35d7053..4c30dd9 100644
    a b  
    44    size="0 36 50 93"
    55    hidden="true"
    66>
    7     <object name="unitHeroButton" size="0 0 50 50" type="button" style="iconButton"
    8         tooltip_style="sessionToolTip">
    9         <object name="unitHeroImage" size="5 5 100%-5 100%-5" type="image" ghost="true"/>
    10         <object name="heroHitOverlay" hidden="true" type="image" ghost="true" size="5 5 100%-5 100%-5"/>
    11     </object>
    12     <!-- Hero Health bar -->
    13     <object size="3 100%-7 100%-3 100%-2" name="heroHealthSection" ghost="true">
    14         <object size="0 0 100% 5" name="heroHealth" type="image" ghost="true">
    15             <object type="image" sprite="barBorder" ghost="true" size="-1 -1 100%+1 100%+1"/>
    16             <object type="image" sprite="healthBackground" ghost="true"/>
    17             <object type="image" sprite="healthForeground" ghost="true" name="heroHealthBar"/>
    18             <object type="image" sprite="statsBarShaderHorizontal" ghost="true"/>
     7    <repeat count="10" var="n">
     8        <object name="unitHeroButton[n]" size="0 0 50 50" type="button" hidden="true" style="iconButton" tooltip_style="sessionToolTip">
     9            <object name="unitHeroImage[n]" size="5 5 100%-5 100%-5" type="image" ghost="true"/>
     10            <object name="heroHitOverlay[n]" hidden="true" type="image" ghost="true" size="5 5 100%-5 100%-5"/>
     11            <!-- Hero Health bar -->
     12            <object size="3 100%-7 100%-3 100%-2" name="heroHealthSection[n]" ghost="true">
     13                <object size="0 0 100% 5" name="heroHealth[n]" type="image" ghost="true">
     14                    <object type="image" sprite="barBorder" ghost="true" size="-1 -1 100%+1 100%+1"/>
     15                    <object type="image" sprite="healthBackground" ghost="true"/>
     16                    <object type="image" sprite="healthForeground" ghost="true" name="heroHealthBar[n]"/>
     17                    <object type="image" sprite="statsBarShaderHorizontal" ghost="true"/>
     18                </object>
     19            </object>
    1920        </object>
    20     </object>
     21    </repeat>
    2122</object>