diff --git a/binaries/data/mods/public/gui/common/colorFades.js b/binaries/data/mods/public/gui/common/colorFades.js new file mode 100644 index 0000000000..212cbf8849 --- /dev/null +++ b/binaries/data/mods/public/gui/common/colorFades.js @@ -0,0 +1,176 @@ +/* + DESCRIPTION : Some functions to make colour fades on GUI elements (f.e. used for hero and group icons) + NOTES : +*/ + +// Used for storing object names of running color fades in order to stop them, if the fade is restarted before the old ended +var g_colorFade = {}; +g_colorFade["id"] = {}; +g_colorFade["tick"] = {}; + +/** + * starts fading a colour of a GUI object using the sprite argument + * name: name of the object which colour should be faded + * changeInterval: interval in ms when the next colour change should be made + * duration: maximal duration of the complete fade + * colour: RGB + opacity object with keys r,g,b and o + * fun_colorTransform: function which transform the colors; + * arguments: [colour object, tickCounter] + * fun_smoothRestart [optional]: a function, which returns a smooth tick counter, if the fade should be started; + * arguments: [tickCounter of current fade; not smaller than 1 or it restarts at 0] returns: smooth tick counter value + * tickCounter [optional]: should not be set by hand! - how often the function was called recursively + */ +function fadeColour(name, changeInterval, duration, colour, fun_colorTransform, fun_smoothRestart, tickCounter) +{ + // get the overlay + var overlay = Engine.GetGUIObjectByName(name); + if (overlay) + { + // check, if fade overlay was started just now + if (!tickCounter) + { + tickCounter = 1; + overlay.hidden = false; + + // check, if another animation is running and restart it, if it's the case + if (isColourFadeRunning(name)) + { + restartColourFade(name, changeInterval, duration, colour, fun_colorTransform, fun_smoothRestart, g_colorFade.tick[name]); + return; + } + } + + // get colors + fun_colorTransform(colour, tickCounter); + + // set new colour + overlay.sprite="colour: "+colour.r+" "+colour.g+" "+colour.b+" "+colour.o; + + // recusive call, if duration is positive + duration-= changeInterval; + if (duration > 0 && colour.o > 0) + { + var id = setTimeout(function() { fadeColour(name, changeInterval, duration, colour, fun_colorTransform, fun_smoothRestart, ++tickCounter); }, changeInterval); + g_colorFade.id[name] = id; + g_colorFade.tick[name] = tickCounter; + } + else { + overlay.hidden = true; + stopColourFade(name); + } + } +} + + +/** + * checks, if a colour fade on that object is running + * name: name of the object which colour fade should be checked + * return: true a running fade was found + */ +function isColourFadeRunning(name) +{ + return name in g_colorFade.id; +} + +/** + * stops fading a colour + * name: name of the object which colour fade should be stopped + * return: true a running fade was stopped + */ +function stopColourFade(name, doNotHideOverlay) +{ + if (isColourFadeRunning(name)) + { + clearTimeout(g_colorFade.id[name]); + delete g_colorFade.id[name]; + delete g_colorFade.tick[name]; + + // get the overlay and hide it + if (doNotHideOverlay != true) + { + var overlay = Engine.GetGUIObjectByName(name); + if(overlay) + overlay.hidden = true; + } + + return true; + } + return false; +} + +/** + * restarts a colour fade + * see paramter in fadeColour function + */ +function restartColourFade(name, changeInterval, duration, colour, fun_colorTransform, fun_smoothRestart, tickCounter) +{ + if (isColourFadeRunning(name)) + { + // check, if fade can be restarted smoothly + if (fun_smoothRestart) + { + tickCounter = fun_smoothRestart(colour, tickCounter); + // set new function to existing timer + var fun = function() { fadeColour(name, changeInterval, duration, colour, fun_colorTransform, fun_smoothRestart, tickCounter); }; + setNewTimerFunction(g_colorFade.id[name], fun); + } + // stop it and restart it + else + { + stopColourFade(name, true); + fadeColour(name, changeInterval, duration, colour, fun_colorTransform); + } + } +} + +/********************************************************************************************************/ +/* PREDEFINED FUNCTIONS */ +/********************************************************************************************************/ + +/** + * rgb: colour object with keys r,g,b and o + * tickCounter: how often the fade was executed + */ +function colourFade_attackUnit(rgb, tickCounter) +{ + + // blinking + if (tickCounter < 50) + { + // slow that process down + if (tickCounter%5 != 0) + return; + + rgb.g = rgb.g == 0 ? 255 : rgb.g = 0; + rgb.b = rgb.b == 0 ? 255 : rgb.b = 0; + } + // wait a short time and then colour fade from red to grey to nothing + else if ( tickCounter > 54) + { + rgb.g = rgb.g < 255 ? rgb.g += 3*Math.sqrt(tickCounter-50) : 255; + rgb.b = rgb.g; + + // start with fading it out + if (rgb.g > 100) + rgb.o = rgb.o > 3 ? rgb.o -= 3 : 0; + } +} + +/** + * makes a smooth fade, if the attack on the unit has not stopped yet + * rgb: colour object with keys r,g,b and o + * tickCounter: how often the fade was executed + */ +function smoothColourFadeRestart_attackUnit(rgb, tickCounter) +{ + // check, if in blinking phase + if (tickCounter < 50) + { + // get rgb to current state + for (var i = 1; i <= tickCounter; i++) + colourFade_attackUnit(rgb, i); + // set the tick counter back to start + return (tickCounter%10)+1; + } + return 1; +} \ No newline at end of file diff --git a/binaries/data/mods/public/gui/common/timer.js b/binaries/data/mods/public/gui/common/timer.js index 5391ba7c8c..bf8c097309 100644 --- a/binaries/data/mods/public/gui/common/timer.js +++ b/binaries/data/mods/public/gui/common/timer.js @@ -4,6 +4,8 @@ var g_Time = Date.now(); /** * Set a timeout to call func() after 'delay' msecs. + * func: function to call + * delay: delay in ms * Returns an id that can be passed to clearTimeout. */ function setTimeout(func, delay) @@ -13,11 +15,27 @@ function setTimeout(func, delay) return id; } +/** + * deletes a timer + * id: of the timer + */ function clearTimeout(id) { delete g_Timers[id]; } +/** +* alters an function call +* id: of the timer +* func: function to call +*/ +function setNewTimerFunction(id, func) +{ + if (id in g_Timers) { + g_Timers[id][1] = func; + } +} + /** * If you want to use timers, then you must call this function regularly * (e.g. in a Tick handler) diff --git a/binaries/data/mods/public/gui/session/session.js b/binaries/data/mods/public/gui/session/session.js index 1981eb3c22..b0f7e12c5e 100644 --- a/binaries/data/mods/public/gui/session/session.js +++ b/binaries/data/mods/public/gui/session/session.js @@ -51,6 +51,9 @@ var g_ShowGuarding = false; var g_ShowGuarded = false; var g_AdditionalHighlight = []; +// for saving the hitpoins of the hero (is there a better way to do that?) +var g_heroHitpoints = undefined; + function GetSimState() { if (!g_SimState) @@ -485,17 +488,59 @@ function onSimulationUpdate() var battleState = Engine.GuiInterfaceCall("GetBattleState", Engine.GetPlayerID()); if (battleState) global.music.setState(global.music.states[battleState]); + } +/** +* updates a status bar on the GUI +* nameOfBar: name of the bar +* points: points to show +* maxPoints: max points +* direction: gets less from (right to left) 0; (top to bottom) 1; (left to right) 2; (bottom to top) 3; +*/ +function updateGUIStatusBar(nameOfBar, points, maxPoints, direction) +{ + // check, if optional direction parameter is valid. + if (!direction || !(direction>=0 && direction<4)) + direction = 0; + + // get the bar and update it + var statusBar = Engine.GetGUIObjectByName(nameOfBar); + if (statusBar) + { + var healthSize = statusBar.size; + var value = 100*Math.max(0, Math.min(1, points / maxPoints)); + + // inverse bar + if(direction == 2 || direction == 3) + value = 100 - value; + + if(direction == 0) + healthSize.rright = value; + else if(direction == 1) + healthSize.rbottom = value; + else if(direction == 2) + healthSize.rleft = value; + else if(direction == 3) + healthSize.rtop = value; + + // update bar + statusBar.size = healthSize; + } +} + + function updateHero() { var simState = GetSimState(); var playerState = simState.players[Engine.GetPlayerID()]; + var unitHeroPanel = Engine.GetGUIObjectByName("unitHeroPanel"); var heroButton = Engine.GetGUIObjectByName("unitHeroButton"); if (!playerState || playerState.heroes.length <= 0) { - heroButton.hidden = true; + g_heroHitpoints = undefined; + unitHeroPanel.hidden = true; return; } @@ -512,7 +557,7 @@ function updateHero() g_Selection.addList([hero]); }; heroButton.ondoublepress = function() { selectAndMoveTo(getEntityOrHolder(hero)); }; - heroButton.hidden = false; + unitHeroPanel.hidden = false; // Setup tooltip var tooltip = "[font=\"serif-bold-16\"]" + template.name.specific + "[/font]"; @@ -527,7 +572,25 @@ function updateHero() tooltip += "\n" + template.tooltip; heroButton.tooltip = tooltip; -}; + + // update heros health bar + updateGUIStatusBar("heroHealthBar", heroState.hitpoints, heroState.maxHitpoints); + + // define the hit points if not defined + if (!g_heroHitpoints) + g_heroHitpoints = heroState.hitpoints; + + // check, if the health of the hero changed since the last update + if (heroState.hitpoints < g_heroHitpoints) + { + g_heroHitpoints = heroState.hitpoints; + // trigger the animation + fadeColour("heroHitOverlay", 100, 10000, {"r": 175,"g": 0,"b": 0,"o": 100}, colourFade_attackUnit, smoothColourFadeRestart_attackUnit); + return; + } +} + + function updateGroups() { diff --git a/binaries/data/mods/public/gui/session/session.xml b/binaries/data/mods/public/gui/session/session.xml index 240efc4cb3..16d59d4b72 100644 --- a/binaries/data/mods/public/gui/session/session.xml +++ b/binaries/data/mods/public/gui/session/session.xml @@ -7,6 +7,7 @@