1
1
forked from 0ad/0ad

Fix unit-only Attack move.

attackmoveUnit is more specific than attackMove, so since d0a42f2f00
won't fire at the same time. However the GUI code expected that,
breaking it.

Instead, properly check for either attackmove or attackmoveUnit.

Also fix an issue with d0a42f2f00 where hotkeys would be release if
switching to a more specific combination of the same hotkey.

Reported by: snelius
Fixes #5944

Differential Revision: https://code.wildfiregames.com/D3436
This was SVN commit r24752.
This commit is contained in:
wraitii 2021-01-21 15:58:33 +00:00
parent b28e6fda42
commit 8c429b9a68
5 changed files with 49 additions and 7 deletions

View File

@ -297,7 +297,7 @@ unload = "U" ; Unload garrisoned units when a building/mechanica
move = "" ; Modifier to move to a point instead of another action (e.g. gather)
attack = Ctrl ; Modifier to attack instead of another action (e.g. capture)
attackmove = Ctrl ; Modifier to attackmove when clicking on a point
attackmoveUnit = "Ctrl+Q" ; Modifier to attackmove targeting only units when clicking on a point (should contain the attackmove keys)
attackmoveUnit = "Ctrl+Q" ; Modifier to attackmove targeting only units when clicking on a point
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

View File

@ -268,6 +268,12 @@ function ownsEntity(ent)
return entState && entState.player == g_ViewedPlayer;
}
function isAttackMovePressed()
{
return Engine.HotkeyIsPressed("session.attackmove") ||
Engine.HotkeyIsPressed("session.attackmoveUnit");
}
function isSnapToEdgesEnabled()
{
let config = Engine.ConfigDB_GetValue("user", "gui.session.snaptoedges");
@ -1194,7 +1200,7 @@ function positionUnitsFreehandSelectionMouseUp(ev)
entityDistribution.reverse();
Engine.PostNetworkCommand({
"type": Engine.HotkeyIsPressed("session.attackmove") ? "attack-walk-custom" : "walk-custom",
"type": isAttackMovePressed() ? "attack-walk-custom" : "walk-custom",
"entities": selection,
"targetPositions": entityDistribution.map(pos => pos.toFixed(2)),
"targetClasses": Engine.HotkeyIsPressed("session.attackmoveUnit") ? { "attack": ["Unit"] } : { "attack": ["Unit", "Structure"] },

View File

@ -124,7 +124,7 @@ var g_UnitActions =
},
"hotkeyActionCheck": function(target, selection)
{
return Engine.HotkeyIsPressed("session.attackmove") &&
return isAttackMovePressed() &&
this.actionCheck(target, selection);
},
"actionCheck": function(target, selection)
@ -892,7 +892,7 @@ var g_UnitActions =
let data = { "command": "walk" };
let cursor = "";
if (Engine.HotkeyIsPressed("session.attackmove"))
if (isAttackMovePressed())
{
let targetClasses;
if (Engine.HotkeyIsPressed("session.attackmoveUnit"))

View File

@ -310,9 +310,12 @@ InReaction HotkeyInputHandler(const SDL_Event_* ev)
if ((ev->ev.type == SDL_KEYDOWN) || (ev->ev.type == SDL_MOUSEBUTTONDOWN))
for (const SHotkeyMapping* hotkey : pressedHotkeys)
{
if (hotkey->requires.size() + 1 < closestMapMatch)
if (std::find_if(newPressedHotkeys.begin(), newPressedHotkeys.end(),
[&hotkey](const SHotkeyMapping* v){ return v->name == hotkey->name; }) != newPressedHotkeys.end())
continue;
else if (hotkey->requires.size() + 1 < closestMapMatch)
releasedHotkeys.push_back(hotkey->name.c_str());
else if (std::find(newPressedHotkeys.begin(), newPressedHotkeys.end(), hotkey) == newPressedHotkeys.end())
else
{
// We need to check that all 'keys' are still pressed (because of mouse buttons).
if (!isPressed(hotkey->primary))

View File

@ -55,6 +55,8 @@ public:
TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache"));
configDB = new CConfigDB;
g_scancodes = {};
}
void tearDown()
@ -70,7 +72,7 @@ public:
configDB->SetValueString(CFG_SYSTEM, "hotkey.A", "A");
configDB->SetValueString(CFG_SYSTEM, "hotkey.AB", "A+B");
configDB->SetValueString(CFG_SYSTEM, "hotkey.ABC", "A+B+C");
configDB->SetValueString(CFG_SYSTEM, "hotkey.D", "D");
configDB->SetValueList(CFG_SYSTEM, "hotkey.D", { "D", "D+E" });
configDB->WriteFile(CFG_SYSTEM, "config/conf.cfg");
configDB->Reload(CFG_SYSTEM);
@ -115,6 +117,7 @@ public:
fakeInput("B", true);
fakeInput("A", true);
// Activating the more precise hotkey AB untriggers "A"
TS_ASSERT_EQUALS(HotkeyIsPressed("A"), false);
TS_ASSERT_EQUALS(HotkeyIsPressed("AB"), true);
TS_ASSERT_EQUALS(HotkeyIsPressed("ABC"), false);
@ -135,6 +138,36 @@ public:
TS_ASSERT_EQUALS(HotkeyIsPressed("ABC"), false);
TS_ASSERT_EQUALS(HotkeyIsPressed("D"), false);
fakeInput("A", false);
fakeInput("D", true);
TS_ASSERT_EQUALS(HotkeyIsPressed("A"), false);
TS_ASSERT_EQUALS(HotkeyIsPressed("AB"), false);
TS_ASSERT_EQUALS(HotkeyIsPressed("ABC"), false);
TS_ASSERT_EQUALS(HotkeyIsPressed("D"), true);
fakeInput("E", true);
// Changing from one hotkey to another more specific combination of the same hotkey keeps it active
TS_ASSERT_EQUALS(HotkeyIsPressed("A"), false);
TS_ASSERT_EQUALS(HotkeyIsPressed("AB"), false);
TS_ASSERT_EQUALS(HotkeyIsPressed("ABC"), false);
TS_ASSERT_EQUALS(HotkeyIsPressed("D"), true);
fakeInput("E", false);
// Likewise going the other way.
TS_ASSERT_EQUALS(HotkeyIsPressed("D"), true);
}
void test_quirk()
{
configDB->SetValueString(CFG_SYSTEM, "hotkey.A", "A");
configDB->SetValueString(CFG_SYSTEM, "hotkey.AB", "A+B");
configDB->SetValueString(CFG_SYSTEM, "hotkey.ABC", "A+B+C");
configDB->SetValueList(CFG_SYSTEM, "hotkey.D", { "D", "D+E" });
configDB->WriteFile(CFG_SYSTEM, "config/conf.cfg");
configDB->Reload(CFG_SYSTEM);
UnloadHotkeys();
LoadHotkeys(*configDB);
/**
* Quirk of the implementation: hotkeys are allowed to fire with too many keys.
* Further, hotkeys of the same specificity (i.e. same # of required keys)