Index: ps/trunk/binaries/data/mods/public/gui/common/colorFades.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/common/colorFades.js (nonexistent) +++ ps/trunk/binaries/data/mods/public/gui/common/colorFades.js (revision 14524) @@ -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 Index: ps/trunk/binaries/data/mods/public/gui/common/timer.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/common/timer.js (revision 14523) +++ ps/trunk/binaries/data/mods/public/gui/common/timer.js (revision 14524) @@ -1,52 +1,70 @@ var g_TimerID = 0; var g_Timers = {}; 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) { var id = ++g_TimerID; g_Timers[id] = [g_Time + delay, func]; 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) */ function updateTimers() { g_Time = Date.now(); // Collect the timers that need to run // (We do this in two stages to avoid deleting from the timer list while // we're in the middle of iterating through it) var run = []; for (var id in g_Timers) { if (g_Timers[id][0] <= g_Time) run.push(id); } for each (var id in run) { var t = g_Timers[id]; if (!t) continue; // an earlier timer might have cancelled this one, so skip it try { t[1](); } catch (e) { var stack = e.stack.trimRight().replace(/^/mg, ' '); // indent the stack trace error("Error in timer: "+e+"\n"+stack+"\n"); } delete g_Timers[id]; } } Index: ps/trunk/binaries/data/mods/public/gui/session/session.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/session.js (revision 14523) +++ ps/trunk/binaries/data/mods/public/gui/session/session.js (revision 14524) @@ -1,894 +1,957 @@ // Network Mode var g_IsNetworked = false; // Is this user in control of game settings (i.e. is a network server, or offline player) var g_IsController; // Match ID for tracking var g_MatchID; // Cache the basic player data (name, civ, color) var g_Players = []; // Cache the useful civ data var g_CivData = {}; var g_GameSpeeds = {}; var g_CurrentSpeed; var g_PlayerAssignments = { "local": { "name": "You", "player": 1 } }; // Cache dev-mode settings that are frequently or widely used var g_DevSettings = { controlAll: false }; // Whether status bars should be shown for all of the player's units. var g_ShowAllStatusBars = false; // Indicate when one of the current player's training queues is blocked // (this is used to support population counter blinking) var g_IsTrainingBlocked = false; // Cache simulation state (updated on every simulation update) var g_SimState; // Cache EntityStates var g_EntityStates = {}; // {id:entState} // Whether the player has lost/won and reached the end of their game var g_GameEnded = false; var g_Disconnected = false; // Lost connection to server // Holds player states from the last tick var g_CachedLastStates = ""; // Colors to flash when pop limit reached const DEFAULT_POPULATION_COLOR = "white"; const POPULATION_ALERT_COLOR = "orange"; // List of additional entities to highlight 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) g_SimState = Engine.GuiInterfaceCall("GetSimulationState"); return g_SimState; } function GetEntityState(entId) { if (!(entId in g_EntityStates)) { var entState = Engine.GuiInterfaceCall("GetEntityState", entId); if (entState) entState.extended = false; g_EntityStates[entId] = entState; } return g_EntityStates[entId]; } function GetExtendedEntityState(entId) { if (entId in g_EntityStates) var entState = g_EntityStates[entId]; else var entState = Engine.GuiInterfaceCall("GetEntityState", entId); if (!entState || entState.extended) return entState; var extension = Engine.GuiInterfaceCall("GetExtendedEntityState", entId); for (var prop in extension) entState[prop] = extension[prop]; entState.extended = true; g_EntityStates[entId] = entState; return entState; } // Cache TemplateData var g_TemplateData = {}; // {id:template} function GetTemplateData(templateName) { if (!(templateName in g_TemplateData)) { var template = Engine.GuiInterfaceCall("GetTemplateData", templateName); g_TemplateData[templateName] = template; } return g_TemplateData[templateName]; } // Cache TechnologyData var g_TechnologyData = {}; // {id:template} function GetTechnologyData(technologyName) { if (!(technologyName in g_TechnologyData)) { var template = Engine.GuiInterfaceCall("GetTechnologyData", technologyName); g_TechnologyData[technologyName] = template; } return g_TechnologyData[technologyName]; } // Init function init(initData, hotloadData) { if (initData) { g_IsNetworked = initData.isNetworked; // Set network mode g_IsController = initData.isController; // Set controller mode g_PlayerAssignments = initData.playerAssignments; g_MatchID = initData.attribs.matchID; // Cache the player data // (This may be updated at runtime by handleNetMessage) g_Players = getPlayerData(g_PlayerAssignments); if (initData.savedGUIData) restoreSavedGameData(initData.savedGUIData); Engine.GetGUIObjectByName("gameSpeedButton").hidden = g_IsNetworked; } else // Needed for autostart loading option { g_Players = getPlayerData(null); } // Cache civ data g_CivData = loadCivData(); g_CivData["gaia"] = { "Code": "gaia", "Name": "Gaia" }; g_GameSpeeds = initGameSpeeds(); g_CurrentSpeed = Engine.GetSimRate(); var gameSpeed = Engine.GetGUIObjectByName("gameSpeed"); gameSpeed.list = g_GameSpeeds.names; gameSpeed.list_data = g_GameSpeeds.speeds; var idx = g_GameSpeeds.speeds.indexOf(g_CurrentSpeed); gameSpeed.selected = idx != -1 ? idx : g_GameSpeeds["default"]; gameSpeed.onSelectionChange = function() { changeGameSpeed(+this.list_data[this.selected]); } Engine.GetGUIObjectByName("civIcon").sprite = "stretched:" + g_CivData[g_Players[Engine.GetPlayerID()].civ].Emblem; Engine.GetGUIObjectByName("civIcon").tooltip = g_CivData[g_Players[Engine.GetPlayerID()].civ].Name; initMenuPosition(); // set initial position // Populate player selection dropdown var playerNames = []; var playerIDs = []; for (var player in g_Players) { playerNames.push(g_Players[player].name); playerIDs.push(player); } var viewPlayerDropdown = Engine.GetGUIObjectByName("viewPlayer"); viewPlayerDropdown.list = playerNames; viewPlayerDropdown.list_data = playerIDs; viewPlayerDropdown.selected = Engine.GetPlayerID(); // If in Atlas editor, disable the exit button if (Engine.IsAtlasRunning()) Engine.GetGUIObjectByName("menuExitButton").enabled = false; if (hotloadData) { g_Selection.selected = hotloadData.selection; } else { // Starting for the first time: var civMusic = g_CivData[g_Players[Engine.GetPlayerID()].civ].Music; initMusic(); global.music.storeTracks(civMusic); global.music.setState(global.music.states.PEACE); playRandomAmbient("temperate"); } if (Engine.ConfigDB_GetValue("user", "gui.session.timeelapsedcounter") === "true") Engine.GetGUIObjectByName("timeElapsedCounter").hidden = false; onSimulationUpdate(); // Report the performance after 5 seconds (when we're still near // the initial camera view) and a minute (when the profiler will // have settled down if framerates as very low), to give some // extremely rough indications of performance setTimeout(function() { reportPerformance(5); }, 5000); setTimeout(function() { reportPerformance(60); }, 60000); } function selectViewPlayer(playerID) { Engine.SetPlayerID(playerID); if (playerID != 0) { Engine.GetGUIObjectByName("civIcon").sprite = "stretched:" + g_CivData[g_Players[playerID].civ].Emblem; Engine.GetGUIObjectByName("civIcon").tooltip = g_CivData[g_Players[playerID].civ].Name; } } function reportPerformance(time) { var settings = Engine.GetMapSettings(); var data = { time: time, map: settings.Name, seed: settings.Seed, // only defined for random maps size: settings.Size, // only defined for random maps profiler: Engine.GetProfilerState() }; Engine.SubmitUserReport("profile", 3, JSON.stringify(data)); } function resignGame() { var simState = GetSimState(); // Players can't resign if they've already won or lost. if (simState.players[Engine.GetPlayerID()].state != "active" || g_Disconnected) return; // Tell other players that we have given up and been defeated Engine.PostNetworkCommand({ "type": "defeat-player", "playerId": Engine.GetPlayerID() }); global.music.setState(global.music.states.DEFEAT); resumeGame(); } function leaveGame() { var extendedSimState = Engine.GuiInterfaceCall("GetExtendedSimulationState"); var playerState = extendedSimState.players[Engine.GetPlayerID()]; var mapSettings = Engine.GetMapSettings(); var gameResult; if (g_Disconnected) { gameResult = "You have been disconnected." } else if (playerState.state == "won") { gameResult = "You have won the battle!"; } else if (playerState.state == "defeated") { gameResult = "You have been defeated..."; } else // "active" { gameResult = "You have abandoned the game."; // Tell other players that we have given up and been defeated Engine.PostNetworkCommand({ "type": "defeat-player", "playerId": Engine.GetPlayerID() }); global.music.setState(global.music.states.DEFEAT); } stopAmbient(); Engine.EndGame(); if (g_IsController && Engine.HasXmppClient()) Engine.SendUnregisterGame(); Engine.SwitchGuiPage("page_summary.xml", { "gameResult" : gameResult, "timeElapsed" : extendedSimState.timeElapsed, "playerStates": extendedSimState.players, "players": g_Players, "mapSettings": mapSettings }); } // Return some data that we'll use when hotloading this file after changes function getHotloadData() { return { selection: g_Selection.selected }; } // Return some data that will be stored in saved game files function getSavedGameData() { var data = {}; data.playerAssignments = g_PlayerAssignments; data.groups = g_Groups.groups; // TODO: any other gui state? return data; } function restoreSavedGameData(data) { // Clear selection when loading a game g_Selection.reset(); // Restore control groups for (var groupNumber in data.groups) { g_Groups.groups[groupNumber].groups = data.groups[groupNumber].groups; g_Groups.groups[groupNumber].ents = data.groups[groupNumber].ents; } updateGroups(); } var lastTickTime = new Date; /** * Called every frame. */ function onTick() { var now = new Date; var tickLength = new Date - lastTickTime; lastTickTime = now; checkPlayerState(); while (true) { var message = Engine.PollNetworkClient(); if (!message) break; handleNetMessage(message); } updateCursorAndTooltip(); // If the selection changed, we need to regenerate the sim display (the display depends on both the // simulation state and the current selection). if (g_Selection.dirty) { g_Selection.dirty = false; onSimulationUpdate(); // Display rally points for selected buildings Engine.GuiInterfaceCall("DisplayRallyPoint", { "entities": g_Selection.toList() }); } // Run timers updateTimers(); // Animate menu updateMenuPosition(tickLength); // When training is blocked, flash population (alternates colour every 500msec) if (g_IsTrainingBlocked && (Date.now() % 1000) < 500) Engine.GetGUIObjectByName("resourcePop").textcolor = POPULATION_ALERT_COLOR; else Engine.GetGUIObjectByName("resourcePop").textcolor = DEFAULT_POPULATION_COLOR; // Clear renamed entities list Engine.GuiInterfaceCall("ClearRenamedEntities"); } function checkPlayerState() { // Once the game ends, we're done here. if (g_GameEnded) return; // Send a game report for each player in this game. var m_simState = GetSimState(); var playerState = m_simState.players[Engine.GetPlayerID()]; var tempStates = ""; for each (var player in m_simState.players) {tempStates += player.state + ",";} if (g_CachedLastStates != tempStates) { g_CachedLastStates = tempStates; reportGame(Engine.GuiInterfaceCall("GetExtendedSimulationState")); } // If the local player hasn't finished playing, we return here to avoid the victory/defeat messages. if (playerState.state == "active") return; // We can't resign once the game is over. Engine.GetGUIObjectByName("menuResignButton").enabled = false; // Make sure nothing is open to avoid stacking. closeMenu(); closeOpenDialogs(); // Make sure this doesn't run again. g_GameEnded = true; if (Engine.IsAtlasRunning()) { // If we're in Atlas, we can't leave the game var btCaptions = ["OK"]; var btCode = [null]; var message = "Press OK to continue"; } else { var btCaptions = ["Yes", "No"]; var btCode = [leaveGame, null]; var message = "Do you want to quit?"; } if (playerState.state == "defeated") { global.music.setState(global.music.states.DEFEAT); messageBox(400, 200, message, "DEFEATED!", 0, btCaptions, btCode); } else if (playerState.state == "won") { global.music.setState(global.music.states.VICTORY); // TODO: Reveal map directly instead of this silly proxy. if (!Engine.GetGUIObjectByName("devCommandsRevealMap").checked) Engine.GetGUIObjectByName("devCommandsRevealMap").checked = true; messageBox(400, 200, message, "VICTORIOUS!", 0, btCaptions, btCode); } } function changeGameSpeed(speed) { // For non-networked games only if (!g_IsNetworked) { Engine.SetSimRate(speed); g_CurrentSpeed = speed; } } /** * Recomputes GUI state that depends on simulation state or selection state. Called directly every simulation * update (see session.xml), or from onTick when the selection has changed. */ function onSimulationUpdate() { g_EntityStates = {}; g_TemplateData = {}; g_TechnologyData = {}; g_SimState = Engine.GuiInterfaceCall("GetSimulationState"); // If we're called during init when the game is first loading, there will be no simulation yet, so do nothing if (!g_SimState) return; handleNotifications(); if (g_ShowAllStatusBars) recalculateStatusBarDisplay(); if (g_ShowGuarding || g_ShowGuarded) updateAdditionalHighlight(); updateHero(); updateGroups(); updateDebug(); updatePlayerDisplay(); updateSelectionDetails(); updateResearchDisplay(); updateBuildingPlacementPreview(); updateTimeElapsedCounter(); updateTimeNotifications(); // Update music state on basis of battle state. 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; } var heroImage = Engine.GetGUIObjectByName("unitHeroImage"); var heroState = GetExtendedEntityState(playerState.heroes[0]); var template = GetTemplateData(heroState.template); heroImage.sprite = "stretched:session/portraits/" + template.icon; var hero = playerState.heroes[0]; heroButton.onpress = function() { if (!Engine.HotkeyIsPressed("selection.add")) g_Selection.reset(); 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]"; tooltip += "\n[font=\"serif-bold-13\"]Health:[/font] " + heroState.hitpoints + "/" + heroState.maxHitpoints; tooltip += "\n[font=\"serif-bold-13\"]" + (heroState.attack ? heroState.attack.type + " " : "") + "Attack:[/font] " + damageTypeDetails(heroState.attack); // Show max attack range if ranged attack, also convert to tiles (4m per tile) if (heroState.attack && heroState.attack.type == "Ranged") tooltip += ", [font=\"serif-bold-13\"]Range:[/font] " + Math.round(heroState.attack.maxRange/4); tooltip += "\n[font=\"serif-bold-13\"]Armor:[/font] " + damageTypeDetails(heroState.armour); 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() { var guiName = "Group"; g_Groups.update(); for (var i = 0; i < 10; i++) { var button = Engine.GetGUIObjectByName("unit"+guiName+"Button["+i+"]"); var label = Engine.GetGUIObjectByName("unit"+guiName+"Label["+i+"]").caption = i; if (g_Groups.groups[i].getTotalCount() == 0) button.hidden = true; else button.hidden = false; button.onpress = (function(i) { return function() { performGroup((Engine.HotkeyIsPressed("selection.add") ? "add" : "select"), i); } })(i); button.ondoublepress = (function(i) { return function() { performGroup("snap", i); } })(i); } var numButtons = i; var rowLength = 1; var numRows = Math.ceil(numButtons / rowLength); var buttonSideLength = Engine.GetGUIObjectByName("unit"+guiName+"Button[0]").size.bottom; var buttonSpacer = buttonSideLength+1; for (var i = 0; i < numRows; i++) layoutButtonRow(i, guiName, buttonSideLength, buttonSpacer, rowLength*i, rowLength*(i+1) ); } function updateDebug() { var simState = GetSimState(); var debug = Engine.GetGUIObjectByName("debug"); if (Engine.GetGUIObjectByName("devDisplayState").checked) { debug.hidden = false; } else { debug.hidden = true; return; } var conciseSimState = deepcopy(simState); conciseSimState.players = "<<>>"; var text = "simulation: " + uneval(conciseSimState); var selection = g_Selection.toList(); if (selection.length) { var entState = GetExtendedEntityState(selection[0]); if (entState) { var template = GetTemplateData(entState.template); text += "\n\nentity: {\n"; for (var k in entState) text += " "+k+":"+uneval(entState[k])+"\n"; text += "}\n\ntemplate: " + uneval(template); } } debug.caption = text; } function updatePlayerDisplay() { var simState = GetSimState(); var playerState = simState.players[Engine.GetPlayerID()]; if (!playerState) return; Engine.GetGUIObjectByName("resourceFood").caption = playerState.resourceCounts.food; Engine.GetGUIObjectByName("resourceWood").caption = playerState.resourceCounts.wood; Engine.GetGUIObjectByName("resourceStone").caption = playerState.resourceCounts.stone; Engine.GetGUIObjectByName("resourceMetal").caption = playerState.resourceCounts.metal; Engine.GetGUIObjectByName("resourcePop").caption = playerState.popCount + "/" + playerState.popLimit; g_IsTrainingBlocked = playerState.trainingBlocked; } function selectAndMoveTo(ent) { var entState = GetEntityState(ent); if (!entState || !entState.position) return; g_Selection.reset(); g_Selection.addList([ent]); var position = entState.position; Engine.CameraMoveTo(position.x, position.z); } function updateResearchDisplay() { var researchStarted = Engine.GuiInterfaceCall("GetStartedResearch", Engine.GetPlayerID()); if (!researchStarted) return; // Set up initial positioning. var buttonSideLength = Engine.GetGUIObjectByName("researchStartedButton[0]").size.right; for (var i = 0; i < 10; ++i) { var button = Engine.GetGUIObjectByName("researchStartedButton[" + i + "]"); var size = button.size; size.top = (4 + buttonSideLength) * i; size.bottom = size.top + buttonSideLength; button.size = size; } var numButtons = 0; for (var tech in researchStarted) { // Show at most 10 in-progress techs. if (numButtons >= 10) break; var template = GetTechnologyData(tech); var button = Engine.GetGUIObjectByName("researchStartedButton[" + numButtons + "]"); button.hidden = false; button.tooltip = getEntityNames(template); button.onpress = (function(e) { return function() { selectAndMoveTo(e) } })(researchStarted[tech].researcher); var icon = "stretched:session/portraits/" + template.icon; Engine.GetGUIObjectByName("researchStartedIcon[" + numButtons + "]").sprite = icon; // Scale the progress indicator. var size = Engine.GetGUIObjectByName("researchStartedProgressSlider[" + numButtons + "]").size; // Buttons are assumed to be square, so left/right offsets can be used for top/bottom. size.top = size.left + Math.round(researchStarted[tech].progress * (size.right - size.left)); Engine.GetGUIObjectByName("researchStartedProgressSlider[" + numButtons + "]").size = size; ++numButtons; } // Hide unused buttons. for (var i = numButtons; i < 10; ++i) Engine.GetGUIObjectByName("researchStartedButton[" + i + "]").hidden = true; } function updateTimeElapsedCounter() { var simState = GetSimState(); var speed = g_CurrentSpeed != 1.0 ? " (" + g_CurrentSpeed + "x)" : ""; var timeElapsedCounter = Engine.GetGUIObjectByName("timeElapsedCounter"); timeElapsedCounter.caption = timeToString(simState.timeElapsed) + speed; } // Toggles the display of status bars for all of the player's entities. function recalculateStatusBarDisplay() { if (g_ShowAllStatusBars) var entities = Engine.PickFriendlyEntitiesOnScreen(Engine.GetPlayerID()); else { var selected = g_Selection.toList(); for each (var ent in g_Selection.highlighted) selected.push(ent); // Remove selected entities from the 'all entities' array, to avoid disabling their status bars. var entities = Engine.GuiInterfaceCall("GetPlayerEntities").filter( function(idx) { return (selected.indexOf(idx) == -1); } ); } Engine.GuiInterfaceCall("SetStatusBars", { "entities": entities, "enabled": g_ShowAllStatusBars }); } // Update the additional list of entities to be highlighted. function updateAdditionalHighlight() { var entsAdd = []; // list of entities units to be highlighted var entsRemove = []; var highlighted = g_Selection.toList(); for each (var ent in g_Selection.highlighted) highlighted.push(ent); if (g_ShowGuarding) { // flag the guarding entities to add in this additional highlight for each (var sel in g_Selection.selected) { var state = GetEntityState(sel); if (!state.guard || !state.guard.entities.length) continue; for each (var ent in state.guard.entities) if (highlighted.indexOf(ent) == -1 && entsAdd.indexOf(ent) == -1) entsAdd.push(ent); } } if (g_ShowGuarded) { // flag the guarded entities to add in this additional highlight for each (var sel in g_Selection.selected) { var state = GetEntityState(sel); if (!state.unitAI || !state.unitAI.isGuarding) continue; var ent = state.unitAI.isGuarding; if (highlighted.indexOf(ent) == -1 && entsAdd.indexOf(ent) == -1) entsAdd.push(ent); } } // flag the entities to remove (from the previously added) from this additional highlight for each (var ent in g_AdditionalHighlight) if (highlighted.indexOf(ent) == -1 && entsAdd.indexOf(ent) == -1 && entsRemove.indexOf(ent) == -1) entsRemove.push(ent); _setHighlight(entsAdd , HIGHLIGHTED_ALPHA, true ); _setHighlight(entsRemove, 0 , false); g_AdditionalHighlight = entsAdd; } // Temporarily adding this here const AMBIENT_TEMPERATE = "temperate"; var currentAmbient; function playRandomAmbient(type) { switch (type) { case AMBIENT_TEMPERATE: // Seem to need the underscore at the end of "temperate" to avoid crash // (Might be caused by trying to randomly load day_temperate.xml) // currentAmbient = newRandomSound("ambient", "temperate_", "dayscape"); const AMBIENT = "audio/ambient/dayscape/day_temperate_gen_03.ogg"; Engine.PlayAmbientSound( AMBIENT, true ); break; default: Engine.Console_Write("Unrecognized ambient type: " + type); break; } } // Temporarily adding this here function stopAmbient() { if (currentAmbient) { currentAmbient.free(); currentAmbient = null; } } // Send a report on the game status to the lobby function reportGame(extendedSimState) { if (!Engine.HasXmppClient()) return; // Resources gathered and used var playerFoodGatheredString = ""; var playerWoodGatheredString = ""; var playerStoneGatheredString = ""; var playerMetalGatheredString = ""; var playerFoodUsedString = ""; var playerWoodUsedString = ""; var playerStoneUsedString = ""; var playerMetalUsedString = ""; // Resources exchanged var playerFoodBoughtString = ""; var playerWoodBoughtString = ""; var playerStoneBoughtString = ""; var playerMetalBoughtString = ""; var playerFoodSoldString = ""; var playerWoodSoldString = ""; var playerStoneSoldString = ""; var playerMetalSoldString = ""; var playerTradeIncomeString = ""; // Unit Stats var playerUnitsLostString = ""; var playerUnitsTrainedString = ""; var playerEnemyUnitsKilledString = ""; // Building stats var playerBuildingsConstructedString = ""; var playerBuildingsLostString = ""; var playerEnemyBuildingsDestroyedString = ""; var playerCivCentersBuiltString = ""; var playerEnemyCivCentersDestroyedString = ""; // Tribute var playerTributeSentString = ""; var playerTributeReceivedString = ""; // Various var mapName = Engine.GetMapSettings().Name; var playerStatesString = ""; var playerCivsString = ""; var playerPercentMapExploredString = ""; var playerTreasuresCollectedString = ""; // Serialize the statistics for each player into a comma-separated list. for each (var player in extendedSimState.players) { playerStatesString += player.state + ","; playerCivsString += player.civ + ","; playerFoodGatheredString += player.statistics.resourcesGathered.food + ","; playerWoodGatheredString += player.statistics.resourcesGathered.wood + ","; playerStoneGatheredString += player.statistics.resourcesGathered.stone + ","; playerMetalGatheredString += player.statistics.resourcesGathered.metal + ","; playerFoodUsedString += player.statistics.resourcesUsed.food + ","; playerWoodUsedString += player.statistics.resourcesUsed.wood + ","; playerStoneUsedString += player.statistics.resourcesUsed.stone + ","; playerMetalUsedString += player.statistics.resourcesUsed.metal + ","; playerUnitsLostString += player.statistics.unitsLost + ","; playerUnitsTrainedString += player.statistics.unitsTrained + ","; playerEnemyUnitsKilledString += player.statistics.enemyUnitsKilled + ","; playerBuildingsConstructedString += player.statistics.buildingsConstructed + ","; playerBuildingsLostString += player.statistics.buildingsLost + ","; playerEnemyBuildingsDestroyedString += player.statistics.enemyBuildingsDestroyed + ","; playerFoodBoughtString += player.statistics.resourcesBought.food + ","; playerWoodBoughtString += player.statistics.resourcesBought.wood + ","; playerStoneBoughtString += player.statistics.resourcesBought.stone + ","; playerMetalBoughtString += player.statistics.resourcesBought.metal + ","; playerFoodSoldString += player.statistics.resourcesSold.food + ","; playerWoodSoldString += player.statistics.resourcesSold.wood + ","; playerStoneSoldString += player.statistics.resourcesSold.stone + ","; playerMetalSoldString += player.statistics.resourcesSold.metal + ","; playerTributeSentString += player.statistics.tributesSent + ","; playerTributeReceivedString += player.statistics.tributesReceived + ","; playerPercentMapExploredString += player.statistics.precentMapExplored = ","; playerCivCentersBuiltString += player.statistics.civCentresBuilt + ","; playerEnemyCivCentersDestroyedString += player.statistics.enemyCivCentresDestroyed + ","; playerTreasuresCollectedString += player.statistics.treasuresCollected + ","; playerTradeIncomeString += player.statistics.tradeIncome + ","; } // Send the report with serialized data Engine.SendGameReport({ "timeElapsed" : extendedSimState.timeElapsed, "playerStates" : playerStatesString, "playerID": Engine.GetPlayerID(), "matchID": g_MatchID, "civs" : playerCivsString, "mapName" : mapName, "foodGathered": playerFoodGatheredString, "woodGathered": playerWoodGatheredString, "stoneGathered": playerStoneGatheredString, "metalGathered": playerMetalGatheredString, "foodUsed": playerFoodUsedString, "woodUsed": playerWoodUsedString, "stoneUsed": playerStoneUsedString, "metalUsed": playerMetalUsedString, "unitsLost": playerUnitsLostString, "unitsTrained": playerUnitsTrainedString, "enemyUnitsKilled": playerEnemyUnitsKilledString, "buildingsLost": playerBuildingsLostString, "buildingsConstructed": playerBuildingsConstructedString, "enemyBuildingsDestroyed": playerEnemyBuildingsDestroyedString, "foodBought": playerFoodBoughtString, "woodBought": playerWoodBoughtString, "stoneBought": playerStoneBoughtString, "metalBought": playerMetalBoughtString, "foodSold": playerFoodSoldString, "woodSold": playerWoodSoldString, "stoneSold": playerStoneSoldString, "metalSold": playerMetalSoldString, "tributeSent": playerTributeSentString, "tributeReceived": playerTributeReceivedString, "precentMapExplored": playerPercentMapExploredString, "civCentersBuilt": playerCivCentersBuiltString, "enemyCivCentersDestroyed": playerEnemyCivCentersDestroyedString, "treasuresCollected": playerTreasuresCollectedString, "tradeIncome": playerTradeIncomeString }); } Index: ps/trunk/binaries/data/mods/public/gui/session/session.xml =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/session.xml (revision 14523) +++ ps/trunk/binaries/data/mods/public/gui/session/session.xml (revision 14524) @@ -1,1333 +1,1347 @@