diff --git a/binaries/data/mods/public/gui/session_new/input.js b/binaries/data/mods/public/gui/session_new/input.js index 34123f2225..0ff4db1190 100644 --- a/binaries/data/mods/public/gui/session_new/input.js +++ b/binaries/data/mods/public/gui/session_new/input.js @@ -3,6 +3,8 @@ const SDL_BUTTON_MIDDLE = 2; const SDL_BUTTON_RIGHT = 3; const SDLK_RSHIFT = 303; const SDLK_LSHIFT = 304; +const SDLK_RCTRL = 305; +const SDLK_LCTRL = 306; const MAX_SELECTION_SIZE = 32; // Limits selection size and ensures that there will not be too many selection items in the GUI @@ -30,6 +32,8 @@ var mouseIsOverObject = false; var specialKeyStates = {}; specialKeyStates[SDLK_RSHIFT] = 0; specialKeyStates[SDLK_LSHIFT] = 0; +specialKeyStates[SDLK_RCTRL] = 0; +specialKeyStates[SDLK_LCTRL] = 0; // (TODO: maybe we should fix the hotkey system to be usable in this situation, // rather than hardcoding Shift into this code?) @@ -313,6 +317,7 @@ function handleInputBeforeGui(ev, hoveredObject) g_Selection.setHighlightList([]); g_Selection.reset(); g_Selection.addList(ents); + g_Selection.CreateSelectionGroups(); inputState = INPUT_NORMAL; return true; @@ -719,12 +724,12 @@ function removeFromTrainingQueue(entity, id) } // Called by unit selection buttons -function changePrimarySelectionGroup(index) +function changePrimarySelectionGroup(templateName) { - if (specialKeyStates[SDLK_RSHIFT] || specialKeyStates[SDLK_LSHIFT]) - g_Selection.makePrimarySelection(index, true); + if (specialKeyStates[SDLK_RCTRL] || specialKeyStates[SDLK_LCTRL]) + g_Selection.makePrimarySelection(templateName, true); else - g_Selection.makePrimarySelection(index, false); + g_Selection.makePrimarySelection(templateName, false); } // Performs the specified command (delete, town bell, repair, etc.) @@ -732,13 +737,25 @@ function performCommand(entity, commandName) { if (entity) { - switch (commandName) + var entState = GetEntityState(entity); + var template = GetTemplateData(entState.template); + var unitName = getEntityName(template); + + var player = Engine.GetPlayerID(); + if (entState.player == player || g_DevSettings.controlAll) { - case "delete": - Engine.PostNetworkCommand({"type": "delete-entity", "entity": entity}); - break; - default: - break; + switch (commandName) + { + case "delete": + var deleteFunction = function () { Engine.PostNetworkCommand({"type": "delete-entity", "entity": entity}); }; + var btCaptions = ["Yes", "No"]; + var btCode = [deleteFunction, null]; + messageBox(320, 180, "Are you sure you want to delete: " + unitName + "?", "Confirmation", 0, btCaptions, btCode); + + break; + default: + break; + } } } } diff --git a/binaries/data/mods/public/gui/session_new/selection.js b/binaries/data/mods/public/gui/session_new/selection.js index 5994f4b772..faa48d62b9 100644 --- a/binaries/data/mods/public/gui/session_new/selection.js +++ b/binaries/data/mods/public/gui/session_new/selection.js @@ -15,6 +15,96 @@ function _playSound(ent) Engine.GuiInterfaceCall("PlaySound", { "name":"select", "entity":ent }); } +//-------------------------------- -------------------------------- -------------------------------- +// EntityGroup class for managing grouped entities +//-------------------------------- -------------------------------- -------------------------------- +function EntityGroup() +{ + this.groupCounts = {}; + this.groupEntIDs = {}; +} + +EntityGroup.prototype.create = function(entIDs) +{ + this.groupCounts = {}; + var rankedTemplates = {}; + + for each (var entID in entIDs) + { + var entState = GetEntityState(entID); + var rank = entState.identity.rank; + var templateName = entState.template; + var template = GetTemplateData(templateName); + var unitName = template.name.specific || template.name.generic || "???"; + + if (rank) + { + if (rankedTemplates[unitName]) + { + this.groupCounts[rankedTemplates[unitName]] += 1; + this.groupEntIDs[unitName].push(entID); + } + else + { + rankedTemplates[unitName] = templateName; + this.groupCounts[rankedTemplates[unitName]] = 1; + this.groupEntIDs[unitName] = [entID]; + } + } + else + { + if (this.groupCounts[templateName]) + { + this.groupCounts[templateName] += 1; + this.groupEntIDs[unitName].push(entID); + } + else + { + this.groupCounts[templateName] = 1; + this.groupEntIDs[unitName] = [entID]; + } + } + } +}; + +EntityGroup.prototype.remove = function(templateName) +{ + delete this.groupCounts[templateName]; +}; + +EntityGroup.prototype.getCount = function(templateName) +{ + if (this.groupCounts[templateName]) + return this.groupCounts[templateName]; + else + return 0; +}; + +EntityGroup.prototype.getTemplateNames = function() +{ + var templateNames = []; + for (var templateName in this.groupCounts) + templateNames.push(templateName); + return templateNames; +}; + +EntityGroup.prototype.getEntsByUnitName = function(unitName) +{ + return this.groupEntIDs[unitName]; +}; + + +EntityGroup.prototype.getEntsByUnitNameInverse = function(unitName) +{ + var ents = []; + + for (var name in this.groupEntIDs) + if (name != unitName) + ents = ents.concat(this.groupEntIDs[name]); + + return ents; +}; + //-------------------------------- -------------------------------- -------------------------------- // EntitySelection class for managing the entity selection list and the primary selection //-------------------------------- -------------------------------- -------------------------------- @@ -33,36 +123,41 @@ function EntitySelection() // Public properties: //-------------------------------- this.dirty = false; // set whenever the selection has changed + this.groups = new EntityGroup(); } // Deselect everything but entities of the chosen type if the modifier is true // otherwise deselect just the chosen entity -EntitySelection.prototype.makePrimarySelection = function(primaryIndex, modifierKey) +EntitySelection.prototype.makePrimarySelection = function(primaryTemplateName, modifierKey) { - var ents = []; var selection = this.toList(); + var entID; + + // Find an entID of a unit of the same type + for (var i = 0; i < selection.length; i++) + { + var entState = GetEntityState(selection[i]); + if (!entState) + continue; + if (entState.template == primaryTemplateName) + entID = selection[i]; + } + + var primaryEntState = GetEntityState(entID); + if (!primaryEntState) + return; + var primaryTemplate = GetTemplateData(primaryTemplateName); + var primaryUnitName = primaryTemplate.name.specific || primaryTemplate.name.generic || "???"; + var ents = []; if (modifierKey) - { - var primaryEntState = GetEntityState(selection[primaryIndex]); - if (!primaryEntState) - return; - - for (var i = 0; i < selection.length; i++) - { - var entState = GetEntityState(selection[i]); - if (!entState) - continue; - if (entState.template == primaryEntState.template) - ents.push(selection[i]); - } - } + ents = this.groups.getEntsByUnitNameInverse(primaryUnitName); else - { - ents.push(selection[primaryIndex]); - } + ents = this.groups.getEntsByUnitName(primaryUnitName); + this.reset(); this.addList(ents); + this.CreateSelectionGroups(); } // Get a list of the template names @@ -80,6 +175,12 @@ EntitySelection.prototype.getTemplateNames = function() return templateNames; } +// Make selection groups +EntitySelection.prototype.CreateSelectionGroups = function() +{ + this.groups.create(this.toList()); +}; + // Update the selection to take care of changes (like units that have been killed) EntitySelection.prototype.update = function() { @@ -94,7 +195,10 @@ EntitySelection.prototype.update = function() } } if (numberRemoved > 0) + { this.dirty = true; + this.groups.create(this.toList()); + } }; EntitySelection.prototype.toggle = function(ent) @@ -138,6 +242,7 @@ EntitySelection.prototype.reset = function() _setMotionOverlay(this.toList(), false); this.selected = {}; this.dirty = true; + this.groups = new EntityGroup(); }; EntitySelection.prototype.toList = function() diff --git a/binaries/data/mods/public/gui/session_new/selection_details.js b/binaries/data/mods/public/gui/session_new/selection_details.js index c727124bcb..9b5eb77675 100644 --- a/binaries/data/mods/public/gui/session_new/selection_details.js +++ b/binaries/data/mods/public/gui/session_new/selection_details.js @@ -2,31 +2,31 @@ const RESOURCE_ICON_CELL_IDS = {food : 0, wood : 1, stone : 2, metal : 3}; function layoutSelectionMultiple() { - getGUIObjectByName("sdSpecific").hidden = true; - getGUIObjectByName("sdIcon").hidden = true; - getGUIObjectByName("sdStatsArea").hidden = true; - getGUIObjectByName("sdHealth").hidden = true; - getGUIObjectByName("sdStamina").hidden = true; +// getGUIObjectByName("specific").hidden = true; +// getGUIObjectByName("iconBorder").hidden = true; +// getGUIObjectByName("statsArea").hidden = true; +// getGUIObjectByName("health").hidden = true; +// getGUIObjectByName("stamina").hidden = true; } function layoutSelectionSingle(entState) { - getGUIObjectByName("sdSpecific").hidden = false; - getGUIObjectByName("sdIcon").hidden = false; - getGUIObjectByName("sdStatsArea").hidden = false; - + getGUIObjectByName("specific").hidden = false; + getGUIObjectByName("iconBorder").hidden = false; +// getGUIObjectByName("sdStatsArea").hidden = false; + if (entState.hitpoints != undefined) - getGUIObjectByName("sdHealth").hidden = false; + getGUIObjectByName("health").hidden = false; else - getGUIObjectByName("sdHealth").hidden = true; + getGUIObjectByName("health").hidden = true; var player = Engine.GetPlayerID(); if (entState.player == player || g_DevSettings.controlAll) { if (entState.stamina != undefined) - getGUIObjectByName("sdStamina").hidden = false; + getGUIObjectByName("stamina").hidden = false; else - getGUIObjectByName("sdStamina").hidden = true; + getGUIObjectByName("stamina").hidden = true; } } @@ -37,99 +37,93 @@ function displayGeneralInfo(entState, template) var specificName = "[font=\"serif-bold-18\"]" + template.name.specific + "[/font]"; var genericName = template.name.generic != template.name.specific? template.name.generic : ""; - var rank = entState.identity.rank? "[font=\"serif-bold-18\"]" + entState.identity.rank + " [/font]" : ""; var civName = getFormalCivName(toTitleCase(g_Players[entState.player].civ)); var playerName = g_Players[entState.player].name; var playerColor = g_Players[entState.player].color.r + " " + g_Players[entState.player].color.g + " " + g_Players[entState.player].color.b+ " " + g_Players[entState.player].color.a; + // Rank + getGUIObjectByName("rankIcon").cell_id = getRankIconCellId(entState); + // Hitpoints var hitpoints = ""; if (entState.hitpoints) { - var unitHealthBar = getGUIObjectByName("sdHealthBar"); + var unitHealthBar = getGUIObjectByName("healthBar"); var healthSize = unitHealthBar.size; - healthSize.rright = 100*Math.max(0, Math.min(1, entState.hitpoints / entState.maxHitpoints)); + healthSize.rtop = 100-100*Math.max(0, Math.min(1, entState.hitpoints / entState.maxHitpoints)); unitHealthBar.size = healthSize; - + hitpoints = "[font=\"serif-bold-13\"]Hitpoints [/font]" + entState.hitpoints + "/" + entState.maxHitpoints; - getGUIObjectByName("sdHealth").tooltip = hitpoints; + getGUIObjectByName("health").tooltip = hitpoints; } // Resource stats var resources = ""; var resourceType = ""; - var resourceCellID = -1; if (entState.resourceSupply) { - resources = Math.ceil(+entState.resourceSupply.amount) + "/" + entState.resourceSupply.max + " "; + resources = Math.ceil(+entState.resourceSupply.amount) + "/" + entState.resourceSupply.max; resourceType = entState.resourceSupply.type["generic"]; - resourceCellID = RESOURCE_ICON_CELL_IDS[resourceType]; - getGUIObjectByName("sdResources").hidden = false; - getGUIObjectByName("sdAttack").hidden = true; - getGUIObjectByName("sdArmour").hidden = true; + var unitResourceBar = getGUIObjectByName("resourceBar"); + var resourceSize = unitResourceBar.size; + + resourceSize.rtop = 100-100*Math.max(0, Math.min(1, +entState.resourceSupply.amount / entState.resourceSupply.max)); + unitResourceBar.size = resourceSize; + + var unitResources = getGUIObjectByName("resources"); + unitResources.tooltip = "[font=\"serif-bold-13\"]Resources: [/font]" + resources + " " + resourceType; + + if (!entState.hitpoints) + unitResources.size = getGUIObjectByName("health").size; + else + unitResources.size = getGUIObjectByName("stamina").size; + + getGUIObjectByName("resources").hidden = false; } else { - getGUIObjectByName("sdResources").hidden = true; - getGUIObjectByName("sdAttack").hidden = false; - getGUIObjectByName("sdArmour").hidden = false; + getGUIObjectByName("resources").hidden = true; } // Set Captions - getGUIObjectByName("sdSpecific").caption = rank + specificName; - getGUIObjectByName("sdPlayer").caption = playerName; - getGUIObjectByName("sdPlayer").textcolor = playerColor; - getGUIObjectByName("sdAttackStats").caption = damageTypesToTextStacked(entState.attack); - getGUIObjectByName("sdArmourStats").caption = damageTypesToTextStacked(entState.armour); - getGUIObjectByName("sdResourceStats").caption = resources; - getGUIObjectByName("sdResourceIcon").cell_id = resourceCellID; + getGUIObjectByName("specific").caption = specificName; + getGUIObjectByName("player").caption = playerName; + getGUIObjectByName("player").textcolor = playerColor; // Icon image if (template.icon_sheet && typeof template.icon_cell) { - getGUIObjectByName("sdIconImage").sprite = template.icon_sheet; - getGUIObjectByName("sdIconImage").cell_id = template.icon_cell; + getGUIObjectByName("icon").sprite = template.icon_sheet; + getGUIObjectByName("icon").cell_id = template.icon_cell; } else { // TODO: we should require all entities to have icons, so this case never occurs - getGUIObjectByName("sdIconImage").sprite = "bkFillBlack"; + getGUIObjectByName("icon").sprite = "bkFillBlack"; } - // TODO: need to change color of icon outline with the playerColor - //getGUIObjectByName("sdIconOutline"); - // Tooltips // getGUIObjectByName("sdSpecific").tooltip = genericName; - getGUIObjectByName("sdPlayer").tooltip = civName != GAIA? civName : ""; // Don't need civ tooltip for Gaia Player - redundant - getGUIObjectByName("sdHealth").tooltip = hitpoints; + getGUIObjectByName("attackIcon").tooltip = damageTypesToText(entState.attack); + getGUIObjectByName("armourIcon").tooltip = damageTypesToText(entState.armour); + getGUIObjectByName("player").tooltip = civName != GAIA? civName : ""; // Don't need civ tooltip for Gaia Player - redundant + getGUIObjectByName("health").tooltip = hitpoints; // Icon Tooltip var iconTooltip = ""; - + if (genericName) iconTooltip = "[font=\"serif-bold-16\"]" + genericName + "[/font]"; if (template.tooltip) iconTooltip += "\n[font=\"serif-13\"]" + template.tooltip + "[/font]"; - - /* - if (entState.hitpoints) - iconTooltip += "\n" + hitpoints; - if (entState.attack) - iconTooltip += "\n[font=\"serif-bold-13\"]Attack: [/font]" + damageTypesToText(entState.attack); - if (entState.armour) - iconTooltip += "\n[font=\"serif-bold-13\"]Armour: [/font]" + damageTypesToText(entState.armour); - if (entState.resourceSupply) - iconTooltip += "\n[font=\"serif-bold-13\"]Resources: [/font]" + resources + "[font=\"serif-12\"]" + resourceType + "[/font]"; - */ - getGUIObjectByName("sdIcon").tooltip = iconTooltip; + getGUIObjectByName("iconBorder").tooltip = iconTooltip; } // Updates middle entity Selection Details Panel @@ -145,6 +139,7 @@ function updateSelectionDetails() { detailsPanel.hidden = true; commandsPanel.hidden = true; + getGUIObjectByName("unitSelectionPanel").hidden = true; return; } diff --git a/binaries/data/mods/public/gui/session_new/session.xml b/binaries/data/mods/public/gui/session_new/session.xml index 12718c7120..ef01ec4251 100644 --- a/binaries/data/mods/public/gui/session_new/session.xml +++ b/binaries/data/mods/public/gui/session_new/session.xml @@ -31,13 +31,13 @@ - - - + + + - + @@ -184,7 +184,7 @@ Enable Shadows @@ -295,162 +295,170 @@ - + - - - - - - handleMinimapEvent(arguments[0]); - + + + + - - - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - - - - - - - + + + + - + + + + + + + + + + + + + handleMinimapEvent(arguments[0]); + + + + +