Ticket #1902: hero_health_v2.patch

File hero_health_v2.patch, 12.3 KB (added by Michael, 10 years ago)

Adapted coding style on sanderd17's recommendation.

  • binaries/data/mods/public/gui/common/colorFades.js

     
     1/*
     2    DESCRIPTION : Some functions to make colour fades on GUI elements (f.e. used for hero and group icons)
     3    NOTES       :
     4*/
     5
     6// Used for storing object names of running color fades in order to stop them, if the fade is restarted before the old ended
     7var g_colorFade = {};
     8g_colorFade["id"] = {};
     9g_colorFade["tick"] = {};
     10
     11/**
     12 * starts fading a colour of a GUI object using the sprite argument
     13 * name: name of the object which colour should be faded
     14 * changeInterval: interval in ms when the next colour change should be made
     15 * duration: maximal duration of the complete fade
     16 * colour: RGB + opacity object with keys r,g,b and o
     17 * fun_colorTransform: function which transform the colors;
     18 *                    arguments: [colour object, tickCounter]
     19 * fun_smoothRestart [optional]: a function, which returns a smooth tick counter, if the fade should be started;
     20 *                              arguments: [tickCounter of current fade; not smaller than 1 or it restarts at 0] returns: smooth tick counter value
     21 * tickCounter [optional]: should not be set by hand! - how often the function was called recursively
     22 */
     23function fadeColour(name, changeInterval, duration, colour, fun_colorTransform, fun_smoothRestart, tickCounter)
     24{
     25    // get the overlay
     26    var overlay = Engine.GetGUIObjectByName(name);
     27    if (!overlay)
     28        return;
     29
     30    // check, if fade overlay was started just now
     31    if (!tickCounter)
     32    {
     33        tickCounter = 1;
     34        overlay.hidden = false;
     35                   
     36        // check, if another animation is running and restart it, if it's the case
     37        if (isColourFadeRunning(name))
     38        {
     39            restartColourFade(name, changeInterval, duration, colour, fun_colorTransform, fun_smoothRestart, g_colorFade.tick[name]);
     40            return;
     41        }
     42    }
     43   
     44    // get colors
     45    fun_colorTransform(colour, tickCounter);
     46   
     47    // set new colour
     48    overlay.sprite="colour: "+colour.r+" "+colour.g+" "+colour.b+" "+colour.o;
     49
     50    // recusive call, if duration is positive
     51    duration-= changeInterval;
     52    if (duration > 0 && colour.o > 0)
     53    {
     54        var id = setTimeout(function() { fadeColour(name, changeInterval, duration, colour, fun_colorTransform, fun_smoothRestart, ++tickCounter); }, changeInterval);
     55        g_colorFade.id[name] = id;
     56        g_colorFade.tick[name] = tickCounter;
     57    }
     58    else
     59    {
     60        overlay.hidden = true;
     61        stopColourFade(name);
     62    }
     63}
     64
     65
     66/**
     67 * checks, if a colour fade on that object is running
     68 * name: name of the object which colour fade should be checked
     69 * return: true a running fade was found
     70 */
     71function isColourFadeRunning(name)
     72{
     73    return name in g_colorFade.id;
     74}
     75
     76/**
     77 * stops fading a colour
     78 * name: name of the object which colour fade should be stopped
     79 * hideOverlay: hides the overlay, if true
     80 * return: true a running fade was stopped
     81 */
     82function stopColourFade(name, hideOverlay)
     83{
     84    // check, if a colour fade is running
     85    if (!isColourFadeRunning(name))
     86        return false;
     87
     88    // delete the timer
     89    clearTimeout(g_colorFade.id[name]);
     90    delete g_colorFade.id[name];
     91    delete g_colorFade.tick[name];
     92   
     93    // get the overlay and hide it
     94    if (hideOverlay)
     95    {
     96        var overlay = Engine.GetGUIObjectByName(name);
     97        if(overlay)
     98            overlay.hidden = true;
     99    }
     100    return true;
     101}
     102
     103/**
     104 * restarts a colour fade
     105 * see paramter in fadeColour function
     106 */
     107function restartColourFade(name, changeInterval, duration, colour, fun_colorTransform, fun_smoothRestart, tickCounter)
     108{
     109    // check, if a colour fade is running
     110    if (!isColourFadeRunning(name))
     111        return false;
     112   
     113    // check, if fade can be restarted smoothly
     114    if (fun_smoothRestart)
     115    {
     116        tickCounter = fun_smoothRestart(colour, tickCounter);
     117        // set new function to existing timer
     118        var fun = function() { fadeColour(name, changeInterval, duration, colour, fun_colorTransform, fun_smoothRestart, tickCounter); };
     119        setNewTimerFunction(g_colorFade.id[name], fun);
     120    }
     121    // stop it and restart it
     122    else
     123    {
     124        stopColourFade(name, true);
     125        fadeColour(name, changeInterval, duration, colour, fun_colorTransform);
     126    }
     127    return true;
     128}
     129
     130/**                                     PREDEFINED FUNCTIONS                                            */
     131
     132//[START] of hero fade functions
     133
     134var g_fadeAttackUnit = {};
     135g_fadeAttackUnit.blinkingTicks = 50; // how many ticks should first blinking phase be
     136g_fadeAttackUnit.blinkingChangeInterval = 5; // how often should the colour be changed during the blinking phase
     137g_fadeAttackUnit.gbColourChangeRate = 3; // how fast should blue and green part of the colour change
     138g_fadeAttackUnit.fadeOutStart = 100; // when should the fade out start using the opacity
     139g_fadeAttackUnit.opacityChangeRate = 3; // how fast should opacity change
     140
     141/**
     142 * rgb: colour object with keys r,g,b and o
     143 * tickCounter: how often the fade was executed
     144 */
     145function colourFade_attackUnit(rgb, tickCounter)
     146{
     147    // blinking
     148    if (tickCounter < g_fadeAttackUnit.blinkingTicks)
     149    {
     150        // slow that process down
     151        if (tickCounter % g_fadeAttackUnit.blinkingChangeInterval != 0)
     152            return;
     153           
     154        rgb.g = rgb.g == 0 ? 255 : rgb.g = 0;
     155        rgb.b = rgb.b == 0 ? 255 : rgb.b = 0;
     156    }
     157    // wait a short time and then colour fade from red to grey to nothing
     158    else if ( tickCounter >= g_fadeAttackUnit.blinkingTicks + g_fadeAttackUnit.blinkingChangeInterval)
     159    {
     160        rgb.g = rgb.g < 255 ? rgb.g += g_fadeAttackUnit.gbColourChangeRate * Math.sqrt(tickCounter - g_fadeAttackUnit.blinkingTicks) : 255;
     161        rgb.b = rgb.g;
     162       
     163        // start with fading it out
     164        if (rgb.g > g_fadeAttackUnit.fadeOutStart)
     165            rgb.o = rgb.o > g_fadeAttackUnit.opacityChangeRate ? rgb.o -= g_fadeAttackUnit.opacityChangeRate : 0;
     166    }
     167}
     168
     169/**
     170 * makes a smooth fade, if the attack on the unit has not stopped yet
     171 * rgb: colour object with keys r,g,b and o
     172 * tickCounter: how often the fade was executed
     173 */
     174function smoothColourFadeRestart_attackUnit(rgb, tickCounter)
     175{
     176    // check, if in blinking phase
     177    if (tickCounter < g_fadeAttackUnit.blinkingTicks)
     178    {
     179        // get rgb to current state
     180        for (var i = 1; i <= tickCounter; i++)
     181            colourFade_attackUnit(rgb, i);
     182        // set the tick counter back to start
     183        return (tickCounter % (g_fadeAttackUnit.blinkingChangeInterval * 2)) + 1;
     184    }
     185    return 1;
     186}
     187
     188//[END] of hero fade functions
     189 No newline at end of file
  • binaries/data/mods/public/gui/common/timer.js

     
    44
    55/**
    66 * Set a timeout to call func() after 'delay' msecs.
     7 * func: function to call
     8 * delay: delay in ms
    79 * Returns an id that can be passed to clearTimeout.
    810 */
    911function setTimeout(func, delay)
     
    1315    return id;
    1416}
    1517
     18/**
     19 * deletes a timer
     20 * id: of the timer
     21 */
    1622function clearTimeout(id)
    1723{
    1824    delete g_Timers[id];
     
    1925}
    2026
    2127/**
     28* alters an function call
     29* id: of the timer
     30* func: function to call
     31*/
     32function setNewTimerFunction(id, func)
     33{
     34    if (id in g_Timers)
     35        g_Timers[id][1] = func;
     36}
     37
     38/**
    2239 * If you want to use timers, then you must call this function regularly
    2340 * (e.g. in a Tick handler)
    2441 */
  • binaries/data/mods/public/gui/session/session.js

     
    5151var g_ShowGuarded = false;
    5252var g_AdditionalHighlight = [];
    5353
     54// for saving the hitpoins of the hero (is there a better way to do that?)
     55// Should be possible with AttackDetection but might be an overkill because it would have to loop
     56// always through the list of all ongoing attacks...
     57var g_previousHeroHitPoints = undefined;
     58
    5459function GetSimState()
    5560{
    5661    if (!g_SimState)
     
    487492        global.music.setState(global.music.states[battleState]);
    488493}
    489494
     495/**
     496* updates a status bar on the GUI
     497* nameOfBar: name of the bar
     498* points: points to show
     499* maxPoints: max points
     500* direction: gets less from (right to left) 0; (top to bottom) 1; (left to right) 2; (bottom to top) 3;
     501*/
     502function updateGUIStatusBar(nameOfBar, points, maxPoints, direction)
     503{
     504    // check, if optional direction parameter is valid.
     505    if (!direction || !(direction>=0 && direction<4))
     506        direction = 0;
     507
     508    // get the bar and update it
     509    var statusBar = Engine.GetGUIObjectByName(nameOfBar);
     510    if (!statusBar)
     511        return;
     512       
     513    var healthSize = statusBar.size;
     514    var value = 100*Math.max(0, Math.min(1, points / maxPoints));
     515   
     516    // inverse bar
     517    if(direction == 2 || direction == 3)
     518        value = 100 - value;
     519
     520    if(direction == 0)
     521        healthSize.rright = value;
     522    else if(direction == 1)
     523        healthSize.rbottom = value;
     524    else if(direction == 2)
     525        healthSize.rleft = value;
     526    else if(direction == 3)
     527        healthSize.rtop = value;
     528   
     529    // update bar
     530    statusBar.size = healthSize;
     531}
     532
     533
    490534function updateHero()
    491535{
    492536    var simState = GetSimState();
    493537    var playerState = simState.players[Engine.GetPlayerID()];
     538    var unitHeroPanel = Engine.GetGUIObjectByName("unitHeroPanel");
    494539    var heroButton = Engine.GetGUIObjectByName("unitHeroButton");
    495540
    496541    if (!playerState || playerState.heroes.length <= 0)
    497542    {
    498         heroButton.hidden = true;
     543        g_previousHeroHitPoints = undefined;
     544        unitHeroPanel.hidden = true;
    499545        return;
    500546    }
    501547
     
    512558        g_Selection.addList([hero]);
    513559    };
    514560    heroButton.ondoublepress = function() { selectAndMoveTo(getEntityOrHolder(hero)); };
    515     heroButton.hidden = false;
     561    unitHeroPanel.hidden = false;
    516562
    517563    // Setup tooltip
    518564    var tooltip = "[font=\"serif-bold-16\"]" + template.name.specific + "[/font]";
     
    527573    tooltip += "\n" + template.tooltip;
    528574
    529575    heroButton.tooltip = tooltip;
    530 };
     576   
     577    // update heros health bar
     578    updateGUIStatusBar("heroHealthBar", heroState.hitpoints, heroState.maxHitpoints);
     579   
     580    // define the hit points if not defined
     581    if (!g_previousHeroHitPoints)
     582        g_previousHeroHitPoints = heroState.hitpoints;
     583   
     584    // check, if the health of the hero changed since the last update
     585    if (heroState.hitpoints < g_previousHeroHitPoints)
     586    {   
     587        g_previousHeroHitPoints = heroState.hitpoints;
     588        // trigger the animation
     589        fadeColour("heroHitOverlay", 100, 10000, {"r": 175,"g": 0,"b": 0,"o": 100}, colourFade_attackUnit, smoothColourFadeRestart_attackUnit);
     590        return;
     591    }
     592}
    531593
     594
    532595function updateGroups()
    533596{
    534597    var guiName = "Group";
  • binaries/data/mods/public/gui/session/session.xml

     
    77    <script file="gui/common/functions_global_object.js" />
    88    <script file="gui/common/music.js"/>
    99    <script file="gui/common/timer.js"/>
     10    <script file="gui/common/colorFades.js"/>
    1011    <script file="gui/session/session.js"/>
    1112    <script file="gui/session/selection.js"/>
    1213    <script file="gui/session/placement.js"/>
     
    866867    <!-- ================================  ================================ -->
    867868    <object
    868869        name="unitHeroPanel"
    869         size="0 36 50 86"
     870        size="0 36 50 93"
     871        hidden="true"
    870872    >
    871         <object name="unitHeroButton" size="0 0 50 50" type="button" hidden="false" style="iconButton"
     873        <object name="unitHeroButton" size="0 0 50 50" type="button" style="iconButton"
    872874            tooltip_style="sessionToolTip" tooltip="Attack and Armor">
    873875            <object name="unitHeroImage" size="5 5 100%-5 100%-5" type="image" ghost="true"/>
     876            <object name="heroHitOverlay" hidden="true" type="image" ghost="true" size="5 5 100%-5 100%-5"/>
    874877        </object>
     878        <!-- Hero Health bar -->
     879            <object size="3 100%-7 100%-3 100%-2" name="heroHealthSection" ghost="true">
     880                <object size="0 0 100% 5" name="heroHealth" type="image" ghost="true">
     881                    <object type="image" sprite="barBorder" ghost="true" size="-1 -1 100%+1 100%+1"/>
     882                    <object type="image" sprite="healthBackground" ghost="true"/>
     883                    <object type="image" sprite="healthForeground" ghost="true" name="heroHealthBar"/>
     884                    <object type="image" sprite="statsBarShaderHorizontal" ghost="true"/>
     885                </object>
     886            </object>
     887        <!-- Hit overlay -->
    875888    </object>
    876889   
    877890    <!-- ================================  ================================ -->