Index: ps/trunk/binaries/data/config/default.cfg
===================================================================
--- ps/trunk/binaries/data/config/default.cfg (revision 18577)
+++ ps/trunk/binaries/data/config/default.cfg (revision 18578)
@@ -1,419 +1,422 @@
; 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
; Enable/disable the splashscreen
splashscreendisable = false
; Splashscreen version (date of last modification). By default, 0 to force splashscreen to appear at first launch.
splashscreenversion = 0
; 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
waterugly=false; 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
shadowpcf = true
vsync = false
particles = 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 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"
[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 = "Alt+F4", "Ctrl+Break", "Super+Q" ; Exit to desktop
cancel = Escape ; Close or cancel the current dialog box/popup
leave = Escape ; End current game or Exit
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+W" ; Toggle wireframe mode
silhouettes = "Alt+S" ; Toggle unit silhouettes
showsky = "Alt+Z" ; Toggle sky
; > 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
session.gui.toggle = "Alt+G" ; Toggle visibility of session GUI
menu.toggle = "F10" ; Toggle in-game menu
timeelapsedcounter.toggle = "F12" ; Toggle time elapsed 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
; > HOTKEYS ONLY
chat = Return ; Toggle chat window
teamchat = "T" ; Toggle chat window in team chat mode
; > 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
milonly = Alt ; Add only military units to selection
idleonly = "I" ; Select only idle 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
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
+unload = "U" ; Unload garrisoned units when a building/mechanical unit is selected
attack = Ctrl ; Modifier to attack instead of another action (eg 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
+repair = "J" ; Modifier to repair when clicking on building/mechanical unit
queue = Shift ; Modifier to queue unit orders instead of replacing
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
[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.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.menu]
limitfps = true ; Limit FPS in the menus and loading screen
[gui.session]
attacknotificationmessage = true ; Show attack notification messages
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
batchtrainingsize = 5 ; Number of units to be trained per batch (when pressing the hotkey)
[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
[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
[lobby]
chattimestamp = false ; Show time chat message was posted
history = 0 ; Number of past messages to display on join
room = "arena21" ; Default MUC room to join
server = "lobby.wildfiregames.com" ; Address of lobby server
xpartamupp = "wfgbot21" ; Name of the server-side xmpp client that manage games
[mod]
enabledmods = "mod public"
[network]
duplicateplayernames = false ; Rename joining player to "User (2)" if "User" is already connected, otherwise prohibit join.
lateobserverjoins = false ; Allow observers to join the game after it started
observerlimit = 6 ; Prevent further observer joins in running games if this limit is reached
[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)
script.enable = false ; Enable Javascript profiling. Needs to be set before startup and can't be changed later. (default off for 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
[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 = "http://feedback.wildfiregames.com/report/upload/v1/"
[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/manual/intro.txt
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/manual/intro.txt (revision 18577)
+++ ps/trunk/binaries/data/mods/public/gui/manual/intro.txt (revision 18578)
@@ -1,132 +1,134 @@
[font="sans-bold-18"]0 A.D. in-game manual
[font="sans-14"]
Thank you for installing 0 A.D.! This page will give a brief overview of the features available in this incomplete, under-development, alpha version of the game.
[font="sans-bold-16"]Graphics settings
[font="sans-14"]You can switch between fullscreen and windowed mode by pressing Alt + Enter. In windowed mode, you can resize the window. If the game runs too slowly, you can change some settings in the configuration file: look for binaries/data/config/default.cfg in the location where the game is installed, which gives instructions for editing, and try disabling the "fancywater" and "shadows" options.
[font="sans-bold-16"]Playing the game
[font="sans-14"]The controls and gameplay should be familiar to players of traditional RTS games. There are currently a lot of missing features and poorly-balanced stats – you will probably have to wait until a beta release for it to work well.
Basic controls:
• Left-click to select units.
• Left-click-and-drag to select groups of units.
• Right-click to order units to the target.
• Arrow keys or WASD keys to move the camera.
• Ctrl + arrow keys, or shift + mouse wheel, to rotate the camera.
• Mouse wheel, or "+" and "-" keys, to zoom.
[font="sans-bold-16"]Modes
[font="sans-14"]The main menu gives access to two game modes:
• [font="sans-bold-14"]Single-player[font="sans-14"] — play a sandbox game or against one or more AI opponents. The AI/AIs are under development and may not always be up to date on the new features, but you can test playing the game against an actual opponent if you aren't able to play with a human.
• [font="sans-bold-14"]Multiplayer[font="sans-14"] — play against human opponents over the internet.
To set up a multiplayer game, one player must select the "Host game" option. The game uses UDP port 20595, so the host must configure their NAT/firewall/etc to allow this. Other players can then select "Join game" and enter the host's IP address.
[font="sans-bold-16"]Game setup
[font="sans-14"]In a multiplayer game, only the host can alter the game setup options.
First, select what type of map you want to play:
• [font="sans-bold-14"]Random map[font="sans-14"] — A map created automatically from a script
• [font="sans-bold-14"]Scenario map[font="sans-14"] — A map created by map designers and with fixed civilisations
• [font="sans-bold-14"]Skirmish map[font="sans-14"] — A map created by map designers but where the civilisations can be chosen
Then the maps can be futher filtered. The default maps are generally playable maps. Naval maps are maps where not all opponents can be reached over land and demo maps are maps used for testing purposes (generally not useful to play on). The "All Maps" filter shows all maps together in one list.
Finally change the settings. For random maps this includes the number of players, the size of a map, etc. For scenarios you can only select who controls which player (decides where you start on the map etc). The options are either a human player, an AI or no player at all (the opponent will just be idle).
When you are ready to start, click the "Start game" button.
[font="sans-bold-16"]Hotkeys:
[font="sans-bold-14"]Global
[font="sans-14"]Alt + F4: Close the game, without confirmation
Alt + Enter: Toggle between fullscreen and windowed
~ or F9: Show/hide console
Alt + F: Show/hide frame counter (FPS)
F11: Enable/disable real-time profiler (toggles through the displays of information)
Shift + F11: Save current profiler data to "logs/profile.txt"
F2: Take screenshot (in .png format, location is displayed in the top left of the GUI after the file has been saved, and can also be seen in the console/logs if you miss it there)
Shift + F2: Take huge screenshot (6400px*4800px, in .bmp format, location is displayed in the top left of the GUI after the file has been saved, and can also be seen in the console/logs if you miss it there)
[font="sans-bold-14"]In Game
[font="sans-14"]Double Left Click \[on unit]: Select all of your units of the same kind on the screen (even if they're different ranks)
Triple Left Click \[on unit]: Select all of your units of the same kind and the same rank on the screen
Alt + Double Left Click \[on unit]: Select all your units of the same kind on the entire map (even if they have different ranks)
Alt + Triple Left Click \[on unit]: Select all your units of the same kind and rank on the entire map
Shift + F5: Quicksave
Shift + F8: Quickload
F10: Open/close menu
F12: Show/hide time elapsed counter
ESC: Close all dialogs (chat, menu) or clear selected units
Enter/return: Open/send chat
T: Send team chat
Pause: Pause/resume the game
Delete: Delete currently selected units/buildings
Shift + Delete: Delete currently selected units/buildings without confirmation
/ (ForwardSlash): Select idle fighter
Shift + /: add idle fighter to selection
. (Period): Select idle worker (including citizen soldiers)
Shift + .: add idle worker to selection (including citizen soldiers)
H: Stop (halt) the currently selected units.
+U: Unload the garrisoned units of the selected buildings
Ctrl + 1 (and so on up to Ctrl + 0): Create control group 1 (to 0) from the selected units/buildings
1 (and so on up to 0): Select the units/buildings in control group 1 (to 0)
Shift + 1 (to 0): Add control group 1 (to 0) to the selected units/buildings
Ctrl + F5 (and so on up to F8): Mark the current camera position, for jumping back to later.
F5, F6, F7, and F8: Move the camera to a marked position. Jump back to the last location if the camera is already over the marked position.
Z, X, C, V, B, N, M: With training buildings selected. Add the 1st, 2nd, ... unit shown to the training queue for all the selected buildings.
PageUp with units selected: highlights the units/buildings guarded by the selection.
PageDown with units/buildings selected: highlights the units guarding the selection.
Tab: See all status bars (which would also show the building progress)
[font="sans-bold-14"]Modify mouse action
[font="sans-14"]Ctrl + Right Click on building: Garrison
+J + Right Click on building: Repair
Shift + Right Click: Queue the move/build/gather/etc order
Shift + Left click when training unit/s: Add units in batches of five
Shift + Left Click or Left Drag over unit on map: Add unit to selection
Ctrl + Left Click or Left Drag over unit on map: Remove unit from selection
Alt + Left Drag over units on map: Only select military units
I + Left Drag over units on map: Only select idle units
Ctrl + Left Click on unit/group icon with multiple units selected: Deselect
Right Click with a building/buildings selected: sets a rally point for units created/ungarrisoned from that building.
Ctrl + Right Click with units selected:
- If the cursor is over an allied structure: Garrison
- If the cursor is over a non-allied unit or building: Attack (instead of capture or gather)
- Otherwise: Attack move (by default all enemy units and structures along the way are targeted, use Ctrl + Q + Right Click to target only units).
[font="sans-bold-14"]Overlays
[font="sans-14"]Alt + G: Hide/show the GUI
Alt + D: Show/hide developer overlay (with developer options)
Alt + W: Toggle wireframe mode (press once to get wireframes overlaid over the textured models, twice to get just the wireframes colored by the textures, thrice to get back to normal textured mode)
Alt + S: Toggle unit silhouettes (might give a small performance boost)
Alt + Z: Toggle sky
[font="sans-bold-14"]Camera manipulation
[font="sans-14"]W or \[up]: Pan screen up
S or \[down]: Pan screen down
A or \[left]: Pan screen left
D or \[right]: Pan screen right
Ctrl + W or \[up]: Rotate camera to look upward
Ctrl + S or \[down]: Rotate camera to look downward
Ctrl + A or \[left]: Rotate camera clockwise around terrain
Ctrl + D or \[right]: Rotate camera anticlockwise around terrain
Q: Rotate camera clockwise around terrain
E: Rotate camera anticlockwise around terrain
Shift + Mouse Wheel Rotate Up: Rotate camera clockwise around terrain
Shift + Mouse Wheel Rotate Down: Rotate camera anticlockwise around terrain
F: Follow the selected unit (move the camera to stop the camera from following the unit/s)
R: Reset camera zoom/orientation
+: Zoom in (keep pressed for continuous zoom)
-: Zoom out (keep pressed for continuous zoom)
Alt + W: Toggle through wireframe modes
Middle Mouse Button: Keep pressed and move the mouse to pan
[font="sans-bold-14"]During Building Placement
[font="sans-14"]\[: Rotate building 15 degrees counter-clockwise
]: Rotate building 15 degrees clockwise
Left Drag: Rotate building using mouse (foundation will be placed on mouse release)
[font="sans-bold-14"]When loading a saved game
[font="sans-14"]Delete: delete the selected saved game asking confirmation
Shift: do not ask confirmation when deleting a saved game
Index: ps/trunk/binaries/data/mods/public/gui/session/hotkeys/camera.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/hotkeys/camera.xml (revision 18577)
+++ ps/trunk/binaries/data/mods/public/gui/session/hotkeys/camera.xml (revision 18578)
@@ -1,88 +1,92 @@
Index: ps/trunk/binaries/data/mods/public/gui/session/hotkeys/misc.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/hotkeys/misc.xml (revision 18577)
+++ ps/trunk/binaries/data/mods/public/gui/session/hotkeys/misc.xml (revision 18578)
@@ -1,62 +1,66 @@
closeOpenDialogs();openChat(false);openChat(true);toggleMenu();
var newSetting = !Engine.Renderer_GetSilhouettesEnabled();
Engine.Renderer_SetSilhouettesEnabled(newSetting);
var newSetting = !Engine.Renderer_GetShowSkyEnabled();
Engine.Renderer_SetShowSkyEnabled(newSetting);
togglePause();Engine.QuickSave();Engine.QuickLoad();performCommand(g_Selection.getFirstSelected(), "delete");
+
+ unloadAll();
+
+
stopUnits(g_Selection.toList());findIdleUnit(["Hero", "Champion", "CitizenSoldier", "Siege", "Warship", "Dog"]);clearSelection();
Index: ps/trunk/binaries/data/mods/public/gui/session/unit_actions.js
===================================================================
--- ps/trunk/binaries/data/mods/public/gui/session/unit_actions.js (revision 18577)
+++ ps/trunk/binaries/data/mods/public/gui/session/unit_actions.js (revision 18578)
@@ -1,1351 +1,1375 @@
/**
* List of different actions units can execute,
* this is mostly used to determine which actions can be executed
*
* "execute" is meant to send the command to the engine
*
* The next functions will always return false
* in case you have to continue to seek
* (i.e. look at the next entity for getActionInfo, the next
* possible action for the actionCheck ...)
* They will return an object when the searching is finished
*
* "getActionInfo" is used to determine if the action is possible,
* and also give visual feedback to the user (tooltips, cursors, ...)
*
* "preSelectedActionCheck" is used to select actions when the gui buttons
* were used to set them, but still require a target (like the guard button)
*
* "hotkeyActionCheck" is used to check the possibility of actions when
* a hotkey is pressed
*
* "actionCheck" is used to check the possibilty of actions without specific
* command. For that, the specificness variable is used
*
* "specificness" is used to determine how specific an action is,
* The lower the number, the more specific an action is, and the bigger
* the chance of selecting that action when multiple actions are possible
*/
var unitActions =
{
"move":
{
"execute": function(target, action, selection, queued)
{
Engine.PostNetworkCommand({
"type": "walk",
"entities": selection,
"x": target.x,
"z": target.z,
"queued": queued
});
Engine.GuiInterfaceCall("PlaySound", {
"name": "order_walk",
"entity": selection[0]
});
return true;
},
"getActionInfo": function(entState, targetState)
{
return { "possible": true };
},
"actionCheck": function(target, selection)
{
if (!someUnitAI(selection) || !getActionInfo("move", target).possible)
return false;
return { "type": "move" };
},
"specificness": 12,
},
"attack-move":
{
"execute": function(target, action, selection, queued)
{
let targetClasses;
if (Engine.HotkeyIsPressed("session.attackmoveUnit"))
targetClasses = { "attack": ["Unit"] };
else
targetClasses = { "attack": ["Unit", "Structure"] };
Engine.PostNetworkCommand({
"type": "attack-walk",
"entities": selection,
"x": target.x,
"z": target.z,
"targetClasses": targetClasses,
"queued": queued
});
Engine.GuiInterfaceCall("PlaySound", {
"name": "order_walk",
"entity": selection[0]
});
return true;
},
"getActionInfo": function(entState, targetState)
{
return { "possible": true };
},
"hotkeyActionCheck": function(target, selection)
{
if (!someUnitAI(selection) ||
!Engine.HotkeyIsPressed("session.attackmove") ||
!getActionInfo("attack-move", target).possible)
return false;
return {
"type": "attack-move",
"cursor": "action-attack-move"
};
},
"specificness": 30,
},
"capture":
{
"execute": function(target, action, selection, queued)
{
Engine.PostNetworkCommand({
"type": "attack",
"entities": selection,
"target": action.target,
"allowCapture": true,
"queued": queued
});
Engine.GuiInterfaceCall("PlaySound", {
"name": "order_attack",
"entity": selection[0]
});
return true;
},
"getActionInfo": function(entState, targetState)
{
if (!entState.attack || !targetState.hitpoints)
return false;
return {
"possible": Engine.GuiInterfaceCall("CanCapture", {
"entity": entState.id,
"target": targetState.id
})
};
},
"actionCheck": function(target)
{
if (!getActionInfo("capture", target).possible)
return false;
return {
"type": "capture",
"cursor": "action-capture",
"target": target
};
},
"specificness": 9,
},
"attack":
{
"execute": function(target, action, selection, queued)
{
Engine.PostNetworkCommand({
"type": "attack",
"entities": selection,
"target": action.target,
"queued": queued,
"allowCapture": false
});
Engine.GuiInterfaceCall("PlaySound", {
"name": "order_attack",
"entity": selection[0]
});
return true;
},
"getActionInfo": function(entState, targetState)
{
if (!entState.attack || !targetState.hitpoints)
return false;
return {
"possible": Engine.GuiInterfaceCall("CanAttack", {
"entity": entState.id,
"target": targetState.id
})
};
},
"hotkeyActionCheck": function(target)
{
if (!Engine.HotkeyIsPressed("session.attack") ||
!getActionInfo("attack", target).possible)
return false;
return {
"type": "attack",
"cursor": "action-attack",
"target": target
};
},
"actionCheck": function(target)
{
if (!getActionInfo("attack", target).possible)
return false;
return {
"type": "attack",
"cursor": "action-attack",
"target": target
};
},
"specificness": 10,
},
"heal":
{
"execute": function(target, action, selection, queued)
{
Engine.PostNetworkCommand({
"type": "heal",
"entities": selection,
"target": action.target,
"queued": queued
});
Engine.GuiInterfaceCall("PlaySound", {
"name": "order_heal",
"entity": selection[0]
});
return true;
},
"getActionInfo": function(entState, targetState)
{
if (!entState.heal ||
!hasClass(targetState, "Unit") || !targetState.needsHeal ||
!playerCheck(entState, targetState, ["Player", "Ally"]) ||
entState.id == targetState.id) // Healers can't heal themselves.
return false;
let unhealableClasses = entState.heal.unhealableClasses;
if (MatchesClassList(targetState.identity.classes, unhealableClasses))
return false;
let healableClasses = entState.heal.healableClasses;
if (!MatchesClassList(targetState.identity.classes, healableClasses))
return false;
return { "possible": true };
},
"actionCheck": function(target)
{
if (!getActionInfo("heal", target).possible)
return false;
return {
"type": "heal",
"cursor": "action-heal",
"target": target
};
},
"specificness": 7,
},
"build":
{
"execute": function(target, action, selection, queued)
{
Engine.PostNetworkCommand({
"type": "repair",
"entities": selection,
"target": action.target,
"autocontinue": true,
"queued": queued
});
Engine.GuiInterfaceCall("PlaySound", {
"name": "order_repair",
"entity": selection[0]
});
return true;
},
"getActionInfo": function(entState, targetState)
{
if (!targetState.foundation || !entState.builder ||
!playerCheck(entState, targetState, ["Player", "Ally"]))
return false;
return { "possible": true };
},
"actionCheck": function(target)
{
if (!getActionInfo("build", target).possible)
return false;
return {
"type": "build",
"cursor": "action-build",
"target": target
};
},
"specificness": 3,
},
"repair":
{
"execute": function(target, action, selection, queued)
{
Engine.PostNetworkCommand({
"type": "repair",
"entities": selection,
"target": action.target,
"autocontinue": true,
"queued": queued
});
Engine.GuiInterfaceCall("PlaySound", {
"name": "order_repair",
"entity": selection[0]
});
return true;
},
"getActionInfo": function(entState, targetState)
{
if (!entState.builder ||
!targetState.needsRepair && !targetState.foundation ||
!playerCheck(entState, targetState, ["Player", "Ally"]))
return false;
return { "possible": true };
},
"preSelectedActionCheck" : function(target)
{
if (preSelectedAction != ACTION_REPAIR)
return false;
if (getActionInfo("repair", target).possible)
return {
"type": "repair",
"cursor": "action-repair",
"target": target
};
return {
"type": "none",
"cursor": "action-repair-disabled",
"target": null
};
},
+ "hotkeyActionCheck": function(target)
+ {
+ if (!Engine.HotkeyIsPressed("session.repair") ||
+ !getActionInfo("repair", target).possible)
+ return false;
+
+ return {
+ "type": "build",
+ "cursor": "action-repair",
+ "target": target
+ };
+ },
"actionCheck": function(target)
{
if (!getActionInfo("repair", target).possible)
return false;
return {
"type": "build",
"cursor": "action-repair",
"target": target
};
},
"specificness": 11,
},
"gather":
{
"execute": function(target, action, selection, queued)
{
Engine.PostNetworkCommand({
"type": "gather",
"entities": selection,
"target": action.target,
"queued": queued
});
Engine.GuiInterfaceCall("PlaySound", {
"name": "order_gather",
"entity": selection[0]
});
return true;
},
"getActionInfo": function(entState, targetState)
{
if (!targetState.resourceSupply)
return false;
let resource = findGatherType(entState, targetState.resourceSupply);
if (!resource)
return false;
return {
"possible": true,
"cursor": "action-gather-" + resource
};
},
"actionCheck": function(target)
{
let actionInfo = getActionInfo("gather", target);
if (!actionInfo.possible)
return false;
return {
"type": "gather",
"cursor": actionInfo.cursor,
"target": target
};
},
"specificness": 1,
},
"returnresource":
{
"execute": function(target, action, selection, queued)
{
Engine.PostNetworkCommand({
"type": "returnresource",
"entities": selection,
"target": action.target,
"queued": queued
});
Engine.GuiInterfaceCall("PlaySound", {
"name": "order_gather",
"entity": selection[0]
});
return true;
},
"getActionInfo": function(entState, targetState)
{
if (!targetState.resourceDropsite)
return false;
let playerState = GetSimState().players[entState.player];
if (playerState.hasSharedDropsites && targetState.resourceDropsite.shared)
{
if (!playerCheck(entState, targetState, ["Player", "MutualAlly"]))
return false;
}
else if (!playerCheck(entState, targetState, ["Player"]))
return false;
if (!entState.resourceCarrying || !entState.resourceCarrying.length)
return false;
let carriedType = entState.resourceCarrying[0].type;
if (targetState.resourceDropsite.types.indexOf(carriedType) == -1)
return false;
return {
"possible": true,
"cursor": "action-return-" + carriedType
};
},
"actionCheck": function(target)
{
let actionInfo = getActionInfo("returnresource", target);
if (!actionInfo.possible)
return false;
return {
"type": "returnresource",
"cursor": actionInfo.cursor,
"target": target
};
},
"specificness": 2,
},
"setup-trade-route":
{
"execute": function(target, action, selection, queued)
{
Engine.PostNetworkCommand({
"type": "setup-trade-route",
"entities": selection,
"target": action.target,
"source": null,
"route": null,
"queued": queued
});
Engine.GuiInterfaceCall("PlaySound", {
"name": "order_trade",
"entity": selection[0]
});
return true;
},
"getActionInfo": function(entState, targetState)
{
if (targetState.foundation || !entState.trader || !targetState.market ||
!playerCheck(entState, targetState, ["Player", "Ally"]) ||
!(targetState.market.land && hasClass(entState, "Organic") ||
targetState.market.naval && hasClass(entState, "Ship")))
return false;
let tradingDetails = Engine.GuiInterfaceCall("GetTradingDetails", {
"trader": entState.id,
"target": targetState.id
});
if (!tradingDetails)
return false;
let tooltip;
switch (tradingDetails.type)
{
case "is first":
tooltip = translate("Origin trade market.") + "\n";
if (tradingDetails.hasBothMarkets)
tooltip += sprintf(translate("Gain: %(gain)s"), {
"gain": getTradingTooltip(tradingDetails.gain)
});
else
tooltip += translate("Right-click on another market to set it as a destination trade market.");
break;
case "is second":
tooltip = translate("Destination trade market.") + "\n" +
sprintf(translate("Gain: %(gain)s"), {
"gain": getTradingTooltip(tradingDetails.gain)
});
break;
case "set first":
tooltip = translate("Right-click to set as origin trade market");
break;
case "set second":
if (tradingDetails.gain.traderGain == 0) // markets too close
return false;
tooltip = translate("Right-click to set as destination trade market.") + "\n" +
sprintf(translate("Gain: %(gain)s"), {
"gain": getTradingTooltip(tradingDetails.gain)
});
break;
}
return {
"possible": true,
"tooltip": tooltip
};
},
"actionCheck": function(target)
{
let actionInfo = getActionInfo("setup-trade-route", target);
if (!actionInfo.possible)
return false;
return {
"type": "setup-trade-route",
"cursor": "action-setup-trade-route",
"tooltip": actionInfo.tooltip,
"target": target
};
},
"specificness": 0,
},
"garrison":
{
"execute": function(target, action, selection, queued)
{
Engine.PostNetworkCommand({
"type": "garrison",
"entities": selection,
"target": action.target,
"queued": queued
});
Engine.GuiInterfaceCall("PlaySound", {
"name": "order_garrison",
"entity": selection[0]
});
return true;
},
"getActionInfo": function(entState, targetState)
{
if (!hasClass(entState, "Unit") ||
!targetState.garrisonHolder ||
!playerCheck(entState, targetState, ["Player", "MutualAlly"]))
return false;
let tooltip = sprintf(translate("Current garrison: %(garrisoned)s/%(capacity)s"), {
"garrisoned": targetState.garrisonHolder.garrisonedEntitiesCount,
"capacity": targetState.garrisonHolder.capacity
});
let extraCount = 0;
if (entState.garrisonHolder)
extraCount += entState.garrisonHolder.garrisonedEntitiesCount;
if (targetState.garrisonHolder.garrisonedEntitiesCount + extraCount >= targetState.garrisonHolder.capacity)
tooltip = "[color=\"orange\"]" + tooltip + "[/color]";
if (!MatchesClassList(entState.identity.classes, targetState.garrisonHolder.allowedClasses))
return false;
return {
"possible": true,
"tooltip": tooltip
};
},
"preSelectedActionCheck": function(target)
{
if (preSelectedAction != ACTION_GARRISON)
return false;
let actionInfo = getActionInfo("garrison", target);
if (!actionInfo.possible)
return {
"type": "none",
"cursor": "action-garrison-disabled",
"target": null
};
return {
"type": "garrison",
"cursor": "action-garrison",
"tooltip": actionInfo.tooltip,
"target": target
};
},
"hotkeyActionCheck": function(target)
{
let actionInfo = getActionInfo("garrison", target);
if (!Engine.HotkeyIsPressed("session.garrison") || !actionInfo.possible)
return false;
return {
"type": "garrison",
"cursor": "action-garrison",
"tooltip": actionInfo.tooltip,
"target": target
};
},
"specificness": 20,
},
"guard":
{
"execute": function(target, action, selection, queued)
{
Engine.PostNetworkCommand({
"type": "guard",
"entities": selection,
"target": action.target,
"queued": queued
});
Engine.GuiInterfaceCall("PlaySound", {
"name": "order_guard",
"entity": selection[0]
});
return true;
},
"getActionInfo": function(entState, targetState)
{
if (!targetState.guard ||
!playerCheck(entState, targetState, ["Player", "Ally"]) ||
!entState.unitAI || !entState.unitAI.canGuard ||
targetState.unitAI && targetState.unitAI.isGuarding)
return false;
return { "possible": true };
},
"preSelectedActionCheck" : function(target)
{
if (preSelectedAction != ACTION_GUARD)
return false;
if (getActionInfo("guard", target).possible)
return {
"type": "guard",
"cursor": "action-guard",
"target": target
};
return {
"type": "none",
"cursor": "action-guard-disabled",
"target": null
};
},
"hotkeyActionCheck": function(target)
{
if (!Engine.HotkeyIsPressed("session.guard") ||
!getActionInfo("guard", target).possible)
return false;
return {
"type": "guard",
"cursor": "action-guard",
"target": target
};
},
"specificness": 40,
},
"remove-guard":
{
"execute": function(target, action, selection, queued)
{
Engine.PostNetworkCommand({
"type": "remove-guard",
"entities": selection,
"target": action.target,
"queued": queued
});
Engine.GuiInterfaceCall("PlaySound", {
"name": "order_guard",
"entity": selection[0]
});
return true;
},
"hotkeyActionCheck": function(target, selection)
{
if (!Engine.HotkeyIsPressed("session.guard") ||
!getActionInfo("remove-guard", target).possible ||
!someGuarding(selection))
return false;
return {
"type": "remove-guard",
"cursor": "action-remove-guard"
};
},
"specificness": 41,
},
"set-rallypoint":
{
"execute": function(target, action, selection, queued)
{
// if there is a position set in the action then use this so that when setting a
// rally point on an entity it is centered on that entity
if (action.position)
target = action.position;
Engine.PostNetworkCommand({
"type": "set-rallypoint",
"entities": selection,
"x": target.x,
"z": target.z,
"data": action.data,
"queued": queued
});
// Display rally point at the new coordinates, to avoid display lag
Engine.GuiInterfaceCall("DisplayRallyPoint", {
"entities": selection,
"x": target.x,
"z": target.z,
"queued": queued
});
return true;
},
"getActionInfo": function(entState, targetState)
{
let tooltip;
// default to walking there (or attack-walking if hotkey pressed)
let data = { "command": "walk" };
let cursor = "";
if (Engine.HotkeyIsPressed("session.attackmove"))
{
let targetClasses;
if (Engine.HotkeyIsPressed("session.attackmoveUnit"))
targetClasses = { "attack": ["Unit"] };
else
targetClasses = { "attack": ["Unit", "Structure"] };
data.command = "attack-walk";
data.targetClasses = targetClasses;
cursor = "action-attack-move";
}
- if (targetState.garrisonHolder &&
+ if (Engine.HotkeyIsPressed("session.repair") &&
+ (targetState.needsRepair || targetState.foundation) &&
+ playerCheck(entState, targetState, ["Player", "Ally"]))
+ {
+ data.command = "repair";
+ data.target = targetState.id;
+ cursor = "action-repair";
+ }
+ else if (targetState.garrisonHolder &&
playerCheck(entState, targetState, ["Player", "MutualAlly"]))
{
data.command = "garrison";
data.target = targetState.id;
cursor = "action-garrison";
tooltip = sprintf(translate("Current garrison: %(garrisoned)s/%(capacity)s"), {
"garrisoned": targetState.garrisonHolder.garrisonedEntitiesCount,
"capacity": targetState.garrisonHolder.capacity
});
if (targetState.garrisonHolder.garrisonedEntitiesCount >=
targetState.garrisonHolder.capacity)
tooltip = "[color=\"orange\"]" + tooltip + "[/color]";
}
else if (targetState.resourceSupply)
{
let resourceType = targetState.resourceSupply.type;
if (resourceType.generic == "treasure")
cursor = "action-gather-" + resourceType.generic;
else
cursor = "action-gather-" + resourceType.specific;
data.command = "gather";
data.resourceType = resourceType;
data.resourceTemplate = targetState.template;
}
else if (entState.market && targetState.market &&
entState.id != targetState.id &&
(!entState.market.naval || targetState.market.naval) &&
!playerCheck(entState, targetState, ["Enemy"]))
{
// Find a trader (if any) that this building can produce.
let trader;
if (entState.production && entState.production.entities.length)
for (let i = 0; i < entState.production.entities.length; ++i)
if ((trader = GetTemplateData(entState.production.entities[i]).trader))
break;
let traderData = {
"firstMarket": entState.id,
"secondMarket": targetState.id,
"template": trader
};
let gain = Engine.GuiInterfaceCall("GetTradingRouteGain", traderData);
if (gain && gain.traderGain)
{
data.command = "trade";
data.target = traderData.secondMarket;
data.source = traderData.firstMarket;
cursor = "action-setup-trade-route";
tooltip = translate("Right-click to establish a default route for new traders.") + "\n" +
sprintf(
trader ?
translate("Gain: %(gain)s") :
translate("Expected gain: %(gain)s"),
{ "gain": getTradingTooltip(gain) });
}
}
else if (targetState.foundation && playerCheck(entState, targetState, ["Ally"]))
{
data.command = "build";
data.target = targetState.id;
cursor = "action-build";
}
else if (targetState.needsRepair && playerCheck(entState, targetState, ["Ally"]))
{
data.command = "repair";
data.target = targetState.id;
cursor = "action-repair";
}
else if (playerCheck(entState, targetState, ["Enemy"]))
{
data.target = targetState.id;
data.command = "attack";
cursor = "action-attack";
}
// Don't allow the rally point to be set on any of the currently selected entities (used for unset)
// except if the autorallypoint hotkey is pressed and the target can produce entities
if (!Engine.HotkeyIsPressed("session.autorallypoint") ||
!targetState.production ||
!targetState.production.entities.length)
{
for (let ent in g_Selection.selected)
if (targetState.id == +ent)
return false;
}
return {
"possible": true,
"data": data,
"position": targetState.position,
"cursor": cursor,
"tooltip": tooltip
};
},
"actionCheck": function(target, selection)
{
if (someUnitAI(selection) || !someRallyPoints(selection))
return false;
let actionInfo = getActionInfo("set-rallypoint", target);
if (!actionInfo.possible)
return false;
return {
"type": "set-rallypoint",
"cursor": actionInfo.cursor,
"data": actionInfo.data,
"tooltip": actionInfo.tooltip,
"position": actionInfo.position
};
},
"specificness": 6,
},
"unset-rallypoint":
{
"execute": function(target, action, selection, queued)
{
Engine.PostNetworkCommand({
"type": "unset-rallypoint",
"entities": selection
});
// Remove displayed rally point
Engine.GuiInterfaceCall("DisplayRallyPoint", {
"entities": []
});
return true;
},
"getActionInfo": function(entState, targetState)
{
if (entState.id != targetState.id ||
!entState.rallyPoint || !entState.rallyPoint.position)
return false;
return { "possible": true };
},
"actionCheck": function(target, selection)
{
if (someUnitAI(selection) || !someRallyPoints(selection) ||
!getActionInfo("unset-rallypoint", target).possible)
return false;
return {
"type": "unset-rallypoint",
"cursor": "action-unset-rally"
};
},
"specificness": 11,
},
"none":
{
"execute": function(target, action, selection, queued)
{
return true;
},
"specificness": 100,
},
};
/**
* Info and actions for the entity commands
* Currently displayed in the bottom of the central panel
*/
var g_EntityCommands =
{
"unload-all": {
"getInfo": function(entState)
{
if (!entState.garrisonHolder)
return false;
let count = 0;
for (let ent in g_Selection.selected)
{
let state = GetEntityState(+ent);
if (state.garrisonHolder)
count += state.garrisonHolder.entities.length;
}
return {
- "tooltip": translate("Unload All"),
+ "tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.unload") +
+ translate("Unload All."),
"icon": "garrison-out.png",
"count": count,
};
},
"execute": function(entState)
{
unloadAll();
},
},
"delete": {
"getInfo": function(entState)
{
let deleteReason = isUndeletable(entState);
return deleteReason ?
{
"tooltip": deleteReason,
"icon": "kill_small_disabled.png"
} :
{
"tooltip":
colorizeHotkey("%(hotkey)s", "session.kill") + " " +
translate("Destroy the selected units or buildings.") + "\n" +
colorizeHotkey(
translate("Use %(hotkey)s to avoid the confirmation dialog."),
"session.noconfirmation"
),
"icon": "kill_small.png"
};
},
"execute": function(entState)
{
if (isUndeletable(entState))
return;
let selection = g_Selection.toList();
if (!selection.length)
return;
if (Engine.HotkeyIsPressed("session.noconfirmation"))
Engine.PostNetworkCommand({
"type": "delete-entities",
"entities": selection
});
else
openDeleteDialog(selection);
},
},
"stop": {
"getInfo": function(entState)
{
if (!entState.unitAI)
return false;
return {
"tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.stop") +
translate("Abort the current order."),
"icon": "stop.png"
};
},
"execute": function(entState)
{
let selection = g_Selection.toList();
if (selection.length)
stopUnits(selection);
},
},
"garrison": {
"getInfo": function(entState)
{
if (!entState.unitAI || entState.turretParent)
return false;
return {
"tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.garrison") +
translate("Order the selected units to garrison a building or unit."),
"icon": "garrison.png"
};
},
"execute": function(entState)
{
inputState = INPUT_PRESELECTEDACTION;
preSelectedAction = ACTION_GARRISON;
},
},
"unload": {
"getInfo": function(entState)
{
if (!entState.unitAI || !entState.turretParent)
return false;
let p = GetEntityState(entState.turretParent);
if (!p.garrisonHolder || p.garrisonHolder.entities.indexOf(entState.id) == -1)
return false;
return {
"tooltip": translate("Unload"),
"icon": "garrison-out.png"
};
},
"execute": function(entState)
{
unloadSelection();
},
},
"repair": {
"getInfo": function(entState)
{
if (!entState.builder)
return false;
return {
- "tooltip": translate("Repair"),
+ "tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.repair") +
+ translate("Order the selected units to repair a building or mechanical unit."),
"icon": "repair.png"
};
},
"execute": function(entState)
{
inputState = INPUT_PRESELECTEDACTION;
preSelectedAction = ACTION_REPAIR;
},
},
"focus-rally": {
"getInfo": function(entState)
{
if (!entState.rallyPoint)
return false;
return {
- "tooltip": translate("Focus on Rally Point"),
+ "tooltip": colorizeHotkey("%(hotkey)s" + " ", "camera.rallypointfocus") +
+ translate("Focus on Rally Point."),
"icon": "focus-rally.png"
};
},
"execute": function(entState)
{
let focusTarget;
if (entState.rallyPoint && entState.rallyPoint.position)
focusTarget = entState.rallyPoint.position;
else if (entState.position)
focusTarget = entState.position;
if (focusTarget)
Engine.CameraMoveTo(focusTarget.x, focusTarget.z);
},
},
"back-to-work": {
"getInfo": function(entState)
{
if (!entState.unitAI || !entState.unitAI.hasWorkOrders)
return false;
return {
"tooltip": translate("Back to Work"),
"icon": "production.png"
};
},
"execute": function(entState)
{
backToWork();
},
},
"add-guard": {
"getInfo": function(entState)
{
if (!entState.unitAI || !entState.unitAI.canGuard ||
entState.unitAI.isGuarding)
return false;
return {
"tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.guard") +
translate("Order the selected units to guard a building or unit."),
"icon": "add-guard.png"
};
},
"execute": function(entState)
{
inputState = INPUT_PRESELECTEDACTION;
preSelectedAction = ACTION_GUARD;
},
},
"remove-guard": {
"getInfo": function(entState)
{
if (!entState.unitAI || !entState.unitAI.isGuarding)
return false;
return {
"tooltip": translate("Remove guard"),
"icon": "remove-guard.png"
};
},
"execute": function(entState)
{
removeGuard();
},
},
"select-trading-goods": {
"getInfo": function(entState)
{
if (!entState.market)
return false;
return {
"tooltip": translate("Select trading goods"),
"icon": "economics.png"
};
},
"execute": function(entState)
{
toggleTrade();
},
},
"share-dropsite": {
"getInfo": function(entState)
{
if (!entState.resourceDropsite || !entState.resourceDropsite.sharable)
return false;
let playerState = GetSimState().players[entState.player];
if (!playerState.isMutualAlly.some((e, i) => e && i != entState.player))
return false;
if (entState.resourceDropsite.shared)
return {
"tooltip": translate("Press to prevent allies from using this dropsite"),
"icon": "unlocked_small.png"
};
return {
"tooltip": translate("Press to allow allies to use this dropsite"),
"icon": "locked_small.png"
};
},
"execute": function(entState)
{
Engine.PostNetworkCommand({
"type": "set-dropsite-sharing",
"entities": g_Selection.toList(),
"shared": !entState.resourceDropsite.shared
});
},
}
};
var g_AllyEntityCommands =
{
"unload-all": {
"getInfo": function(entState)
{
if (!entState.garrisonHolder)
return false;
let player = Engine.GetPlayerID();
let count = 0;
for (let ent in g_Selection.selected)
{
let selectedEntState = GetEntityState(+ent);
if (!selectedEntState.garrisonHolder)
continue;
for (let entity of selectedEntState.garrisonHolder.entities)
{
let state = GetEntityState(entity);
if (state.player == player)
++count;
}
}
return {
- "tooltip": translate("Unload All"),
+ "tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.unload") +
+ translate("Unload All."),
"icon": "garrison-out.png",
"count": count,
};
},
"execute": function(entState)
{
unloadAllByOwner();
},
},
"share-dropsite": {
"getInfo": function(entState)
{
if (Engine.GetPlayerID() == -1 ||
!GetSimState().players[Engine.GetPlayerID()].hasSharedDropsites ||
!entState.resourceDropsite || !entState.resourceDropsite.sharable)
return false;
if (entState.resourceDropsite.shared)
return {
"tooltip": translate("You are allowed to use this dropsite"),
"icon": "unlocked_small.png"
};
return {
"tooltip": translate("The use of this dropsite is prohibited"),
"icon": "locked_small.png"
};
},
"execute": function(entState)
{
// This command button is always disabled
},
}
};
function playerCheck(entState, targetState, validPlayers)
{
let playerState = GetSimState().players[entState.player];
for (let player of validPlayers)
{
if (player == "Gaia" && targetState.player == 0 ||
player == "Player" && targetState.player == entState.player ||
playerState["is"+player] && playerState["is"+player][targetState.player])
return true;
}
return false;
}
/**
* Work out whether at least part of the selected entities have UnitAI.
*/
function someUnitAI(entities)
{
return entities.some(ent => {
let entState = GetEntityState(ent);
return entState && entState.unitAI;
});
}
function someRallyPoints(entities)
{
return entities.some(ent => {
let entState = GetEntityState(ent);
return entState && entState.rallyPoint;
});
}
function someGuarding(entities)
{
return entities.some(ent => {
let entState = GetEntityState(ent);
return entState && entState.unitAI && entState.unitAI.isGuarding;
});
}
/**
* Keep in sync with Commands.js.
*/
function isUndeletable(entState)
{
if (g_DevSettings.controlAll)
return false;
if (entState.resourceSupply && entState.resourceSupply.killBeforeGather)
return translate("The entity has to be killed before it can be gathered from");
if (entState.capturePoints && entState.capturePoints[entState.player] < entState.maxCapturePoints / 2)
return translate("You cannot destroy this entity as you own less than half the capture points");
if (!entState.canDelete)
return translate("This entity is undeletable");
return false;
}