Ticket #1492: hotkeys_total.2.patch
File hotkeys_total.2.patch, 35.3 KB (added by , 12 years ago) |
---|
-
binaries/data/config/default.cfg
diff --git a/binaries/data/config/default.cfg b/binaries/data/config/default.cfg index 7a7ff2e..6d9bfaa 100644
a b hotkey.pause = Pause ; Pause/unpause game 119 119 hotkey.screenshot = F2 ; Take PNG screenshot 120 120 hotkey.bigscreenshot = "Shift+F2" ; Take large BMP screenshot 121 121 hotkey.togglefullscreen = "Alt+Return" ; Toggle fullscreen/windowed mode 122 hotkey.screenshot.watermark = " K" ; Toggle product/company watermark for official screenshots122 hotkey.screenshot.watermark = "R" ; Toggle product/company watermark for official screenshots 123 123 hotkey.wireframe = "Alt+W" ; Toggle wireframe mode 124 124 hotkey.silhouettes = "Alt+S" ; Toggle unit silhouettes 125 125 126 126 ; > CAMERA SETTINGS 127 hotkey.camera.reset = " H" ; Reset camera rotation to default.127 hotkey.camera.reset = "X" ; Reset camera rotation to default. 128 128 hotkey.camera.follow = "F" ; Follow the first unit in the selection 129 129 hotkey.camera.zoom.in = Plus, Equals, NumPlus ; Zoom camera in (continuous control) 130 130 hotkey.camera.zoom.out = Minus, NumMinus ; Zoom camera out (continuous control) … … hotkey.selection.add = Shift ; Add units to selection 155 155 hotkey.selection.milonly = Alt ; Add only military units to selection 156 156 hotkey.selection.remove = Ctrl ; Remove units from selection 157 157 hotkey.selection.idleworker = Period ; Select next idle worker 158 hotkey.selection.structure = Y ; Select structure 159 hotkey.selection.civilcenter = U ; Select towncenter 160 hotkey.selection.dropsiteres = I ; Select dropsite stone/wood/metal 161 hotkey.selection.dropsitefood = O ; Select dropsite food 162 hotkey.selection.market = P ; Select market 158 163 hotkey.selection.idlewarrior = Comma ; Select next idle warrior 159 164 hotkey.selection.offscreen = Alt ; Include offscreen units in selection 160 165 hotkey.selection.group.select.0 = 0 … … hotkey.selection.group.select.9 = 9 188 193 hotkey.selection.group.save.9 = "Ctrl+9" 189 194 hotkey.selection.group.add.9 = "Shift+9" 190 195 196 hotkey.selection.group.action.0 = G 197 hotkey.selection.group.action.1 = H 198 hotkey.selection.group.action.2 = J 199 hotkey.selection.group.action.3 = K 200 hotkey.selection.group.action.4 = L 201 hotkey.selection.group.action.5 = Semicolon 202 hotkey.selection.group.action.6 = SingleQuote 203 hotkey.selection.group.action.7 = "Ctrl+G" 204 hotkey.selection.group.action.8 = "Ctrl+H" 205 hotkey.selection.group.action.9 = "Ctrl+J" 206 hotkey.selection.group.action.10 = "Ctrl+K" 207 hotkey.selection.group.action.11 = "Ctrl+L" 208 hotkey.selection.group.action.12 = "Ctrl+Semicolon" 209 hotkey.selection.group.action.13 = "Ctrl+SingleQuote" 210 hotkey.selection.group.reset.0 = ForwardSlash 211 hotkey.selection.group.stance.0 = V 212 hotkey.selection.group.formation.0 = B 213 hotkey.selection.group.garrison.0 = N 214 hotkey.selection.group.ungarrison.0 = M 215 191 216 ; > SESSION CONTROLS 192 217 hotkey.session.kill = Delete ; Destroy selected units 193 218 hotkey.session.garrison = Ctrl ; Modifier to garrison when clicking on building -
binaries/data/mods/public/gui/session/input.js
diff --git a/binaries/data/mods/public/gui/session/input.js b/binaries/data/mods/public/gui/session/input.js index ff39b74..a2cdc0a 100644
a b const SDLK_LALT = 308; 14 14 15 15 const ACTION_NONE = 0; 16 16 const ACTION_GARRISON = 1; 17 const ACTION_REPAIR = 2; 17 const ACTION_BUILD = 2; 18 const ACTION_TRAIN = 4; 19 const ACTION_UNGARRISON = 8; 20 const ACTION_FORMATION = 16; 21 const ACTION_STANCE = 32; 22 const ACTION_BARTER = 64; 23 const ACTION_TRADER =128; 18 24 var preSelectedAction = ACTION_NONE; 19 25 26 var followQueue = []; 27 20 28 const INPUT_NORMAL = 0; 21 29 const INPUT_SELECTING = 1; 22 30 const INPUT_BANDBOXING = 2; … … const INPUT_BATCHTRAINING = 6; 27 35 const INPUT_PRESELECTEDACTION = 7; 28 36 const INPUT_BUILDING_WALL_CLICK = 8; 29 37 const INPUT_BUILDING_WALL_PATHING = 9; 38 const INPUT_ACTION_STATE = 10; 30 39 31 40 var inputState = INPUT_NORMAL; 32 41 var placementSupport = new PlacementSupport(); … … function updateBuildingPlacementPreview() 137 146 return false; 138 147 } 139 148 149 function initBuildingPlacementView() 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 140 175 function findGatherType(gatherer, supply) 141 176 { 142 177 if (!gatherer || !supply) … … function findGatherType(gatherer, supply) 148 183 return undefined; 149 184 } 150 185 186 function resetPreselectedAction() 187 { 188 preSelectedAction = ACTION_NONE; 189 inputState = INPUT_NORMAL; 190 placementSupport.Reset(); // or a hotkey may leave a building snapshot 191 updateCursorAndTooltip(); 192 193 } 194 151 195 function getActionInfo(action, target) 152 196 { 153 197 var selection = g_Selection.toList(); … … function determineAction(x, y, fromMinimap) 423 467 { 424 468 target = targets[0]; 425 469 } 470 if (Engine.HotkeyIsPressed("session.garrison")) 471 preSelectedAction = ACTION_GARRISON; 426 472 427 if (preSelectedAction != ACTION_NONE)473 if (preSelectedAction & (ACTION_GARRISON|ACTION_BUILD)) 428 474 { 429 475 switch (preSelectedAction) 430 476 { … … function determineAction(x, y, fromMinimap) 434 480 else 435 481 return {"type": "none", "cursor": "action-garrison-disabled", "target": undefined}; 436 482 break; 437 case ACTION_ REPAIR:483 case ACTION_BUILD: 438 484 if (getActionInfo("repair", target).possible) 439 485 return {"type": "repair", "cursor": "action-repair", "target": target}; 440 486 else … … function determineAction(x, y, fromMinimap) 442 488 break; 443 489 } 444 490 } 445 else if (Engine.HotkeyIsPressed("session.garrison"))446 {447 if (getActionInfo("garrison", target).possible)448 return {"type": "garrison", "cursor": "action-garrison", "target": target};449 else450 return {"type": "none", "cursor": "action-garrison-disabled", "target": undefined};451 }452 491 else 453 492 { 454 493 var actionInfo = undefined; … … function handleInputBeforeGui(ev, hoveredObject) 623 662 mouseY = ev.y; 624 663 break; 625 664 } 626 665 if (followQueue.length) 666 { 667 var gents = followQueue; 668 var state = GetEntityState(gents[0]); 669 if (state.visibility == "hidden") 670 return true; 671 Engine.CameraFollow(0); 672 Engine.CameraFollow(gents[0]); 673 g_Selection.addList(gents); 674 resetPreselectedAction(); 675 followQueue = []; // for next time. 676 } 627 677 // Remember whether the mouse is over a GUI object or not 628 678 mouseIsOverObject = (hoveredObject != null); 629 679 … … function handleInputBeforeGui(ev, hoveredObject) 751 801 if (queued) 752 802 inputState = INPUT_BUILDING_PLACEMENT; 753 803 else 754 inputState = INPUT_NORMAL;804 resetPreselectedAction(); 755 805 } 756 806 else 757 807 { … … function handleInputBeforeGui(ev, hoveredObject) 765 815 if (ev.button == SDL_BUTTON_RIGHT) 766 816 { 767 817 // Cancel building 768 placementSupport.Reset(); 769 inputState = INPUT_NORMAL; 818 resetPreselectedAction(); 770 819 return true; 771 820 } 772 821 break; … … function handleInputAfterGui(ev) 975 1024 switch (inputState) 976 1025 { 977 1026 case INPUT_NORMAL: 1027 case INPUT_ACTION_STATE: 978 1028 switch (ev.type) 979 1029 { 980 1030 case "mousemotion": … … function handleInputAfterGui(ev) 1004 1054 break; 1005 1055 1006 1056 case "hotkeydown": 1007 if (ev.hotkey.indexOf("selection.group.") == 0) 1008 { 1009 var now = new Date(); 1010 if ((now.getTime() - doublePressTimer < doublePressTime) && (ev.hotkey == prevHotkey)) 1011 { 1012 if (ev.hotkey.indexOf("selection.group.select.") == 0) 1013 { 1014 var sptr = ev.hotkey.split("."); 1015 performGroup("snap", sptr[3]); 1016 } 1017 } 1018 else 1019 { 1020 var sptr = ev.hotkey.split("."); 1021 performGroup(sptr[2], sptr[3]); 1022 1023 doublePressTimer = now.getTime(); 1024 prevHotkey = ev.hotkey; 1025 } 1026 } 1027 break; 1057 handleHotkey(ev); 1058 break; 1028 1059 } 1029 1060 break; 1030 1061 … … function handleInputAfterGui(ev) 1035 1066 if (ev.button == SDL_BUTTON_LEFT && preSelectedAction != ACTION_NONE) 1036 1067 { 1037 1068 var action = determineAction(ev.x, ev.y); 1069 resetPreselectedAction(); 1038 1070 if (!action) 1039 1071 break; 1040 preSelectedAction = ACTION_NONE;1041 inputState = INPUT_NORMAL;1042 1072 return doAction(action, ev); 1043 1073 } 1044 else if (ev.button == SDL_BUTTON_RIGHT && preSelectedAction != ACTION_NONE)1074 else if (ev.button == SDL_BUTTON_RIGHT) 1045 1075 { 1046 preSelectedAction = ACTION_NONE; 1047 inputState = INPUT_NORMAL; 1076 resetPreselectedAction(); 1048 1077 break; 1049 1078 } 1050 // else 1079 case "hotkeydown": 1080 handleHotkey(ev); 1081 break; 1051 1082 default: 1052 1083 // Slight hack: If selection is empty, reset the input state 1053 1084 if (g_Selection.toList().length == 0) 1054 1085 { 1055 preSelectedAction = ACTION_NONE; 1056 inputState = INPUT_NORMAL; 1086 resetPreselectedAction(); 1057 1087 break; 1058 1088 } 1059 1089 } … … function handleInputAfterGui(ev) 1084 1114 if (!ents.length) 1085 1115 { 1086 1116 g_Selection.reset(); 1087 reset IdleUnit();1088 inputState = INPUT_NORMAL;1117 resetEntitySearch(); 1118 resetPreselectedAction(); 1089 1119 return true; 1090 1120 } 1091 1092 1121 var selectedEntity = ents[0]; 1093 var now = new Date();1094 1122 1095 1123 // If camera following and we select different unit, stop 1096 1124 if (Engine.GetFollowedEntity() != selectedEntity) 1097 1125 { 1098 1126 Engine.CameraFollow(0); 1099 1127 } 1100 1101 if ((now.getTime() - doubleClickTimer < doubleClickTime) && (selectedEntity == prevClickedEntity)) 1102 { 1103 // Double click or triple click has occurred 1104 var showOffscreen = Engine.HotkeyIsPressed("selection.offscreen"); 1105 var matchRank = true; 1106 var templateToMatch; 1107 1108 // Check for double click or triple click 1109 if (!doubleClicked) 1110 { 1111 // If double click hasn't already occurred, this is a double click. 1112 // Select similar units regardless of rank 1113 templateToMatch = Engine.GuiInterfaceCall("GetEntityState", selectedEntity).identity.selectionGroupName; 1114 if (templateToMatch) 1115 { 1116 matchRank = false; 1117 } 1118 else 1119 { // No selection group name defined, so fall back to exact match 1120 templateToMatch = Engine.GuiInterfaceCall("GetEntityState", selectedEntity).template; 1121 } 1122 1123 doubleClicked = true; 1124 // Reset the timer so the user has an extra period 'doubleClickTimer' to do a triple-click 1125 doubleClickTimer = now.getTime(); 1126 } 1127 else 1128 { 1129 // Double click has already occurred, so this is a triple click. 1130 // Select units matching exact template name (same rank) 1131 templateToMatch = Engine.GuiInterfaceCall("GetEntityState", selectedEntity).template; 1132 } 1133 1134 // TODO: Should we handle "control all units" here as well? 1135 ents = Engine.PickSimilarFriendlyEntities(templateToMatch, showOffscreen, matchRank, false); 1136 } 1137 else 1138 { 1139 // It's single click right now but it may become double or triple click 1140 doubleClicked = false; 1141 doubleClickTimer = now.getTime(); 1142 prevClickedEntity = selectedEntity; 1143 1144 // We only want to include the first picked unit in the selection 1145 ents = [ents[0]]; 1146 } 1147 1148 // Update the list of selected units 1149 if (Engine.HotkeyIsPressed("selection.add")) 1150 { 1151 g_Selection.addList(ents); 1152 } 1153 else if (Engine.HotkeyIsPressed("selection.remove")) 1154 { 1155 g_Selection.removeList(ents); 1156 } 1157 else 1158 { 1159 g_Selection.reset(); 1160 g_Selection.addList(ents); 1161 } 1162 1163 inputState = INPUT_NORMAL; 1128 ClickSelected(ents, (selectedEntity == prevClickedEntity)); 1164 1129 return true; 1165 1130 } 1166 1131 break; … … function handleInputAfterGui(ev) 1171 1136 switch (ev.type) 1172 1137 { 1173 1138 case "mousemotion": 1174 1175 1139 placementSupport.position = Engine.GetTerrainAtScreenPoint(ev.x, ev.y); 1176 1177 if (placementSupport.mode === "wall") 1178 { 1179 // Including only the on-screen towers in the next snap candidate list is sufficient here, since the user is 1180 // still selecting a starting point (which must necessarily be on-screen). (The update of the snap entities 1181 // itself happens in the call to updateBuildingPlacementPreview below). 1182 placementSupport.wallSnapEntitiesIncludeOffscreen = false; 1183 } 1184 else 1185 { 1186 var snapData = Engine.GuiInterfaceCall("GetFoundationSnapData", { 1187 "template": placementSupport.template, 1188 "x": placementSupport.position.x, 1189 "z": placementSupport.position.z, 1190 }); 1191 if (snapData) 1192 { 1193 placementSupport.angle = snapData.angle; 1194 placementSupport.position.x = snapData.x; 1195 placementSupport.position.z = snapData.z; 1196 } 1197 } 1198 1199 updateBuildingPlacementPreview(); // includes an update of the snap entity candidates 1140 initBuildingPlacementView(); 1200 1141 return false; // continue processing mouse motion 1201 1142 1202 1143 case "mousebuttondown": … … function handleInputAfterGui(ev) 1213 1154 else 1214 1155 { 1215 1156 placementSupport.position = Engine.GetTerrainAtScreenPoint(ev.x, ev.y); 1216 1217 1157 dragStart = [ ev.x, ev.y ]; 1158 inputState = INPUT_BUILDING_CLICK; 1218 1159 } 1219 1160 return true; 1220 1161 } … … function handleInputAfterGui(ev) 1222 1163 { 1223 1164 // Cancel building 1224 1165 placementSupport.Reset(); 1225 inputState = INPUT_NORMAL;1166 resetPreselectedAction(); 1226 1167 return true; 1227 1168 } 1228 1169 break; … … function handleInputAfterGui(ev) 1241 1182 placementSupport.angle -= rotation_step; 1242 1183 updateBuildingPlacementPreview(); 1243 1184 break; 1185 default: 1186 handleHotkey(ev); // to switch buildings 1244 1187 } 1245 1188 break; 1246 1189 … … function handleInputAfterGui(ev) 1250 1193 return false; 1251 1194 } 1252 1195 1196 function ClickSelected(ents, is_same) 1197 { 1198 var selectedEntity = ents[0]; 1199 var now = new Date(); 1200 1201 if ((now.getTime() - doubleClickTimer < doubleClickTime) && is_same) 1202 { 1203 // Double click or triple click has occurred 1204 var showOffscreen = Engine.HotkeyIsPressed("selection.offscreen"); 1205 var matchRank = true; 1206 var templateToMatch; 1207 1208 // Check for double click or triple click 1209 if (!doubleClicked) 1210 { 1211 // If double click hasn't already occurred, this is a double click. 1212 // Select similar units regardless of rank 1213 templateToMatch = Engine.GuiInterfaceCall("GetEntityState", selectedEntity).identity.selectionGroupName; 1214 if (templateToMatch) 1215 { 1216 matchRank = false; 1217 } 1218 else 1219 { // No selection group name defined, so fall back to exact match 1220 templateToMatch = Engine.GuiInterfaceCall("GetEntityState", selectedEntity).template; 1221 } 1222 1223 doubleClicked = true; 1224 // Reset the timer so the user has an extra period 'doubleClickTimer' to do a triple-click 1225 doubleClickTimer = now.getTime(); 1226 } 1227 else 1228 { 1229 // Double click has already occurred, so this is a triple click. 1230 // Select units matching exact template name (same rank) 1231 templateToMatch = Engine.GuiInterfaceCall("GetEntityState", selectedEntity).template; 1232 } 1233 1234 // TODO: Should we handle "control all units" here as well? 1235 ents = Engine.PickSimilarFriendlyEntities(templateToMatch, showOffscreen, matchRank, false); 1236 } 1237 else 1238 { 1239 // It's single click right now but it may become double or triple click 1240 doubleClicked = false; 1241 doubleClickTimer = now.getTime(); 1242 prevClickedEntity = selectedEntity; 1243 1244 // We only want to include the first picked unit in the selection 1245 ents = [ents[0]]; 1246 } 1247 1248 // Update the list of selected units 1249 if (Engine.HotkeyIsPressed("selection.add")) 1250 { 1251 g_Selection.addList(ents); 1252 } 1253 else if (Engine.HotkeyIsPressed("selection.remove")) 1254 { 1255 g_Selection.removeList(ents); 1256 } 1257 else 1258 { 1259 g_Selection.reset(); 1260 g_Selection.addList(ents); 1261 } 1262 resetPreselectedAction(); 1263 } 1264 1253 1265 function doAction(action, ev) 1254 1266 { 1255 1267 var selection = g_Selection.toList(); … … function performCommand(entity, commandName) 1533 1545 break; 1534 1546 case "repair": 1535 1547 inputState = INPUT_PRESELECTEDACTION; 1536 preSelectedAction = ACTION_ REPAIR;1548 preSelectedAction = ACTION_BUILD; 1537 1549 break; 1538 1550 case "unload-all": 1539 1551 unloadAll(entity); … … function performFormation(entity, formationName) 1577 1589 } 1578 1590 } 1579 1591 1592 function handleHotkey(ev) 1593 { 1594 if (ev.hotkey && ev.hotkey.indexOf("selection.group.") == 0) 1595 { 1596 var sptr = ev.hotkey.split("."); 1597 var now = new Date(); 1598 if ((inputState == INPUT_NORMAL) && (ev.hotkey == prevHotkey) && 1599 ev.hotkey.indexOf("selection.group.select.") == 0 && 1600 (now.getTime() - doublePressTimer < doublePressTime)) { 1601 performGroup("snap", sptr[3]); 1602 } 1603 else 1604 { 1605 performGroup(sptr[2], sptr[3]); 1606 doublePressTimer = now.getTime(); 1607 prevHotkey = ev.hotkey; 1608 } 1609 } 1610 } 1611 1580 1612 // Performs the specified group 1581 function performGroup(action, groupId)1613 function performGroup(action, x) 1582 1614 { 1583 1615 switch (action) 1584 1616 { … … function performGroup(action, groupId) 1587 1619 case "add": 1588 1620 var toSelect = []; 1589 1621 g_Groups.update(); 1590 for (var ent in g_Groups.groups[ groupId].ents)1622 for (var ent in g_Groups.groups[x].ents) 1591 1623 toSelect.push(+ent); 1592 1624 1593 1625 if (action != "add") … … function performGroup(action, groupId) 1597 1629 1598 1630 if (action == "snap" && toSelect.length) 1599 1631 Engine.CameraFollow(toSelect[0]); 1600 break;1632 return; 1601 1633 case "save": 1602 1634 var selection = g_Selection.toList(); 1603 g_Groups.groups[ groupId].reset();1604 g_Groups.addEntities( groupId, selection);1635 g_Groups.groups[x].reset(); 1636 g_Groups.addEntities(x, selection); 1605 1637 updateGroups(); 1638 return; 1639 case "action": 1640 var selection = g_Selection.toList(); 1641 var player = Engine.GetPlayerID(); 1642 if (inputState != INPUT_ACTION_STATE) 1643 preSelectedAction = getDefaultActionForSelection(player, selection); 1606 1644 break; 1645 case "reset": 1646 resetPreselectedAction(); 1647 return; 1648 case "garrison": 1649 preSelectedAction = ACTION_GARRISON; 1650 inputState = INPUT_PRESELECTEDACTION; 1651 return; 1652 case "ungarrison": 1653 preSelectedAction = ACTION_UNGARRISON; 1654 inputState = INPUT_ACTION_STATE; 1655 return; 1656 case "stance": 1657 preSelectedAction = ACTION_STANCE; 1658 inputState = INPUT_ACTION_STATE; 1659 return; 1660 case "formation": 1661 preSelectedAction = ACTION_FORMATION; 1662 inputState = INPUT_ACTION_STATE; 1663 return; 1664 } 1665 if (inputState == INPUT_ACTION_STATE) 1666 inputState = INPUT_NORMAL; 1667 if (preSelectedAction == ACTION_NONE) 1668 return; 1669 1670 var lst = selectAction(player, selection); 1671 if (!lst) // shouldn't happen 1672 return; 1673 1674 if (preSelectedAction & ACTION_GARRISON) 1675 { 1676 if (++x > lst.length) 1677 x = lst.length; 1678 } else if (preSelectedAction != ACTION_UNGARRISON) { 1679 if (x >= lst.length) 1680 return; 1681 lst = lst[x]; 1607 1682 } 1683 1684 switch (preSelectedAction) 1685 { 1686 case ACTION_BUILD: 1687 var tmpl = GetTemplateData(lst); 1688 if (!tmpl.requiredTechnology || Engine.GuiInterfaceCall("IsTechnologyResearched", tmpl.requiredTechnology)) { 1689 // N.B. sets inputState = INPUT_BUILDING_PLACEMENT: 1690 startBuildingPlacement(lst); 1691 placementSupport.position = Engine.GetTerrainAtScreenPoint(mouseX, mouseY); 1692 initBuildingPlacementView(); 1693 } 1694 break; 1695 case ACTION_TRAIN: 1696 var tmpl = GetTemplateData(lst); 1697 if (!tmpl.requiredTechnology || Engine.GuiInterfaceCall("IsTechnologyResearched", tmpl.requiredTechnology)) { 1698 var ents = g_Selection.toList(); 1699 addTrainingToQueue(ents, lst); 1700 } 1701 break; 1702 case ACTION_GARRISON: // we garison x+1 count 1703 g_Selection.reset(); 1704 lst.splice(x, lst.length - x) 1705 g_Selection.addList(lst); 1706 inputState = INPUT_PRESELECTEDACTION; 1707 break; 1708 case ACTION_UNGARRISON: 1709 if (lst.length > 1 || x == 0) { 1710 if (x >= lst.length) 1711 x = lst.length - 1; 1712 if (lst.length != 1 && x == 0) { 1713 // unload all from all buildings 1714 for each (var gh in lst) 1715 unloadAll(gh); 1716 } else { 1717 if (lst.length != 1) 1718 x--; 1719 unloadAll(lst[x]); 1720 } 1721 g_Selection.reset(); 1722 } else { 1723 lst = lst[0]; 1724 var state = GetEntityState(lst); 1725 var gents = state.garrisonHolder.entities; 1726 if (x > gents.length) 1727 x = gents.length; 1728 while (x--) 1729 Engine.PostNetworkCommand({"type": "unload", "entities": [gents[x]], "garrisonHolder": lst}); 1730 // we could assign a key to follow them here 1731 } 1732 break; 1733 case ACTION_FORMATION: 1734 ents = g_Selection.toList(); 1735 var formationOk = Engine.GuiInterfaceCall("CanMoveEntsIntoFormation", { 1736 "ents": g_Selection.toList(), 1737 "formationName": lst 1738 }); 1739 if (formationOk) 1740 performFormation(ents, lst); 1741 break 1742 case ACTION_STANCE: 1743 ents = g_Selection.toList(); 1744 performStance(ents, lst); 1745 break; 1746 case ACTION_BARTER: //TODO 1747 break; 1748 case ACTION_TRADER: //TODO 1749 break; 1750 } 1751 } 1752 1753 // This returns a list of actions. Caller still has to check Technology availability 1754 function selectAction(player, selection) 1755 { 1756 if (preSelectedAction == ACTION_FORMATION) 1757 return Engine.GuiInterfaceCall("GetAvailableFormations"); 1758 else if (preSelectedAction == ACTION_STANCE) 1759 return ["violent", "aggressive", "passive", "defensive", "standground"]; 1760 1761 var ret = []; 1762 for each (var ent in selection) 1763 { 1764 var state = GetEntityState(ent); 1765 if (!state || (state.player != player && !g_DevSettings.controlAll)) 1766 continue; 1767 1768 switch (preSelectedAction) 1769 { 1770 case ACTION_GARRISON: 1771 if (state.buildEntities || (hasClass(state, "Unit") && !hasClass(state, "Animal") && !state.garrisonHolder)) { 1772 inputState = INPUT_PRESELECTEDACTION; 1773 ret.push(ent); 1774 } 1775 break; 1776 case ACTION_BUILD: 1777 if (state.buildEntities && state.buildEntities.length) { 1778 if (inputState != INPUT_BUILDING_PLACEMENT) 1779 inputState = INPUT_PRESELECTEDACTION; 1780 return state.buildEntities; 1781 } 1782 break; 1783 case ACTION_TRAIN: 1784 if (state.production && state.production.entities.length) 1785 return state.production.entities; 1786 break; 1787 case ACTION_UNGARRISON: 1788 if (state.garrisonHolder && state.garrisonHolder.entities && state.garrisonHolder.entities.length) 1789 ret.push(ent); 1790 break; 1791 case ACTION_BARTER: 1792 if (state.barterMarket) 1793 ret.push(ent); 1794 break; 1795 case ACTION_TRADER: 1796 if (state.trader) 1797 ret.push([ent, state]); 1798 break; 1799 } 1800 } 1801 return ret; 1802 } 1803 1804 function getDefaultActionForSelection(player, selection) 1805 { 1806 var action; 1807 var count = 0; 1808 for each (var ent in selection) 1809 { 1810 var state = GetEntityState(ent); 1811 if (!state || (state.player != player && !g_DevSettings.controlAll)) 1812 continue; 1813 1814 if (state.buildEntities && state.buildEntities.length) 1815 return ACTION_BUILD; // by default 1816 1817 if (state.production && state.production.entities.length) 1818 action |= ACTION_TRAIN; 1819 else if (!hasClass(state, "Unit") || hasClass(state, "Animal") || 1820 !state.garrisonHolder) { 1821 if (++count > 1) //only works with at least two units 1822 action |= ACTION_FORMATION; 1823 } else if (state.barterMarket) 1824 action |= ACTION_BARTER; 1825 else if (state.trader) 1826 action |= ACTION_TRADER; 1827 } 1828 if (action & ACTION_TRAIN) 1829 return ACTION_TRAIN; 1830 else if (action & ACTION_FORMATION) 1831 return ACTION_FORMATION; 1832 else if (action & ACTION_BARTER) { 1833 setupUnitBarterPanel(state); 1834 return ACTION_BARTER; 1835 } else if (action & ACTION_TRADER) { 1836 setupUnitTradingPanel(state, selection); 1837 return ACTION_TRADER; 1838 } 1839 return 0; //shouldn't happen 1608 1840 } 1609 1841 1610 1842 // Performs the specified stance … … function setCameraFollow(entity) 1639 1871 Engine.CameraFollow(0); 1640 1872 } 1641 1873 1642 var lastIdleUnit = 0; 1643 var currIdleClass = 0; 1874 var lastEntity = 0; 1875 var currEntClass = 0; 1876 1877 function resetEntitySearch() 1878 { 1879 lastEntity = 0; 1880 currEntClass = 0; 1881 } 1644 1882 1645 function resetIdleUnit()1883 function findAllVisibleEntities(classes, mode) 1646 1884 { 1647 lastIdleUnit = 0; 1648 currIdleClass = 0; 1885 var player = Engine.GetPlayerID(); 1886 var plEnts = Engine.PickFriendlyEntitiesOnScreen(player); 1887 // Or we could do somthing alike the below, but this is resolution dependent 1888 //var plEnts = Engine.PickFriendlyEntitiesInRect(250, 250, 1400, 750, player); 1889 if (!plEnts.length) 1890 return; 1891 var visibleEnts = []; 1892 for each (cls in classes) 1893 { 1894 var data = { 1895 entClass: cls, 1896 searchMode: mode, 1897 playerEnts: plEnts, 1898 }; 1899 var entities = Engine.GuiInterfaceCall("SubsetMatchedEnts", data); 1900 if (entities.length) 1901 visibleEnts = visibleEnts.concat(entities); 1902 } 1903 1904 if (visibleEnts.length) { 1905 if (!getDefaultActionForSelection(player, visibleEnts).length) 1906 resetPreselectedAction(); 1907 g_Selection.reset(); 1908 g_Selection.addList(visibleEnts); 1909 Engine.CameraFollow(visibleEnts[0]); 1910 } 1649 1911 } 1650 1912 1651 function findIdleUnit(classes) 1913 // mode 0 is to search for idle, 1 to search for any 1914 function findEntity(classes, mode) 1652 1915 { 1916 var queued = Engine.HotkeyIsPressed("session.queue"); 1917 if (queued) { 1918 findAllVisibleEntities(classes, mode) 1919 return; 1920 } 1921 var player = Engine.GetPlayerID(); 1922 1653 1923 // Cycle through idling classes before giving up 1654 1924 for (var i = 0; i <= classes.length; ++i) 1655 1925 { 1656 var data = { prevUnit: lastIdleUnit, idleClass: classes[currIdleClass] }; 1657 var newIdleUnit = Engine.GuiInterfaceCall("FindIdleUnit", data); 1658 1659 // Check if we have new valid entity 1660 if (newIdleUnit && newIdleUnit != lastIdleUnit) 1926 var data = { prevEntity: lastEntity, entClass: classes[currEntClass], searchMode: mode}; 1927 var newEntity = Engine.GuiInterfaceCall("FindEntity", data); 1928 if (newEntity && newEntity != lastEntity) 1661 1929 { 1662 lastIdleUnit = newIdleUnit; 1663 g_Selection.reset() 1664 g_Selection.addList([lastIdleUnit]); 1665 Engine.CameraFollow(lastIdleUnit); 1666 1930 if (!selectAction(player, [newEntity]).length) 1931 resetPreselectedAction(); 1932 else if (preSelectedAction == ACTION_BUILD) 1933 updateBuildingPlacementPreview(); 1934 lastEntity = newEntity; 1935 ClickSelected([newEntity], 1); 1667 1936 return; 1668 1937 } 1669 1670 lastIdleUnit = 0; 1671 currIdleClass = (currIdleClass + 1) % classes.length; 1938 lastEntity = 0; 1939 currEntClass = (currEntClass + 1) % classes.length; 1672 1940 } 1673 1674 1941 // TODO: display a message or play a sound to indicate no more idle units, or something 1675 1942 // Reset for next cycle 1676 reset IdleUnit();1943 resetEntitySearch(); 1677 1944 } 1678 1945 1679 1946 function unload(garrisonHolder, entities) … … function unload(garrisonHolder, entities) 1686 1953 1687 1954 function unloadAll(garrisonHolder) 1688 1955 { 1956 var state = GetEntityState(garrisonHolder); 1957 var gents = state.garrisonHolder.entities; 1958 followQueue = followQueue.concat(gents); 1689 1959 Engine.PostNetworkCommand({"type": "unload-all", "garrisonHolder": garrisonHolder}); 1690 1960 } -
binaries/data/mods/public/gui/session/session.xml
diff --git a/binaries/data/mods/public/gui/session/session.xml b/binaries/data/mods/public/gui/session/session.xml index 3ff530a..a55a7bd 100644
a b 85 85 </object> 86 86 87 87 <!-- Find idle warrior - TODO: Potentially move this to own UI button? --> 88 <object hotkey="selection.idlewarrior"> 89 <action on="Press">findIdleUnit(["Hero", "Champion", "CitizenSoldier", "Siege", "Warship"]);</action> 90 </object> 88 <object hotkey="selection.idlewarrior"> 89 <action on="Press">findEntity(["Hero", "Champion", "CitizenSoldier", "Siege", "Warship"], 1);</action> 90 </object> 91 92 <!-- Select civilcenter --> 93 <object hotkey="selection.civilcenter"> 94 <action on="Press">findEntity(["CivCentre"], 0);</action> 95 </object> 96 <!-- Select market --> 97 <object hotkey="selection.market"> 98 <action on="Press">findEntity(["BarterMarket", "Market", "NavalMarket"], 0);</action> 99 </object> 100 <!-- Select dropsitefood --> 101 <object hotkey="selection.dropsitefood"> 102 <action on="Press">findEntity(["CivCentre", "DropsiteFood"], 0);</action> 103 </object> 104 <!-- Select dropsitewood --> 105 <object hotkey="selection.dropsiteres"> 106 <action on="Press">findEntity(["CivCentre", "DropsiteWood", "DropsiteStone", "DropsiteMetal"], 0);</action> 107 </object> 108 <!-- Select structure --> 109 <object hotkey="selection.structure"> 110 <action on="Press">findEntity(["Structure"], 0);</action> 111 </object> 91 112 92 113 <!-- ================================ ================================ --> 93 114 <!-- Developer / Debug items --> … … 527 548 > 528 549 <!-- TODO: should highlight the button if there's non-zero idle workers --> 529 550 <object size="0 0 100% 100%" type="image" sprite="idleWorker" ghost="true" /> 530 <action on="Press">find IdleUnit(["Female", "Trade", "FishingBoat", "CitizenSoldier", "Healer"]);</action>551 <action on="Press">findEntity(["Female", "Trade", "FishingBoat", "CitizenSoldier", "Healer"], 1);</action> 531 552 </object> 532 553 </object> 533 554 </object> … … 586 607 </repeat> 587 608 </object> 588 609 </object> 589 590 610 <!-- Stance Selection --> 591 611 <object name="unitStancePanel" 592 612 style="TranslucentPanel" … … 756 776 <object name="unitCommandPanel" 757 777 size="0 100%-36 100% 100%-4" 758 778 type="image" 759 z=" 30"779 z="50" 760 780 > 761 781 <object size="0 0 100% 100%"> 762 782 <repeat count="6"> -
binaries/data/mods/public/simulation/components/GuiInterface.js
diff --git a/binaries/data/mods/public/simulation/components/GuiInterface.js b/binaries/data/mods/public/simulation/components/GuiInterface.js index 4ce8c71..6fd71d9 100644
a b GuiInterface.prototype.PlaySound = function(player, data) 1426 1426 PlaySound(data.name, data.entity); 1427 1427 }; 1428 1428 1429 function isIdleUnit(ent, idleClass)1429 GuiInterface.prototype.MatchEnt = function(ent, data) 1430 1430 { 1431 var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI); 1432 var cmpIdentity = Engine.QueryInterface(ent, IID_Identity); 1433 1434 // TODO: Do something with garrisoned idle units 1435 return (cmpUnitAI && cmpIdentity && cmpUnitAI.IsIdle() && !cmpUnitAI.IsGarrisoned() && idleClass && cmpIdentity.HasClass(idleClass)); 1431 var ret; 1432 var cmpId = Engine.QueryInterface(ent, IID_Identity); 1433 if (cmpId && cmpId.HasClass(data.entClass)) { 1434 if (data.searchMode == 0) { 1435 ret = ent; 1436 } else if (data.searchMode == 1) { // Search idle villager/soldier 1437 var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI); 1438 if (cmpUnitAI && cmpUnitAI.IsIdle() && !cmpUnitAI.IsGarrisoned()) 1439 ret = ent; 1440 } 1441 } 1442 return ret; 1443 } 1444 1445 GuiInterface.prototype.SubsetMatchedEnts = function(player, data) 1446 { 1447 var ret = []; 1448 for each (var ent in data.playerEnts) 1449 { 1450 var match = this.MatchEnt(ent, data); 1451 if (match) 1452 ret.push(match); 1453 } 1454 return ret; 1436 1455 } 1437 1456 1438 GuiInterface.prototype.Find IdleUnit= function(player, data)1457 GuiInterface.prototype.FindEntity = function(player, data) 1439 1458 { 1440 1459 var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 1441 1460 var playerEntities = rangeMan.GetEntitiesByPlayer(player); … … GuiInterface.prototype.FindIdleUnit = function(player, data) 1444 1463 // so that we cycle around in a predictable order 1445 1464 for each (var ent in playerEntities) 1446 1465 { 1447 if (ent > data.prevUnit && isIdleUnit(ent, data.idleClass)) 1448 return ent; 1466 if (ent > data.prevEntity) 1467 { 1468 var match = this.MatchEnt(ent, data); 1469 if (match) 1470 return match; 1471 } 1449 1472 } 1450 1473 1451 // No idleentities left in the class1474 // No entities left in the class 1452 1475 return 0; 1453 1476 }; 1454 1477 … … var exposedFunctions = { 1571 1594 "SetWallPlacementPreview": 1, 1572 1595 "GetFoundationSnapData": 1, 1573 1596 "PlaySound": 1, 1574 "FindIdleUnit": 1, 1597 "SubsetMatchedEnts": 1, 1598 "FindEntity": 1, 1575 1599 "GetTradingDetails": 1, 1576 1600 "CanAttack": 1, 1577 1601 -
libraries/spidermonkey/include-win32/js/jstracer.h
diff --git a/libraries/spidermonkey/include-win32/js/jstracer.h b/libraries/spidermonkey/include-win32/js/jstracer.h index 76921cc..bd992c2 100644
a b public: 106 106 107 107 void add(T a) { 108 108 ensure(_len + 1); 109 JS_ASSERT(_len < =_max);109 JS_ASSERT(_len < _max); 110 110 _data[_len++] = a; 111 111 } 112 112 113 113 void add(T* chunk, unsigned size) { 114 114 ensure(_len + size); 115 JS_ASSERT(_len < =_max);115 JS_ASSERT(_len < _max); 116 116 memcpy(&_data[_len], chunk, size * sizeof(T)); 117 117 _len += size; 118 118 } -
source/graphics/GameView.cpp
diff --git a/source/graphics/GameView.cpp b/source/graphics/GameView.cpp index 0062b44..c69df27 100644
a b void CGameView::Update(const float deltaRealTime) 728 728 moveForward += m->ViewScrollSpeed * deltaRealTime; 729 729 } 730 730 731 if (HotkeyIsPressed("camera.right")) 732 moveRightward += m->ViewScrollSpeed * deltaRealTime; 733 if (HotkeyIsPressed("camera.left")) 734 moveRightward -= m->ViewScrollSpeed * deltaRealTime; 735 if (HotkeyIsPressed("camera.up")) 736 moveForward += m->ViewScrollSpeed * deltaRealTime; 737 if (HotkeyIsPressed("camera.down")) 738 moveForward -= m->ViewScrollSpeed * deltaRealTime; 731 if (HotkeyIsPressed("camera.right")) { 732 if (HotkeyIsPressed("session.queue") && 0 /*building placement*/) 733 /* move building placement right*/; 734 else 735 moveRightward += m->ViewScrollSpeed * deltaRealTime; 736 } 737 if (HotkeyIsPressed("camera.left")) { 738 if (HotkeyIsPressed("session.queue") && 0 /*building placement*/) 739 /* move building placement left*/; 740 else 741 moveRightward -= m->ViewScrollSpeed * deltaRealTime; 742 } 743 if (HotkeyIsPressed("camera.up")) { 744 if (HotkeyIsPressed("session.queue") && 0 /*building placement*/) 745 /* move building placement up*/; 746 else 747 moveForward += m->ViewScrollSpeed * deltaRealTime; 748 } 749 if (HotkeyIsPressed("camera.down")) { 750 if (HotkeyIsPressed("session.queue") && 0 /*building placement*/) 751 /* move building placement down*/; 752 else 753 moveForward -= m->ViewScrollSpeed * deltaRealTime; 754 } 739 755 740 756 if (g_Joystick.IsEnabled()) 741 757 { -
source/gui/MiniMap.cpp
diff --git a/source/gui/MiniMap.cpp b/source/gui/MiniMap.cpp index f05da71..237b502 100644
a b 44 44 45 45 bool g_GameRestarted = false; 46 46 47 static unsigned int ScaleColor(unsigned int color, float x)47 static unsigned int ScaleColor(unsigned int color, unsigned int val, unsigned int div) 48 48 { 49 unsigned int r = unsigned(float(color & 0xff) * x);50 unsigned int g = unsigned(float((color>>8) & 0xff) * x);51 unsigned int b = unsigned(float((color>>16) & 0xff) * x);49 unsigned int r = (color & 0xff) * val / div; 50 unsigned int g = ((color>>8) & 0xff) * val / div; 51 unsigned int b = ((color>>16) & 0xff) * val / div; 52 52 return (0xff000000 | r | g<<8 | b<<16); 53 53 } 54 54 … … void CMiniMap::RebuildTerrainTexture() 483 483 u32 y = 0; 484 484 u32 w = m_MapSize - 1; 485 485 u32 h = m_MapSize - 1; 486 float waterHeight = g_Renderer.GetWaterManager()->m_WaterHeight ;486 float waterHeight = g_Renderer.GetWaterManager()->m_WaterHeight * 4.0f; 487 487 488 488 m_TerrainDirty = false; 489 489 … … void CMiniMap::RebuildTerrainTexture() 492 492 u32 *dataPtr = m_TerrainData + ((y + j) * (m_MapSize - 1)) + x; 493 493 for(u32 i = 0; i < w; i++) 494 494 { 495 float avgHeight = (m_Terrain->GetVertexGroundLevel((int)i, (int)j)495 float avgHeight = m_Terrain->GetVertexGroundLevel((int)i, (int)j) 496 496 + m_Terrain->GetVertexGroundLevel((int)i+1, (int)j) 497 497 + m_Terrain->GetVertexGroundLevel((int)i, (int)j+1) 498 + m_Terrain->GetVertexGroundLevel((int)i+1, (int)j+1) 499 ) / 4.0f; 498 + m_Terrain->GetVertexGroundLevel((int)i+1, (int)j+1); 500 499 501 500 if(avgHeight < waterHeight) 502 501 { … … void CMiniMap::RebuildTerrainTexture() 525 524 } 526 525 } 527 526 528 *dataPtr++ = ScaleColor(color, float(val) / 255.0f);527 *dataPtr++ = ScaleColor(color, val, 255); 529 528 } 530 529 } 531 530 }