Index: ps/trunk/binaries/data/config/default.cfg =================================================================== --- ps/trunk/binaries/data/config/default.cfg (revision 23475) +++ ps/trunk/binaries/data/config/default.cfg (revision 23476) @@ -1,525 +1,526 @@ ; Global Configuration Settings ; ; ************************************************************** ; * DO NOT EDIT THIS FILE if you want personal customisations: * ; * create a text file called "local.cfg" instead, and copy * ; * the lines from this file that you want to change. * ; * * ; * If a setting is part of a section (for instance [hotkey]) * ; * you need to append the section name at the beginning of * ; * your custom line (for instance you need to write * ; * "hotkey.pause = Space" if you want to change the pausing * ; * hotkey to the spacebar). * ; * * ; * On Linux, create: * ; * $XDG_CONFIG_HOME/0ad/config/local.cfg * ; * (Note: $XDG_CONFIG_HOME defaults to ~/.config) * ; * * ; * On OS X, create: * ; * ~/Library/Application\ Support/0ad/config/local.cfg * ; * * ; * On Windows, create: * ; * %appdata%\0ad\config\local.cfg * ; * * ; ************************************************************** ; Enable/disable windowed mode by default. (Use Alt+Enter to toggle in the game.) windowed = false ; Show detailed tooltips (Unit stats) showdetailedtooltips = false ; Pause the game on window focus loss (Only applicable to single player mode) pauseonfocusloss = true ; Persist settings after leaving the game setup screen persistmatchsettings = true ; Default player name to use in multiplayer ; playername = "anonymous" ; Default server name or IP to use in multiplayer multiplayerserver = "127.0.0.1" ; Force a particular resolution. (If these are 0, the default is ; to keep the current desktop resolution in fullscreen mode or to ; use 1024x768 in windowed mode.) xres = 0 yres = 0 ; Force a non-standard bit depth (if 0 then use the current desktop bit depth) bpp = 0 ; Preferred display (for multidisplay setups, only works with SDL 2.0) display = 0 ; Emulate right-click with Ctrl+Click on Mac mice macmouse = false ; System settings: ; if false, actors won't be rendered but anything entity will be. renderactors = true watereffects=true ; When disabled, force usage of the fixed pipeline water. This is faster, but really, really ugly. waterfancyeffects = false waterrealdepth = true waterrefraction = true waterreflection = true shadowsonwater = false shadows = true shadowquality = 0 ; Shadow map resolution. (-2 - Very Low, -1 - Low, 0 - Medium, 1 - High, 2 - Very High) ; High values can crash the game when using a graphics card with low memory! shadowpcf = true shadowsfixed = false ; When enabled shadows are rendered only on the shadowsfixeddistance = 300.0 ; fixed distance and without swimming effect. vsync = false particles = true fog = true silhouettes = true showsky = true nos3tc = false noautomipmap = true novbo = false noframebufferobject = false ; Disable hardware cursors nohwcursor = false ; Linux only: Set the driconf force_s3tc_enable option at startup, ; for compressed texture support force_s3tc_enable = true ; Specify the render path. This can be one of: ; default Automatically select one of the below, depending on system capabilities ; fixed Only use OpenGL fixed function pipeline ; shader Use vertex/fragment shaders for transform and lighting where possible ; Using 'fixed' instead of 'default' may work around some graphics-related problems, ; but will reduce performance and features when a modern graphics card is available. renderpath = default ;;;;; EXPERIMENTAL ;;;;; ; Prefer GLSL shaders over ARB shaders. Allows fancier graphical effects. preferglsl = false ; Experimental probably-non-working GPU skinning support; requires preferglsl; use at own risk gpuskinning = false ; Use smooth LOS interpolation smoothlos = false ; Use screen-space postprocessing filters (HDR, bloom, DOF, etc). Incompatible with fixed renderpath. postproc = false ; Quality level of shader effects (set to 10 to display all effects) materialmgr.quality = 2.0 ; Maximum distance to display parallax effect. Set to 0 to disable parallax. materialmgr.PARALLAX_DIST.max = 150 ; Maximum distance to display high quality parallax effect. materialmgr.PARALLAX_HQ_DIST.max = 75 ; Maximum distance to display very high quality parallax effect. Set to 30 to enable. materialmgr.PARALLAX_VHQ_DIST.max = 0 ;;;;;;;;;;;;;;;;;;;;;;;; ; Replace alpha-blending with alpha-testing, for performance experiments forcealphatest = false ; Color of the sky (in "r g b" format) skycolor = "0 0 0" [adaptivefps] session = 60 ; Throttle FPS in running games (prevents 100% CPU workload). menu = 60 ; Throttle FPS in menus only. [hotkey] ; Each one of the specified keys will trigger the action on the left ; for multiple-key combinations, separate keys with '+'. ; See keys.txt for the list of key names. ; > SYSTEM SETTINGS exit = "Ctrl+Break", "Super+Q" ; Exit to desktop cancel = Escape ; Close or cancel the current dialog box/popup confirm = Return ; Confirm the current command pause = Pause ; Pause/unpause game screenshot = F2 ; Take PNG screenshot bigscreenshot = "Shift+F2" ; Take large BMP screenshot togglefullscreen = "Alt+Return" ; Toggle fullscreen/windowed mode screenshot.watermark = "Alt+K" ; Toggle product/company watermark for official screenshots wireframe = "Alt+Shift+W" ; Toggle wireframe mode silhouettes = "Alt+Shift+S" ; Toggle unit silhouettes showsky = "Alt+Z" ; Toggle sky ; > DIALOG HOTKEYS summary = "Ctrl+Tab" ; Toggle in-game summary lobby = "Alt+L" ; Show the multiplayer lobby in a dialog window. structree = "Alt+Shift+T" ; Show structure tree civinfo = "Alt+Shift+H" ; Show civilization info ; > CLIPBOARD CONTROLS copy = "Ctrl+C" ; Copy to clipboard paste = "Ctrl+V" ; Paste from clipboard cut = "Ctrl+X" ; Cut selected text and copy to the clipboard ; > CONSOLE SETTINGS console.toggle = BackQuote, F9 ; Open/close console ; > OVERLAY KEYS fps.toggle = "Alt+F" ; Toggle frame counter realtime.toggle = "Alt+T" ; Toggle current display of computer time session.devcommands.toggle = "Alt+D" ; Toggle developer commands panel timeelapsedcounter.toggle = "F12" ; Toggle time elapsed counter ceasefirecounter.toggle = unused ; Toggle ceasefire counter session.showstatusbars = Tab ; Toggle display of status bars session.highlightguarding = PgDn ; Toggle highlight of guarding units session.highlightguarded = PgUp ; Toggle highlight of guarded units session.toggleattackrange = "Alt+C" ; Toggle display of attack range overlays of selected defensive structures session.toggleaurasrange = "Alt+V" ; Toggle display of aura range overlays of selected units and structures session.togglehealrange = "Alt+B" ; Toggle display of heal range overlays of selected units session.diplomacycolors = "Alt+X" ; Toggle diplomacy colors ; > HOTKEYS ONLY chat = Return ; Toggle chat window teamchat = "T" ; Toggle chat window in team chat mode privatechat = "L" ; Toggle chat window and select the previous private chat partner ; > QUICKSAVE quicksave = "Shift+F5" quickload = "Shift+F8" [hotkey.camera] reset = "R" ; Reset camera rotation to default. follow = "F" ; Follow the first unit in the selection rallypointfocus = unused ; Focus the camera on the rally point of the selected building zoom.in = Plus, Equals, NumPlus ; Zoom camera in (continuous control) zoom.out = Minus, NumMinus ; Zoom camera out (continuous control) zoom.wheel.in = WheelUp ; Zoom camera in (stepped control) zoom.wheel.out = WheelDown ; Zoom camera out (stepped control) rotate.up = "Ctrl+UpArrow", "Ctrl+W" ; Rotate camera to look upwards rotate.down = "Ctrl+DownArrow", "Ctrl+S" ; Rotate camera to look downwards rotate.cw = "Ctrl+LeftArrow", "Ctrl+A", Q ; Rotate camera clockwise around terrain rotate.ccw = "Ctrl+RightArrow", "Ctrl+D", E ; Rotate camera anticlockwise around terrain rotate.wheel.cw = "Shift+WheelUp", MouseX1 ; Rotate camera clockwise around terrain (stepped control) rotate.wheel.ccw = "Shift+WheelDown", MouseX2 ; Rotate camera anticlockwise around terrain (stepped control) pan = MouseMiddle ; Enable scrolling by moving mouse left = A, LeftArrow ; Scroll or rotate left right = D, RightArrow ; Scroll or rotate right up = W, UpArrow ; Scroll or rotate up/forwards down = S, DownArrow ; Scroll or rotate down/backwards scroll.speed.increase = "Ctrl+Shift+S" ; Increase scroll speed scroll.speed.decrease = "Ctrl+Alt+S" ; Decrease scroll speed rotate.speed.increase = "Ctrl+Shift+R" ; Increase rotation speed rotate.speed.decrease = "Ctrl+Alt+R" ; Decrease rotation speed zoom.speed.increase = "Ctrl+Shift+Z" ; Increase zoom speed zoom.speed.decrease = "Ctrl+Alt+Z" ; Decrease zoom speed [hotkey.camera.jump] 1 = F5 ; Jump to position N 2 = F6 3 = F7 4 = F8 ;5 = ;6 = ;7 = ;8 = ;9 = ;10 = [hotkey.camera.jump.set] 1 = "Ctrl+F5" ; Set jump position N 2 = "Ctrl+F6" 3 = "Ctrl+F7" 4 = "Ctrl+F8" ;5 = ;6 = ;7 = ;8 = ;9 = ;10 = [hotkey.profile] toggle = "F11" ; Enable/disable real-time profiler save = "Shift+F11" ; Save current profiler data to logs/profile.txt [hotkey.profile2] toggle = "Ctrl+F11" ; Enable/disable HTTP/GPU modes for new profiler [hotkey.selection] add = Shift ; Add units to selection militaryonly = Alt ; Add only military units to the selection nonmilitaryonly = "Alt+Y" ; Add only non-military units to the selection idleonly = "I" ; Select only idle units woundedonly = "O" ; Select only wounded units remove = Ctrl ; Remove units from selection cancel = Esc ; Un-select all units and cancel building placement idleworker = Period ; Select next idle worker idlewarrior = ForwardSlash ; Select next idle warrior idleunit = BackSlash ; Select next idle unit offscreen = Alt ; Include offscreen units in selection [hotkey.selection.group.add] 0 = "Shift+0" 1 = "Shift+1" 2 = "Shift+2" 3 = "Shift+3" 4 = "Shift+4" 5 = "Shift+5" 6 = "Shift+6" 7 = "Shift+7" 8 = "Shift+8" 9 = "Shift+9" [hotkey.selection.group.save] 0 = "Ctrl+0" 1 = "Ctrl+1" 2 = "Ctrl+2" 3 = "Ctrl+3" 4 = "Ctrl+4" 5 = "Ctrl+5" 6 = "Ctrl+6" 7 = "Ctrl+7" 8 = "Ctrl+8" 9 = "Ctrl+9" [hotkey.selection.group.select] 0 = 0 1 = 1 2 = 2 3 = 3 4 = 4 5 = 5 6 = 6 7 = 7 8 = 8 9 = 9 [hotkey.session] kill = Delete ; Destroy selected units stop = "H" ; Stop the current action backtowork = "Y" ; The unit will go back to work unload = "U" ; Unload garrisoned units when a building/mechanical unit is selected move = unused ; Modifier to move to a point instead of another action (e.g. gather) attack = Ctrl ; Modifier to attack instead of another action (e.g. capture) attackmove = Ctrl ; Modifier to attackmove when clicking on a point attackmoveUnit = "Ctrl+Q" ; Modifier to attackmove targeting only units when clicking on a point (should contain the attackmove keys) garrison = Ctrl ; Modifier to garrison when clicking on building autorallypoint = Ctrl ; Modifier to set the rally point on the building itself guard = "G" ; Modifier to escort/guard when clicking on unit/building patrol = "P" ; Modifier to patrol a unit repair = "J" ; Modifier to repair when clicking on building/mechanical unit queue = Shift ; Modifier to queue unit orders instead of replacing orderone = Alt ; Modifier to order only one entity in selection. batchtrain = Shift ; Modifier to train units in batches massbarter = Shift ; Modifier to barter bunch of resources masstribute = Shift ; Modifier to tribute bunch of resources noconfirmation = Shift ; Do not ask confirmation when deleting a building/unit fulltradeswap = Shift ; Modifier to put the desired trade resource to 100% unloadtype = Shift ; Modifier to unload all units of type deselectgroup = Ctrl ; Modifier to deselect units when clicking group icon, instead of selecting rotate.cw = RightBracket ; Rotate building placement preview clockwise rotate.ccw = LeftBracket ; Rotate building placement preview anticlockwise snaptoedges = Ctrl ; Modifier to align new structures with nearby existing structure [hotkey.session.gui] toggle = "Alt+G" ; Toggle visibility of session GUI menu.toggle = "F10" ; Toggle in-game menu diplomacy.toggle = "Ctrl+H" ; Toggle in-game diplomacy page barter.toggle = "Ctrl+B" ; Toggle in-game barter/trade page objectives.toggle = "Ctrl+O" ; Toggle in-game objectives page tutorial.toggle = "Ctrl+P" ; Toggle in-game tutorial panel [hotkey.session.savedgames] delete = Delete ; Delete the selected saved game asking confirmation noconfirmation = Shift ; Do not ask confirmation when deleting a game [hotkey.session.queueunit] ; > UNIT TRAINING 1 = "Z" ; add first unit type to queue 2 = "X" ; add second unit type to queue 3 = "C" ; add third unit type to queue 4 = "V" ; add fourth unit type to queue 5 = "B" ; add fivth unit type to queue 6 = "N" ; add sixth unit type to queue 7 = "M" ; add seventh unit type to queue 8 = Comma ; add eighth unit type to queue [hotkey.session.timewarp] fastforward = Space ; If timewarp mode enabled, speed up the game rewind = Backspace ; If timewarp mode enabled, go back to earlier point in the game [hotkey.tab] next = "Tab", "Alt+S" ; Show the next tab prev = "Shift+Tab", "Alt+W" ; Show the previous tab [hotkey.text] ; > GUI TEXTBOX HOTKEYS delete.left = "Ctrl+Backspace" ; Delete word to the left of cursor delete.right = "Ctrl+Del" ; Delete word to the right of cursor move.left = "Ctrl+LeftArrow" ; Move cursor to start of word to the left of cursor move.right = "Ctrl+RightArrow" ; Move cursor to start of word to the right of cursor [gui] cursorblinkrate = 0.5 ; Cursor blink rate in seconds (0.0 to disable blinking) scale = 1.0 ; GUI scaling factor, for improved compatibility with 4K displays [gui.gamesetup] enabletips = true ; Enable/Disable tips during gamesetup (for newcomers) assignplayers = everyone ; Whether to assign joining clients to free playerslots. Possible values: everyone, buddies, disabled. aidifficulty = 3 ; Difficulty level, from 0 (easiest) to 5 (hardest) aibehavior = "random" ; Default behavior of the AI (random, balanced, aggressive or defensive) settingsslide = true ; Enable/Disable settings panel slide [gui.loadingscreen] progressdescription = false ; Whether to display the progress percent or a textual description [gui.session] camerajump.threshold = 40 ; How close do we have to be to the actual location in order to jump back to the previous one? timeelapsedcounter = false ; Show the game duration in the top right corner ceasefirecounter = false ; Show the remaining ceasefire time in the top right corner batchtrainingsize = 5 ; Number of units to be trained per batch by default (when pressing the hotkey) scrollbatchratio = 1 ; Number of times you have to scroll to increase/decrease the batchsize by 1 woundedunithotkeythreshold = 33 ; The wounded unit hotkey considers the selected units as wounded if their health percentage falls below this number attackrange = true ; Display attack range overlays of selected defensive structures aurasrange = true ; Display aura range overlays of selected units and structures healrange = true ; Display heal range overlays of selected units rankabovestatusbar = true ; Show rank icons above status bars experiencestatusbar = true ; Show an experience status bar above each selected unit respoptooltipsort = 0 ; Sorting players in the resources and population tooltip by value (0 - no sort, -1 - ascending, 1 - descending) snaptoedges = "disabled" ; Possible values: disabled, enabled. snaptoedgesdistancethreshold = 15 ; On which distance we don't snap to edges +disjointcontrolgroups = "true" ; Whether control groups are disjoint sets or entities can be in multiple control groups at the same time. [gui.session.minimap] blinkduration = 1.7 ; The blink duration while pinging pingduration = 50.0 ; The duration for which an entity will be pinged after an attack notification [gui.session.notifications] attack = true ; Show a chat notification if you are attacked by another player tribute = true ; Show a chat notification if an ally tributes resources to another team member if teams are locked, and all tributes in observer mode barter = true ; Show a chat notification to observers when a player bartered resources phase = completed ; Show a chat notification if you or an ally have started, aborted or completed a new phase, and phases of all players in observer mode. Possible values: none, completed, all. [gui.splashscreen] enable = true ; Enable/disable the splashscreen version = 0 ; Splashscreen version (date of last modification). By default, 0 to force splashscreen to appear at first launch [gui.session.diplomacycolors] self = "21 55 149" ; Color of your units when diplomacy colors are enabled ally = "86 180 31" ; Color of allies when diplomacy colors are enabled neutral = "231 200 5" ; Color of neutral players when diplomacy colors are enabled enemy = "150 20 20" ; Color of enemies when diplomacy colors are enabled [joystick] ; EXPERIMENTAL: joystick/gamepad settings enable = false deadzone = 8192 [joystick.camera] pan.x = 0 pan.y = 1 rotate.x = 3 rotate.y = 2 zoom.in = 5 zoom.out = 4 [chat] timestamp = true ; Show at which time chat messages have been sent [chat.session] extended = true ; Whether to display the chat history [lobby] history = 0 ; Number of past messages to display on join room = "arena24" ; Default MUC room to join server = "lobby.wildfiregames.com" ; Address of lobby server tls = true ; Whether to use TLS encryption when connecting to the server. verify_certificate = false ; Whether to reject connecting to the lobby if the TLS certificate is invalid (TODO: wait for Gloox GnuTLS trust implementation to be fixed) terms_url = "https://trac.wildfiregames.com/browser/ps/trunk/binaries/data/mods/public/gui/prelobby/common/terms/"; Allows the user to save the text and print the terms terms_of_service = "0" ; Version (hash) of the Terms of Service that the user has accepted terms_of_use = "0" ; Version (hash) of the Terms of Use that the user has accepted privacy_policy = "0" ; Version (hash) of the Privacy Policy that the user has accepted xpartamupp = "wfgbot24" ; Name of the server-side XMPP-account that manage games echelon = "echelon24" ; Name of the server-side XMPP-account that manages ratings buddies = "," ; Comma separated list of playernames that the current user has marked as buddies rememberpassword = true ; Whether to store the encrypted password in the user config [lobby.columns] gamerating = false ; Show the average rating of the participating players in a column of the gamelist [lobby.stun] enabled = true ; The STUN protocol allows hosting games without configuring the firewall and router. ; If STUN is disabled, the game relies on direct connection, UPnP and port forwarding. server = "lobby.wildfiregames.com" ; Address of the STUN server. port = 3478 ; Port of the STUN server. delay = 200 ; Duration in milliseconds that is waited between STUN messages. ; Smaller numbers speed up joins but also become less stable. [mod] enabledmods = "mod public" [modio] public_key = "RWTsHxQMrRq4xwHisyBa2rNQfAedcINzbTT83jeX4/ZcfVxqLfWB4y8w" ; Public key corresponding to the private key valid mods are signed with disclaimer = "0" ; Version (hash) of the Disclaimer that the user has accepted [modio.v1] baseurl = "https://api.mod.io/v1" api_key = "23df258a71711ea6e4b50893acc1ba55" name_id = "0ad" [network] duplicateplayernames = false ; Rename joining player to "User (2)" if "User" is already connected, otherwise prohibit join. lateobservers = everyone ; Allow observers to join the game after it started. Possible values: everyone, buddies, disabled. observerlimit = 8 ; Prevent further observer joins in running games if this limit is reached gamestarttimeout = 60000 ; Don't disconnect clients timing out in the loading screen and rejoin process before exceeding this timeout. [overlay] fps = "false" ; Show frames per second in top right corner realtime = "false" ; Show current system time in top right corner netwarnings = "true" ; Show warnings if the network connection is bad [profiler2] autoenable = false ; Enable HTTP server output at startup (default off for security/performance) gpu.arb.enable = true ; Allow GL_ARB_timer_query timing mode when available gpu.ext.enable = true ; Allow GL_EXT_timer_query timing mode when available gpu.intel.enable = true ; Allow GL_INTEL_performance_queries timing mode when available [sound] mastergain = 0.9 musicgain = 0.2 ambientgain = 0.6 actiongain = 0.7 uigain = 0.7 [sound.notify] nick = true ; Play a sound when someone mentions your name in the lobby or game gamesetup.join = false ; Play a sound when a new client joins the game setup [tinygettext] debug = false ; Print error messages each time a translation for an English string is not found. [userreport] ; Opt-in online user reporting system url_upload = "https://feedback.wildfiregames.com/report/upload/v1/" ; URL where UserReports are uploaded to url_publication = "https://feedback.wildfiregames.com/" ; URL where UserReports were analyzed and published url_terms = "https://trac.wildfiregames.com/browser/ps/trunk/binaries/data/mods/public/gui/userreport/Terms_and_Conditions.txt"; Allows the user to save the text and print the terms terms = "0" ; Version (hash) of the UserReporter Terms that the user has accepted [view] ; Camera control settings scroll.speed = 120.0 scroll.speed.modifier = 1.05 ; Multiplier for changing scroll speed rotate.x.speed = 1.2 rotate.x.min = 28.0 rotate.x.max = 60.0 rotate.x.default = 35.0 rotate.y.speed = 2.0 rotate.y.speed.wheel = 0.45 rotate.y.default = 0.0 rotate.speed.modifier = 1.05 ; Multiplier for changing rotation speed drag.speed = 0.5 zoom.speed = 256.0 zoom.speed.wheel = 32.0 zoom.min = 50.0 zoom.max = 200.0 zoom.default = 120.0 zoom.speed.modifier = 1.05 ; Multiplier for changing zoom speed pos.smoothness = 0.1 zoom.smoothness = 0.4 rotate.x.smoothness = 0.5 rotate.y.smoothness = 0.3 near = 2.0 ; Near plane distance far = 4096.0 ; Far plane distance fov = 45.0 ; Field of view (degrees), lower is narrow, higher is wide height.smoothness = 0.5 height.min = 16 Index: ps/trunk/binaries/data/mods/public/gui/options/options.json =================================================================== --- ps/trunk/binaries/data/mods/public/gui/options/options.json (revision 23475) +++ ps/trunk/binaries/data/mods/public/gui/options/options.json (revision 23476) @@ -1,568 +1,586 @@ [ { "label": "General", "options": [ { "type": "string", "label": "Player name (single-player)", "tooltip": "How you want to be addressed in single-player matches.", "config": "playername.singleplayer" }, { "type": "string", "label": "Player name (multiplayer)", "tooltip": "How you want to be addressed in multiplayer matches (except lobby).", "config": "playername.multiplayer" }, { "type": "boolean", "label": "Background pause", "tooltip": "Pause single-player games when window loses focus.", "config": "pauseonfocusloss" }, { "type": "boolean", "label": "Enable welcome screen", "tooltip": "If you disable it, the welcome screen will still appear once, each time a new version is available. You can always launch it from the main menu.", "config": "gui.splashscreen.enable" }, { "type": "boolean", "label": "Network warnings", "tooltip": "Show which player has a bad connection in multiplayer games.", "config": "overlay.netwarnings" }, { "type": "boolean", "label": "FPS overlay", "tooltip": "Show frames per second in top right corner.", "config": "overlay.fps" }, { "type": "boolean", "label": "Real time overlay", "tooltip": "Show current system time in top right corner.", "config": "overlay.realtime" }, { "type": "boolean", "label": "Game time overlay", "tooltip": "Show current simulation time in top right corner.", "config": "gui.session.timeelapsedcounter" }, { "type": "boolean", "label": "Ceasefire time overlay", "tooltip": "Always show the remaining ceasefire time.", "config": "gui.session.ceasefirecounter" }, { "type": "dropdown", "label": "Late observer joins", "tooltip": "Allow everybody or buddies only to join the game as observer after it started.", "config": "network.lateobservers", "list": [ { "value": "everyone", "label": "Everyone" }, { "value": "buddies", "label": "Buddies" }, { "value": "disabled", "label": "Disabled" } ] }, { "type": "number", "label": "Observer limit", "tooltip": "Prevent further observers from joining if the limit is reached.", "config": "network.observerlimit", "min": 0, "max": 32 }, { "type": "boolean", "label": "Chat timestamp", "tooltip": "Show time that messages are posted in the lobby, gamesetup and ingame chat.", "config": "chat.timestamp" } ] }, { "label": "Graphics", "tooltip": "Set the balance between performance and visual appearance.", "options": [ { "type": "boolean", "label": "Windowed mode", "tooltip": "Start 0 A.D. in a window.", "config": "windowed" }, { "type": "boolean", "label": "Prefer GLSL", "tooltip": "Use OpenGL 2.0 shaders (recommended).", "config": "preferglsl", "function": "Renderer_SetPreferGLSLEnabled" }, { "type": "boolean", "label": "Fog", "tooltip": "Enable Fog.", "dependencies": ["preferglsl"], "config": "fog", "function": "Renderer_SetFogEnabled" }, { "type": "boolean", "label": "Post-processing", "tooltip": "Use screen-space post-processing filters (HDR, Bloom, DOF, etc).", "config": "postproc", "function": "Renderer_SetPostProcEnabled" }, { "type": "slider", "label": "Shader effects", "tooltip": "Number of shader effects. REQUIRES GAME RESTART", "config": "materialmgr.quality", "min": 0, "max": 10 }, { "type": "boolean", "label": "Shadows", "tooltip": "Enable shadows.", "config": "shadows", "function": "Renderer_SetShadowsEnabled" }, { "type": "dropdown", "label": "Shadow quality", "tooltip": "Shadow map resolution. High values can crash the game when using a graphics card with low memory!", "dependencies": ["shadows"], "config": "shadowquality", "function": "Renderer_RecreateShadowMap", "list": [ { "value": -2, "label": "Very Low" }, { "value": -1, "label": "Low" }, { "value": 0, "label": "Medium" }, { "value": 1, "label": "High" }, { "value": 2, "label": "Very High" } ] }, { "type": "boolean", "label": "Shadow filtering", "tooltip": "Smooth shadows.", "dependencies": ["shadows"], "config": "shadowpcf", "function": "Renderer_SetShadowPCFEnabled" }, { "type": "boolean", "label": "Unit silhouettes", "tooltip": "Show outlines of units behind structures.", "config": "silhouettes", "function": "Renderer_SetSilhouettesEnabled" }, { "type": "boolean", "label": "Particles", "tooltip": "Enable particles.", "config": "particles", "function": "Renderer_SetParticlesEnabled" }, { "type": "boolean", "label": "Water effects", "tooltip": "When OFF, use the lowest settings possible to render water. This makes other settings irrelevant.", "config": "watereffects", "function": "Renderer_SetWaterEffectsEnabled" }, { "type": "boolean", "label": "High-quality water effects", "tooltip": "Use higher-quality effects for water, rendering coastal waves, shore foam, and ships trails.", "dependencies": ["watereffects"], "config": "waterfancyeffects", "function": "Renderer_SetWaterFancyEffectsEnabled" }, { "type": "boolean", "label": "Real water depth", "tooltip": "Use actual water depth in rendering calculations.", "dependencies": ["watereffects"], "config": "waterrealdepth", "function": "Renderer_SetWaterRealDepthEnabled" }, { "type": "boolean", "label": "Water reflections", "tooltip": "Allow water to reflect a mirror image.", "dependencies": ["watereffects"], "config": "waterreflection", "function": "Renderer_SetWaterReflectionEnabled" }, { "type": "boolean", "label": "Water refraction", "tooltip": "Use a real water refraction map and not transparency.", "dependencies": ["watereffects"], "config": "waterrefraction", "function": "Renderer_SetWaterRefractionEnabled" }, { "type": "boolean", "label": "Shadows on water", "tooltip": "Cast shadows on water.", "dependencies": ["watereffects"], "config": "shadowsonwater", "function": "Renderer_SetWaterShadowsEnabled" }, { "type": "boolean", "label": "Smooth vision", "tooltip": "Lift darkness and fog-of-war smoothly.", "config": "smoothlos", "function": "Renderer_SetSmoothLOSEnabled" }, { "type": "boolean", "label": "Show sky", "tooltip": "Render Sky.", "config": "showsky", "function": "Renderer_SetShowSkyEnabled" }, { "type": "boolean", "label": "VSync", "tooltip": "Run vertical sync to fix screen tearing. REQUIRES GAME RESTART", "config": "vsync" }, { "type": "slider", "label": "FPS throttling in menus", "tooltip": "To save CPU workload, throttle render frequency in all menus. Set to maximum to disable throttling.", "config": "adaptivefps.menu", "min": 20, "max": 100 }, { "type": "slider", "label": "FPS throttling in games", "tooltip": "To save CPU workload, throttle render frequency in running games. Set to maximum to disable throttling.", "config": "adaptivefps.session", "min": 20, "max": 100 } ] }, { "label": "Sound", "options": [ { "type": "slider", "label": "Master volume", "tooltip": "Master audio gain.", "config": "sound.mastergain", "function": "SetMasterGain", "min": 0, "max": 2 }, { "type": "slider", "label": "Music volume", "tooltip": "In game music gain.", "config": "sound.musicgain", "function": "SetMusicGain", "min": 0, "max": 2 }, { "type": "slider", "label": "Ambient volume", "tooltip": "In game ambient sound gain.", "config": "sound.ambientgain", "function": "SetAmbientGain", "min": 0, "max": 2 }, { "type": "slider", "label": "Action volume", "tooltip": "In game unit action sound gain.", "config": "sound.actiongain", "function": "SetActionGain", "min": 0, "max": 2 }, { "type": "slider", "label": "UI volume", "tooltip": "UI sound gain.", "config": "sound.uigain", "function": "SetUIGain", "min": 0, "max": 2 }, { "type": "boolean", "label": "Nick notification", "tooltip": "Receive audio notification when someone types your nick.", "config": "sound.notify.nick" }, { "type": "boolean", "label": "Game setup - new player notification", "tooltip": "Receive audio notification when a new client joins the game setup.", "config": "sound.notify.gamesetup.join" } ] }, { "label": "Game Setup", "options": [ { "type": "boolean", "label": "Enable game setting tips", "tooltip": "Show tips when setting up a game.", "config": "gui.gamesetup.enabletips" }, { "type": "boolean", "label": "Enable settings panel slide", "tooltip": "Slide the settings panel when opening, closing or resizing.", "config": "gui.gamesetup.settingsslide" }, { "type": "boolean", "label": "Persist match settings", "tooltip": "Save and restore match settings for quick reuse when hosting another game.", "config": "persistmatchsettings" }, { "type": "dropdown", "label": "Default AI difficulty", "tooltip": "Default difficulty of the AI.", "config": "gui.gamesetup.aidifficulty", "list": [ { "value": 0, "label": "Sandbox" }, { "value": 1, "label": "Very Easy" }, { "value": 2, "label": "Easy" }, { "value": 3, "label": "Medium" }, { "value": 4, "label": "Hard" }, { "value": 5, "label": "Very Hard" } ] }, { "type": "dropdown", "label": "Default AI behavior", "tooltip": "Default behavior of the AI.", "config": "gui.gamesetup.aibehavior", "list": [ { "value": "random", "label": "Random" }, { "value": "balanced", "label": "Balanced" }, { "value": "aggressive", "label": "Aggressive" }, { "value": "defensive", "label": "Defensive" } ] }, { "type": "dropdown", "label": "Assign players", "tooltip": "Automatically assign joining clients to free player slots during the match setup.", "config": "gui.gamesetup.assignplayers", "list": [ { "value": "everyone", "label": "Everyone", "tooltip": "Players joining the match will be assigned if there is a free slot." }, { "value": "buddies", "label": "Buddies", "tooltip": "Players joining the match will only be assigned if they are a buddy of the host and if there is a free slot." }, { "value": "disabled", "label": "Disabled", "tooltip": "Players only receive a slot when the host assigns them explicitly." } ] } ] }, { "label": "Lobby", "tooltip": "These settings only affect the multiplayer.", "options": [ { "type": "boolean", "label": "TLS encryption", "tooltip": "Protect login and data exchanged with the lobby server using TLS encryption.", "config": "lobby.tls" }, { "type": "number", "label": "Chat backlog", "tooltip": "Number of backlogged messages to load when joining the lobby.", "config": "lobby.history", "min": "0" }, { "type": "boolean", "label": "Game rating column", "tooltip": "Show the average rating of the participating players in a column of the gamelist.", "config": "lobby.columns.gamerating" } ] }, { "label": "In-Game", "tooltip": "Change options regarding the in-game settings.", "options": [ { "type": "slider", "label": "Wounded unit health", "tooltip": "The wounded unit hotkey considers the selected units as wounded if their health percentage falls below this number.", "config": "gui.session.woundedunithotkeythreshold", "min": 0, "max": 100 }, { "type": "number", "label": "Batch training size", "tooltip": "Number of units trained per batch by default.", "config": "gui.session.batchtrainingsize", "min": 1, "max": 20 }, { "type": "slider", "label": "Scroll batch increment ratio", "tooltip": "Number of times you have to scroll to increase/decrease the batchsize by 1.", "config": "gui.session.scrollbatchratio", "min": 0.1, "max": 30 }, { "type": "boolean", "label": "Chat notification attack", "tooltip": "Show a chat notification if you are attacked by another player.", "config": "gui.session.notifications.attack" }, { "type": "boolean", "label": "Chat notification tribute", "tooltip": "Show a chat notification if an ally tributes resources to another team member if teams are locked, and all tributes in observer mode.", "config": "gui.session.notifications.tribute" }, { "type": "boolean", "label": "Chat notification barter", "tooltip": "Show a chat notification to observers when a player bartered resources.", "config": "gui.session.notifications.barter" }, { "type": "dropdown", "label": "Chat notification phase", "tooltip": "Show a chat notification if you or an ally have started, aborted or completed a new phase, and phases of all players in observer mode.", "config": "gui.session.notifications.phase", "list": [ { "value": "none", "label": "Disable" }, { "value": "completed", "label": "Completed" }, { "value": "all", "label": "All displayed" } ] }, { "type": "boolean", "label": "Attack range visualization", "tooltip": "Display the attack range of selected defensive structures (can also be toggled in-game with the hotkey).", "config": "gui.session.attackrange" }, { "type": "boolean", "label": "Aura range visualization", "tooltip": "Display the range of auras of selected units and structures (can also be toggled in-game with the hotkey).", "config": "gui.session.aurasrange" }, { "type": "boolean", "label": "Heal range visualization", "tooltip": "Display the healing range of selected units (can also be toggled in-game with the hotkey).", "config": "gui.session.healrange" }, { "type": "boolean", "label": "Rank icon above status bar", "tooltip": "Show rank icons above status bars.", "config": "gui.session.rankabovestatusbar" }, { "type": "boolean", "label": "Experience status bar", "tooltip": "Show an experience status bar above each selected unit.", "config": "gui.session.experiencestatusbar" }, { "type": "boolean", "label": "Detailed tooltips", "tooltip": "Show detailed tooltips for trainable units in unit-producing structures.", "config": "showdetailedtooltips" }, { "type": "dropdown", "label": "Sort resources and population tooltip", "tooltip": "Dynamically sort players in the resources and population tooltip by value.", "config": "gui.session.respoptooltipsort", "list": [ { "value": 0, "label": "Unordered" }, { "value": -1, "label": "Ascending" }, { "value": 1, "label": "Descending" } ] }, { "type": "color", "label": "Diplomacy colors: self", "tooltip": "Color of your units when diplomacy colors are enabled.", "config": "gui.session.diplomacycolors.self" }, { "type": "color", "label": "Diplomacy colors: ally", "tooltip": "Color of allies when diplomacy colors are enabled.", "config": "gui.session.diplomacycolors.ally" }, { "type": "color", "label": "Diplomacy colors: neutral", "tooltip": "Color of neutral players when diplomacy colors are enabled.", "config": "gui.session.diplomacycolors.neutral" }, { "type": "color", "label": "Diplomacy colors: enemy", "tooltip": "Color of enemies when diplomacy colors are enabled.", "config": "gui.session.diplomacycolors.enemy" }, { "type": "dropdown", "label": "Snap to edges", "tooltip": "This option allows to align new structures with nearby structures.", "config": "gui.session.snaptoedges", "list": [ { "value": "disabled", "label": "Hotkey to enable snapping", "tooltip": "New structures are aligned with nearby structures while pressing the hotkey." }, { "value": "enabled", "label": "Hotkey to disable snapping", "tooltip": "New structures are aligned with nearby structures unless the hotkey is pressed." } ] + }, + { + "type": "dropdown", + "label": "Control Group Membership", + "tooltip": "Decide whether units can be part of multiple control groups.", + "config": "gui.session.disjointcontrolgroups", + "list": [ + { + "value": "true", + "label": "Single", + "tooltip": "When adding a Unit or Structure to a control group, they are removed from other control groups. Use this choice if you want control groups to refer to distinct armies." + }, + { + "value": "false", + "label": "Multiple", + "tooltip": "Units and Structures can be part of multiple control groups. This is useful to keep control groups for distinct armies and a control group for the entire army simultaneously." + } + ] } ] } ] Index: ps/trunk/binaries/data/mods/public/gui/session/selection.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/selection.js (revision 23475) +++ ps/trunk/binaries/data/mods/public/gui/session/selection.js (revision 23476) @@ -1,524 +1,530 @@ // Limits selection size var g_MaxSelectionSize = 200; // Alpha value of hovered/mouseover/highlighted selection overlays // (should probably be greater than always visible alpha value, // see CCmpSelectable) var g_HighlightedAlpha = 0.75; function _setHighlight(ents, alpha, selected) { if (ents.length) Engine.GuiInterfaceCall("SetSelectionHighlight", { "entities": ents, "alpha": alpha, "selected": selected }); } function _setStatusBars(ents, enabled) { if (!ents.length) return; Engine.GuiInterfaceCall("SetStatusBars", { "entities": ents, "enabled": enabled, "showRank": Engine.ConfigDB_GetValue("user", "gui.session.rankabovestatusbar") == "true", "showExperience": Engine.ConfigDB_GetValue("user", "gui.session.experiencestatusbar") == "true" }); } function _setMotionOverlay(ents, enabled) { if (ents.length) Engine.GuiInterfaceCall("SetMotionDebugOverlay", { "entities": ents, "enabled": enabled }); } function _playSound(ent) { Engine.GuiInterfaceCall("PlaySound", { "name": "select", "entity": ent }); } /** * EntityGroups class for managing grouped entities */ function EntityGroups() { this.groups = {}; this.ents = {}; } EntityGroups.prototype.reset = function() { this.groups = {}; this.ents = {}; }; EntityGroups.prototype.add = function(ents) { for (let ent of ents) { if (this.ents[ent]) continue; var entState = GetEntityState(ent); // When this function is called during group rebuild, deleted // entities will not yet have been removed, so entities might // still be present in the group despite not existing. if (!entState) continue; var templateName = entState.template; var key = GetTemplateData(templateName).selectionGroupName || templateName; // Group the ents by player and template if (entState.player !== undefined) key = "p" + entState.player + "&" + key; if (this.groups[key]) this.groups[key] += 1; else this.groups[key] = 1; this.ents[ent] = key; } }; EntityGroups.prototype.removeEnt = function(ent) { var key = this.ents[ent]; // Remove the entity delete this.ents[ent]; --this.groups[key]; // Remove the entire group if (this.groups[key] == 0) delete this.groups[key]; }; EntityGroups.prototype.rebuildGroup = function(renamed) { var oldGroup = this.ents; this.reset(); var toAdd = []; for (var ent in oldGroup) toAdd.push(renamed[ent] ? renamed[ent] : +ent); this.add(toAdd); }; EntityGroups.prototype.getCount = function(key) { return this.groups[key]; }; EntityGroups.prototype.getTotalCount = function() { let totalCount = 0; for (let key in this.groups) totalCount += this.groups[key]; return totalCount; }; EntityGroups.prototype.getKeys = function() { // Preserve order even when shuffling units around // Can be optimized by moving the sorting elsewhere return Object.keys(this.groups).sort(); }; EntityGroups.prototype.getEntsByKey = function(key) { var ents = []; for (var ent in this.ents) if (this.ents[ent] == key) ents.push(+ent); return ents; }; /** * get a list of entities grouped by a key */ EntityGroups.prototype.getEntsGrouped = function() { return this.getKeys().map(key => ({ "ents": this.getEntsByKey(key), "key": key })); }; /** * Gets all ents in every group except ones of the specified group */ EntityGroups.prototype.getEntsByKeyInverse = function(key) { var ents = []; for (var ent in this.ents) if (this.ents[ent] != key) ents.push(+ent); return ents; }; /** * EntitySelection class for managing the entity selection list and the primary selection */ function EntitySelection() { // Private properties: this.selected = {}; // { id:id, id:id, ... } for each selected entity ID 'id' // { id:id, ... } for mouseover-highlighted entity IDs in these, the key is a string and the value is an int; // we want to use the int form wherever possible since it's more efficient to send to the simulation code) this.highlighted = {}; this.motionDebugOverlay = false; // Public properties: this.dirty = false; // set whenever the selection has changed this.groups = new EntityGroups(); } /** * Deselect everything but entities of the chosen type if inverse is true otherwise deselect just the chosen entity */ EntitySelection.prototype.makePrimarySelection = function(key, inverse) { let ents = inverse ? this.groups.getEntsByKeyInverse(key) : this.groups.getEntsByKey(key); this.reset(); this.addList(ents); }; /** * Get a list of the template names */ EntitySelection.prototype.getTemplateNames = function() { var templateNames = []; for (let ent in this.selected) { let entState = GetEntityState(+ent); if (entState) templateNames.push(entState.template); } return templateNames; }; /** * Update the selection to take care of changes (like units that have been killed) */ EntitySelection.prototype.update = function() { this.checkRenamedEntities(); let controlsAll = g_SimState.players[g_ViewedPlayer] && g_SimState.players[g_ViewedPlayer].controlsAll; let removeOwnerChanges = !g_IsObserver && !controlsAll && this.toList().length > 1; let changed = false; for (let ent in this.selected) { let entState = GetEntityState(+ent); // Remove deleted units if (!entState) { delete this.selected[ent]; this.groups.removeEnt(+ent); changed = true; continue; } // Remove non-visible units (e.g. moved back into fog-of-war) // At the next update, mirages will be renamed to the real // entity they replace, so just ignore them now // Futhermore, when multiple selection, remove units which have changed ownership if (entState.visibility == "hidden" && !entState.mirage || removeOwnerChanges && entState.player != g_ViewedPlayer) { // Disable any highlighting of the disappeared unit _setHighlight([+ent], 0, false); _setStatusBars([+ent], false); _setMotionOverlay([+ent], false); delete this.selected[ent]; this.groups.removeEnt(+ent); changed = true; continue; } } if (changed) this.onChange(); }; /** * Update selection if some selected entities were renamed * (in case of unit promotion or finishing building structure) */ EntitySelection.prototype.checkRenamedEntities = function() { var renamedEntities = Engine.GuiInterfaceCall("GetRenamedEntities"); if (renamedEntities.length > 0) { var renamedLookup = {}; for (let renamedEntity of renamedEntities) renamedLookup[renamedEntity.entity] = renamedEntity.newentity; // Reconstruct the selection if at least one entity has been renamed. for (let renamedEntity of renamedEntities) if (this.selected[renamedEntity.entity]) { this.rebuildSelection(renamedLookup); return; } } }; /** * Add entities to selection. Play selection sound unless quiet is true */ EntitySelection.prototype.addList = function(ents, quiet, force = false) { let selection = this.toList(); // If someone else's player is the sole selected unit, don't allow adding to the selection let firstEntState = selection.length == 1 && GetEntityState(selection[0]); if (firstEntState && firstEntState.player != g_ViewedPlayer && !force) return; let i = 1; let added = []; for (let ent of ents) { if (selection.length + i > g_MaxSelectionSize) break; if (this.selected[ent]) continue; var entState = GetEntityState(ent); if (!entState) continue; let isUnowned = g_ViewedPlayer != -1 && entState.player != g_ViewedPlayer || g_ViewedPlayer == -1 && entState.player == 0; // Don't add unowned entities to the list, unless a single entity was selected if (isUnowned && (ents.length > 1 || selection.length) && !force) continue; added.push(ent); this.selected[ent] = ent; ++i; } _setHighlight(added, 1, true); _setStatusBars(added, true); _setMotionOverlay(added, this.motionDebugOverlay); if (added.length) { // Play the sound if the entity is controllable by us or Gaia-owned. var owner = GetEntityState(added[0]).player; if (!quiet && (controlsPlayer(owner) || g_IsObserver || owner == 0)) _playSound(added[0]); } this.groups.add(this.toList()); // Create Selection Groups this.onChange(); }; EntitySelection.prototype.removeList = function(ents) { var removed = []; for (let ent of ents) if (this.selected[ent]) { this.groups.removeEnt(ent); removed.push(ent); delete this.selected[ent]; } _setHighlight(removed, 0, false); _setStatusBars(removed, false); _setMotionOverlay(removed, false); this.onChange(); }; EntitySelection.prototype.reset = function() { _setHighlight(this.toList(), 0, false); _setStatusBars(this.toList(), false); _setMotionOverlay(this.toList(), false); this.selected = {}; this.groups.reset(); this.onChange(); }; EntitySelection.prototype.rebuildSelection = function(renamed) { var oldSelection = this.selected; this.reset(); var toAdd = []; for (let ent in oldSelection) toAdd.push(renamed[ent] || +ent); this.addList(toAdd, true); // don't play selection sounds }; EntitySelection.prototype.getFirstSelected = function() { for (let ent in this.selected) return +ent; return undefined; }; /** * TODO: This array should not be recreated every call */ EntitySelection.prototype.toList = function() { let ents = []; for (let ent in this.selected) ents.push(+ent); return ents; }; EntitySelection.prototype.setHighlightList = function(ents) { var highlighted = {}; for (let ent of ents) highlighted[ent] = ent; var removed = []; var added = []; // Remove highlighting for the old units that are no longer highlighted // (excluding ones that are actively selected too) for (let ent in this.highlighted) if (!highlighted[ent] && !this.selected[ent]) removed.push(+ent); // Add new highlighting for units that aren't already highlighted for (let ent of ents) if (!this.highlighted[ent] && !this.selected[ent]) added.push(+ent); _setHighlight(removed, 0, false); _setStatusBars(removed, false); _setHighlight(added, g_HighlightedAlpha, true); _setStatusBars(added, true); // Store the new highlight list this.highlighted = highlighted; }; EntitySelection.prototype.SetMotionDebugOverlay = function(enabled) { this.motionDebugOverlay = enabled; _setMotionOverlay(this.toList(), enabled); }; EntitySelection.prototype.onChange = function() { this.dirty = true; if (this.isSelection) onSelectionChange(); }; EntitySelection.prototype.selectAndMoveTo = function(entityID) { let entState = GetEntityState(entityID); if (!entState || !entState.position) return; this.reset(); this.addList([entityID]); Engine.CameraMoveTo(entState.position.x, entState.position.z); } /** * Cache some quantities which depends only on selection */ var g_Selection = new EntitySelection(); g_Selection.isSelection = true; var g_canMoveIntoFormation = {}; var g_allBuildableEntities; var g_allTrainableEntities; // Reset cached quantities function onSelectionChange() { g_canMoveIntoFormation = {}; g_allBuildableEntities = undefined; g_allTrainableEntities = undefined; } /** * EntityGroupsContainer class for managing grouped entities */ function EntityGroupsContainer() { this.groups = []; for (var i = 0; i < 10; ++i) this.groups[i] = new EntityGroups(); } +/** + * Add entities to a group. + * @param {string} groupName - The number of the group to add the entities to. + * @param {number[]} ents - The entities to add to the group. + */ EntityGroupsContainer.prototype.addEntities = function(groupName, ents) { - for (let ent of ents) - for (let group of this.groups) - if (ent in group.ents) - group.removeEnt(ent); + if (Engine.ConfigDB_GetValue("user", "gui.session.disjointcontrolgroups") == "true") + for (let ent of ents) + for (let group of this.groups) + if (ent in group.ents) + group.removeEnt(ent); this.groups[groupName].add(ents); }; EntityGroupsContainer.prototype.update = function() { this.checkRenamedEntities(); for (let group of this.groups) for (var ent in group.ents) { var entState = GetEntityState(+ent); // Remove deleted units if (!entState) group.removeEnt(ent); } }; /** * Update control group if some entities in the group were renamed * (in case of unit promotion or finishing building structure) */ EntityGroupsContainer.prototype.checkRenamedEntities = function() { var renamedEntities = Engine.GuiInterfaceCall("GetRenamedEntities"); if (renamedEntities.length > 0) { var renamedLookup = {}; for (let renamedEntity of renamedEntities) renamedLookup[renamedEntity.entity] = renamedEntity.newentity; for (let group of this.groups) for (let renamedEntity of renamedEntities) // Reconstruct the group if at least one entity has been renamed. if (renamedEntity.entity in group.ents) { group.rebuildGroup(renamedLookup); break; } } }; var g_Groups = new EntityGroupsContainer();