commit ab24419fee2fd86ba4cfcec2d85f86c67a526e4a
Author: Roel Kluin <roel.kluin@gmail.com>
Date: Sun Jun 10 21:37:36 2012 +0200
Separate function initBuildingPlacementView()
Building placement is now shown immediately, not after mouse movement.
User can use the same several hotkey more times, e.g. for training.
Or for iterate over the possible options using hotkeys, changing the
Formation or Stance of the selected units or choosing different buildings
during placement.
setting inputState = INPUT_PRESELECTEDACTION for build and garrison
alters mouse left/rightclick behavior.
Formation fix: don't allow hotkey if selection is only one unit
Add forwardslash as hotkey to reset action hotkey
Signed-off-by: Roel Kluin <roel.kluin@gmail.com>
diff --git a/binaries/data/config/default.cfg b/binaries/data/config/default.cfg
index 0f1220e..1f7c35c 100644
a
|
b
|
hotkey.selection.group.action.9 = "Shift+K"
|
202 | 202 | hotkey.selection.group.action.10 = "Shift+L" |
203 | 203 | hotkey.selection.group.action.11 = Colon |
204 | 204 | hotkey.selection.group.action.12 = DoubleQuote |
| 205 | hotkey.selection.group.reset.action = ForwardSlash |
205 | 206 | |
206 | 207 | ; > SESSION CONTROLS |
207 | 208 | hotkey.session.kill = Delete ; Destroy selected units |
diff --git a/binaries/data/mods/public/gui/session/input.js b/binaries/data/mods/public/gui/session/input.js
index 1888087..8775bb3 100644
a
|
b
|
const ACTION_STANCE = 32;
|
22 | 22 | const ACTION_BARTER = 64; |
23 | 23 | const ACTION_TRADER =128; |
24 | 24 | var preSelectedAction = ACTION_NONE; |
| 25 | |
| 26 | // N.B. reset this after selecting different units or buildings |
25 | 27 | var _optionsOfpreSelected = []; |
26 | 28 | |
27 | 29 | const INPUT_NORMAL = 0; |
… |
… |
function updateBuildingPlacementPreview()
|
144 | 146 | return false; |
145 | 147 | } |
146 | 148 | |
| 149 | function initBuildingPlacementView(ev) |
| 150 | { |
| 151 | if (placementSupport.mode === "wall") |
| 152 | { |
| 153 | // Including only the on-screen towers in the next snap candidate list is sufficient here, since the user is |
| 154 | // still selecting a starting point (which must necessarily be on-screen). (The update of the snap entities |
| 155 | // itself happens in the call to updateBuildingPlacementPreview below). |
| 156 | placementSupport.wallSnapEntitiesIncludeOffscreen = false; |
| 157 | } |
| 158 | else |
| 159 | { |
| 160 | var snapData = Engine.GuiInterfaceCall("GetFoundationSnapData", { |
| 161 | "template": placementSupport.template, |
| 162 | "x": placementSupport.position.x, |
| 163 | "z": placementSupport.position.z, |
| 164 | }); |
| 165 | if (snapData) |
| 166 | { |
| 167 | placementSupport.angle = snapData.angle; |
| 168 | placementSupport.position.x = snapData.x; |
| 169 | placementSupport.position.z = snapData.z; |
| 170 | } |
| 171 | } |
| 172 | updateBuildingPlacementPreview(); // includes an update of the snap entity candidates |
| 173 | } |
| 174 | |
147 | 175 | function findGatherType(gatherer, supply) |
148 | 176 | { |
149 | 177 | if (!gatherer || !supply) |
… |
… |
function findGatherType(gatherer, supply)
|
155 | 183 | return undefined; |
156 | 184 | } |
157 | 185 | |
| 186 | function resetPreselectedAction() |
| 187 | { |
| 188 | placementSupport.Reset(); |
| 189 | inputState = INPUT_NORMAL; |
| 190 | _optionsOfpreSelected = []; |
| 191 | |
| 192 | } |
| 193 | |
158 | 194 | function getActionInfo(action, target) |
159 | 195 | { |
160 | 196 | var selection = g_Selection.toList(); |
… |
… |
function determineAction(x, y, fromMinimap)
|
449 | 485 | break; |
450 | 486 | } |
451 | 487 | } |
452 | | else if (Engine.HotkeyIsPressed("session.garrison")) |
| 488 | else if (Engine.HotkeyIsPressed("session.garrison") || preSelectedAction == ACTION_GARRISON) |
453 | 489 | { |
454 | 490 | if (getActionInfo("garrison", target).possible) |
455 | 491 | return {"type": "garrison", "cursor": "action-garrison", "target": target}; |
… |
… |
function handleInputBeforeGui(ev, hoveredObject)
|
755 | 791 | var queued = Engine.HotkeyIsPressed("session.queue"); |
756 | 792 | if (tryPlaceBuilding(queued)) |
757 | 793 | { |
758 | | if (queued) { |
| 794 | if (queued) |
759 | 795 | inputState = INPUT_BUILDING_PLACEMENT; |
760 | | } else { |
761 | | inputState = INPUT_NORMAL; |
762 | | _optionsOfpreSelected = []; |
763 | | } |
| 796 | else |
| 797 | resetPreselectedAction(); |
764 | 798 | } |
765 | 799 | else |
766 | 800 | { |
… |
… |
function handleInputBeforeGui(ev, hoveredObject)
|
774 | 808 | if (ev.button == SDL_BUTTON_RIGHT) |
775 | 809 | { |
776 | 810 | // Cancel building |
777 | | placementSupport.Reset(); |
778 | | inputState = INPUT_NORMAL; |
779 | | _optionsOfpreSelected = []; |
| 811 | resetPreselectedAction(); |
780 | 812 | return true; |
781 | 813 | } |
782 | 814 | break; |
… |
… |
function handleInputAfterGui(ev)
|
998 | 1030 | return false; |
999 | 1031 | |
1000 | 1032 | case "mousebuttondown": |
| 1033 | _optionsOfpreSelected = []; |
1001 | 1034 | if (ev.button == SDL_BUTTON_LEFT) |
1002 | 1035 | { |
1003 | 1036 | dragStart = [ ev.x, ev.y ]; |
… |
… |
function handleInputAfterGui(ev)
|
1014 | 1047 | break; |
1015 | 1048 | |
1016 | 1049 | case "hotkeydown": |
1017 | | if (ev.hotkey.indexOf("selection.group.") == 0) |
| 1050 | if (ev.hotkey && ev.hotkey.indexOf("selection.group.") == 0) |
1018 | 1051 | { |
| 1052 | var sptr = ev.hotkey.split("."); |
1019 | 1053 | var now = new Date(); |
1020 | | if ((now.getTime() - doublePressTimer < doublePressTime) && (ev.hotkey == prevHotkey)) |
1021 | | { |
1022 | | if (ev.hotkey.indexOf("selection.group.select.") == 0) |
1023 | | { |
1024 | | var sptr = ev.hotkey.split("."); |
1025 | | performGroup("snap", sptr[3]); |
1026 | | } |
| 1054 | if ((now.getTime() - doublePressTimer < doublePressTime) && (ev.hotkey == prevHotkey) && ev.hotkey.indexOf("selection.group.select.") == 0) { |
| 1055 | performGroup("snap", sptr[3], ev); |
1027 | 1056 | } |
1028 | 1057 | else |
1029 | 1058 | { |
1030 | | var sptr = ev.hotkey.split("."); |
1031 | | performGroup(sptr[2], sptr[3]); |
| 1059 | performGroup(sptr[2], sptr[3], ev); |
1032 | 1060 | |
1033 | 1061 | doublePressTimer = now.getTime(); |
1034 | 1062 | prevHotkey = ev.hotkey; |
… |
… |
function handleInputAfterGui(ev)
|
1045 | 1073 | if (ev.button == SDL_BUTTON_LEFT && preSelectedAction != ACTION_NONE) |
1046 | 1074 | { |
1047 | 1075 | var action = determineAction(ev.x, ev.y); |
| 1076 | resetPreselectedAction(); |
1048 | 1077 | if (!action) |
1049 | 1078 | break; |
1050 | | preSelectedAction = ACTION_NONE; |
1051 | | inputState = INPUT_NORMAL; |
1052 | | _optionsOfpreSelected = []; |
1053 | 1079 | return doAction(action, ev); |
1054 | 1080 | } |
1055 | 1081 | else if (ev.button == SDL_BUTTON_RIGHT && preSelectedAction != ACTION_NONE) |
1056 | 1082 | { |
1057 | | preSelectedAction = ACTION_NONE; |
1058 | | inputState = INPUT_NORMAL; |
1059 | | _optionsOfpreSelected = []; |
| 1083 | resetPreselectedAction(); |
1060 | 1084 | break; |
1061 | 1085 | } |
1062 | | // else |
1063 | 1086 | case "hotkeydown": |
1064 | | if (!ev.hotkey) |
1065 | | break; |
1066 | | |
1067 | | if (ev.hotkey.indexOf("selection.group.action.") == 0) |
| 1087 | if (ev.hotkey && ev.hotkey.indexOf("selection.group.action.") == 0) |
1068 | 1088 | { |
1069 | 1089 | var sptr = ev.hotkey.split("."); |
1070 | 1090 | performGroup(sptr[2], sptr[3]); |
… |
… |
function handleInputAfterGui(ev)
|
1074 | 1094 | // Slight hack: If selection is empty, reset the input state |
1075 | 1095 | if (g_Selection.toList().length == 0) |
1076 | 1096 | { |
1077 | | preSelectedAction = ACTION_NONE; |
1078 | | inputState = INPUT_NORMAL; |
1079 | | _optionsOfpreSelected = []; |
| 1097 | resetPreselectedAction(); |
1080 | 1098 | break; |
1081 | 1099 | } |
1082 | 1100 | } |
… |
… |
function handleInputAfterGui(ev)
|
1108 | 1126 | { |
1109 | 1127 | g_Selection.reset(); |
1110 | 1128 | resetEntitySearch(); |
1111 | | inputState = INPUT_NORMAL; |
1112 | | _optionsOfpreSelected = []; |
| 1129 | resetPreselectedAction(); |
1113 | 1130 | return true; |
1114 | 1131 | } |
1115 | 1132 | |
… |
… |
function handleInputAfterGui(ev)
|
1183 | 1200 | g_Selection.reset(); |
1184 | 1201 | g_Selection.addList(ents); |
1185 | 1202 | } |
1186 | | |
1187 | | inputState = INPUT_NORMAL; |
1188 | | _optionsOfpreSelected = []; |
| 1203 | resetPreselectedAction(); |
1189 | 1204 | return true; |
1190 | 1205 | } |
1191 | 1206 | break; |
… |
… |
function handleInputAfterGui(ev)
|
1196 | 1211 | switch (ev.type) |
1197 | 1212 | { |
1198 | 1213 | case "mousemotion": |
1199 | | |
1200 | 1214 | placementSupport.position = Engine.GetTerrainAtScreenPoint(ev.x, ev.y); |
1201 | | |
1202 | | if (placementSupport.mode === "wall") |
1203 | | { |
1204 | | // Including only the on-screen towers in the next snap candidate list is sufficient here, since the user is |
1205 | | // still selecting a starting point (which must necessarily be on-screen). (The update of the snap entities |
1206 | | // itself happens in the call to updateBuildingPlacementPreview below). |
1207 | | placementSupport.wallSnapEntitiesIncludeOffscreen = false; |
1208 | | } |
1209 | | else |
1210 | | { |
1211 | | var snapData = Engine.GuiInterfaceCall("GetFoundationSnapData", { |
1212 | | "template": placementSupport.template, |
1213 | | "x": placementSupport.position.x, |
1214 | | "z": placementSupport.position.z, |
1215 | | }); |
1216 | | if (snapData) |
1217 | | { |
1218 | | placementSupport.angle = snapData.angle; |
1219 | | placementSupport.position.x = snapData.x; |
1220 | | placementSupport.position.z = snapData.z; |
1221 | | } |
1222 | | } |
1223 | | |
1224 | | updateBuildingPlacementPreview(); // includes an update of the snap entity candidates |
| 1215 | initBuildingPlacementView(ev); |
1225 | 1216 | return false; // continue processing mouse motion |
1226 | 1217 | |
1227 | 1218 | case "mousebuttondown": |
… |
… |
function handleInputAfterGui(ev)
|
1238 | 1229 | else |
1239 | 1230 | { |
1240 | 1231 | placementSupport.position = Engine.GetTerrainAtScreenPoint(ev.x, ev.y); |
1241 | | dragStart = [ ev.x, ev.y ]; |
1242 | | inputState = INPUT_BUILDING_CLICK; |
| 1232 | dragStart = [ ev.x, ev.y ]; |
| 1233 | inputState = INPUT_BUILDING_CLICK; |
| 1234 | _optionsOfpreSelected = []; |
1243 | 1235 | } |
1244 | 1236 | return true; |
1245 | 1237 | } |
… |
… |
function handleInputAfterGui(ev)
|
1247 | 1239 | { |
1248 | 1240 | // Cancel building |
1249 | 1241 | placementSupport.Reset(); |
1250 | | inputState = INPUT_NORMAL; |
1251 | | preSelectedAction = ACTION_NONE; |
1252 | | _optionsOfpreSelected = []; |
| 1242 | resetPreselectedAction(); |
1253 | 1243 | return true; |
1254 | 1244 | } |
1255 | 1245 | break; |
… |
… |
function handleInputAfterGui(ev)
|
1268 | 1258 | placementSupport.angle -= rotation_step; |
1269 | 1259 | updateBuildingPlacementPreview(); |
1270 | 1260 | break; |
| 1261 | default: |
| 1262 | if (ev.hotkey.indexOf("selection.group.action.") == 0) |
| 1263 | { // can switch buildings |
| 1264 | var sptr = ev.hotkey.split("."); |
| 1265 | performGroup(sptr[2], sptr[3], ev); |
| 1266 | } |
1271 | 1267 | } |
1272 | 1268 | break; |
1273 | 1269 | |
… |
… |
function getActionForSelection(player, selection)
|
1618 | 1614 | switch (preSelectedAction) |
1619 | 1615 | { |
1620 | 1616 | case ACTION_GARRISON: |
1621 | | if (state.buildEntities || (hasClass(state, "Unit") && !hasClass(state, "Animal") && !state.garrisonHolder)) |
| 1617 | if (state.buildEntities || (hasClass(state, "Unit") && !hasClass(state, "Animal") && !state.garrisonHolder)) { |
| 1618 | inputState = INPUT_PRESELECTEDACTION; |
1622 | 1619 | ret.push(ent); |
| 1620 | } |
1623 | 1621 | break; |
1624 | 1622 | case ACTION_BUILD: |
1625 | | if (state.buildEntities && state.buildEntities.length) |
| 1623 | if (state.buildEntities && state.buildEntities.length) { |
| 1624 | inputState = INPUT_PRESELECTEDACTION; |
1626 | 1625 | return state.buildEntities; |
| 1626 | } |
1627 | 1627 | break; |
1628 | 1628 | case ACTION_TRAIN: |
1629 | 1629 | if (state.production && state.production.entities.length) |
… |
… |
function getActionForSelection(player, selection)
|
1638 | 1638 | if (!hasClass(state, "Unit") || hasClass(state, "Animal") || state.garrisonHolder) |
1639 | 1639 | break; |
1640 | 1640 | |
1641 | | if (preSelectedAction == ACTION_FORMATION) { |
1642 | | return Engine.GuiInterfaceCall("GetAvailableFormations"); |
1643 | | } else { // FIXME: |
| 1641 | if (preSelectedAction == STANCE) |
1644 | 1642 | return ["violent", "aggressive", "passive", "defensive", "standground"]; |
1645 | | } |
| 1643 | if (ret.length) // minimimum is 2 units for formation to be enabled |
| 1644 | return Engine.GuiInterfaceCall("GetAvailableFormations"); |
| 1645 | ret.push(1); |
1646 | 1646 | break; |
1647 | 1647 | case ACTION_BARTER: |
1648 | 1648 | if (state.barterMarket) |
… |
… |
function getActionForSelection(player, selection)
|
1660 | 1660 | } |
1661 | 1661 | |
1662 | 1662 | // Performs the specified group |
1663 | | function performGroup(action, nr) |
| 1663 | function performGroup(action, nr, ev) |
1664 | 1664 | { |
1665 | 1665 | switch (action) |
1666 | 1666 | { |
… |
… |
function performGroup(action, nr)
|
1698 | 1698 | var actions = getActionForSelection(player, selection); |
1699 | 1699 | if (!actions || !actions.length) { |
1700 | 1700 | preSelectedAction = ACTION_NONE; |
1701 | | _optionsOfpreSelected = []; |
1702 | 1701 | break; |
1703 | 1702 | } |
1704 | 1703 | |
… |
… |
function performGroup(action, nr)
|
1707 | 1706 | else if (preSelectedAction == ACTION_TRADER) |
1708 | 1707 | setupUnitTradingPanel(state, selection); |
1709 | 1708 | |
1710 | | inputState = INPUT_PRESELECTEDACTION; |
1711 | 1709 | _optionsOfpreSelected = actions; |
1712 | 1710 | } |
1713 | 1711 | else |
… |
… |
function performGroup(action, nr)
|
1735 | 1733 | { |
1736 | 1734 | case ACTION_BUILD: |
1737 | 1735 | var tmpl = GetTemplateData(lst); |
1738 | | if (tmpl.requiredTechnology && !Engine.GuiInterfaceCall("IsTechnologyResearched", tmpl.requiredTechnology)) |
1739 | | break; |
1740 | | |
1741 | | startBuildingPlacement(lst); |
1742 | | inputState = INPUT_BUILDING_PLACEMENT; |
1743 | | preSelectedAction = ACTION_NONE; |
1744 | | return; |
| 1736 | if (!tmpl.requiredTechnology || Engine.GuiInterfaceCall("IsTechnologyResearched", tmpl.requiredTechnology)) { |
| 1737 | // N.B. sets inputState = INPUT_BUILDING_PLACEMENT: |
| 1738 | startBuildingPlacement(lst); |
| 1739 | placementSupport.position = Engine.GetTerrainAtScreenPoint(mouseX, mouseY); |
| 1740 | initBuildingPlacementView(ev); |
| 1741 | } |
| 1742 | break; |
1745 | 1743 | case ACTION_TRAIN: |
1746 | 1744 | var tmpl = GetTemplateData(lst); |
1747 | 1745 | if (!tmpl.requiredTechnology || Engine.GuiInterfaceCall("IsTechnologyResearched", tmpl.requiredTechnology)) { |
… |
… |
function performGroup(action, nr)
|
1753 | 1751 | g_Selection.reset(); |
1754 | 1752 | lst.splice(nr, lst.length - nr) |
1755 | 1753 | g_Selection.addList(lst); |
| 1754 | inputState = INPUT_PRESELECTEDACTION; |
1756 | 1755 | break; |
1757 | 1756 | case ACTION_UNGARRISON: |
1758 | | if (lst.length != 1 || nr == 0) { |
| 1757 | if (lst.length > 1 || nr == 0) { |
| 1758 | if (lst.length != 1) // TODO: uload all from all |
| 1759 | lst = lst[nr]; // selected buildings |
| 1760 | else |
| 1761 | lst = lst[0]; |
| 1762 | // FIXME: follow when ungarrisoning all |
1759 | 1763 | var state = GetEntityState(lst); |
1760 | | var gents = state.garrisonHolder.entities |
1761 | | unloadAll(lst[nr]); |
1762 | | // TODO: follow when ungarrisoning all |
1763 | | //var gents = g_Selection.toList(); |
1764 | | // Engine.CameraFollow(gents[0]); |
| 1764 | var gents = state.garrisonHolder.entities; |
| 1765 | unloadAll(lst); |
| 1766 | Engine.CameraFollow(0); |
| 1767 | g_Selection.reset(); |
| 1768 | g_Selection.addList(gents); |
| 1769 | Engine.CameraFollow(gents[0]); |
1765 | 1770 | } else { |
1766 | 1771 | lst = lst[0]; |
1767 | 1772 | var state = GetEntityState(lst); |
… |
… |
function performGroup(action, nr)
|
1788 | 1793 | case ACTION_TRADER: //TODO |
1789 | 1794 | break; |
1790 | 1795 | } |
1791 | | inputState = INPUT_NORMAL; |
1792 | | _optionsOfpreSelected = []; |
1793 | 1796 | } |
| 1797 | break; |
| 1798 | case "reset": |
| 1799 | resetPreselectedAction(); |
| 1800 | break; |
1794 | 1801 | } |
1795 | 1802 | } |
1796 | 1803 | |
… |
… |
function resetEntitySearch()
|
1837 | 1844 | |
1838 | 1845 | function findEntity(classes, mode) |
1839 | 1846 | { |
| 1847 | var player = Engine.GetPlayerID(); |
1840 | 1848 | // Cycle through idling classes before giving up |
1841 | 1849 | for (var i = 0; i <= classes.length; ++i) |
1842 | 1850 | { |
… |
… |
function findEntity(classes, mode)
|
1844 | 1852 | var newEntity = Engine.GuiInterfaceCall("FindEntity", data); |
1845 | 1853 | if (newEntity && newEntity != lastEntity) |
1846 | 1854 | { |
| 1855 | if (!getActionForSelection(player, [newEntity]).length) |
| 1856 | resetPreselectedAction(); |
| 1857 | |
1847 | 1858 | lastEntity = newEntity; |
1848 | 1859 | g_Selection.reset(); |
1849 | 1860 | g_Selection.addList([lastEntity]); |
commit 5656cbab54bcd160f89a6b6681f6329f8b4d15aa
Author: Roel Kluin <roel.kluin@gmail.com>
Date: Sun Jun 10 12:24:03 2012 +0200
was too much indented (no semantic change)
Signed-off-by: Roel Kluin <roel.kluin@gmail.com>
diff --git a/binaries/data/mods/public/gui/session/input.js b/binaries/data/mods/public/gui/session/input.js
index 7da7546..1888087 100644
a
|
b
|
function handleInputAfterGui(ev)
|
1014 | 1014 | break; |
1015 | 1015 | |
1016 | 1016 | case "hotkeydown": |
1017 | | if (ev.hotkey.indexOf("selection.group.") == 0) |
| 1017 | if (ev.hotkey.indexOf("selection.group.") == 0) |
| 1018 | { |
| 1019 | var now = new Date(); |
| 1020 | if ((now.getTime() - doublePressTimer < doublePressTime) && (ev.hotkey == prevHotkey)) |
1018 | 1021 | { |
1019 | | var now = new Date(); |
1020 | | if ((now.getTime() - doublePressTimer < doublePressTime) && (ev.hotkey == prevHotkey)) |
1021 | | { |
1022 | | if (ev.hotkey.indexOf("selection.group.select.") == 0) |
1023 | | { |
1024 | | var sptr = ev.hotkey.split("."); |
1025 | | performGroup("snap", sptr[3]); |
1026 | | } |
1027 | | } |
1028 | | else |
| 1022 | if (ev.hotkey.indexOf("selection.group.select.") == 0) |
1029 | 1023 | { |
1030 | 1024 | var sptr = ev.hotkey.split("."); |
1031 | | performGroup(sptr[2], sptr[3]); |
1032 | | |
1033 | | doublePressTimer = now.getTime(); |
1034 | | prevHotkey = ev.hotkey; |
| 1025 | performGroup("snap", sptr[3]); |
1035 | 1026 | } |
1036 | 1027 | } |
1037 | | break; |
| 1028 | else |
| 1029 | { |
| 1030 | var sptr = ev.hotkey.split("."); |
| 1031 | performGroup(sptr[2], sptr[3]); |
| 1032 | |
| 1033 | doublePressTimer = now.getTime(); |
| 1034 | prevHotkey = ev.hotkey; |
| 1035 | } |
| 1036 | } |
| 1037 | break; |
1038 | 1038 | } |
1039 | 1039 | break; |
1040 | 1040 | |