diff --git a/AI/Skirmish/BARb b/AI/Skirmish/BARb index e6b33037df..f4a6ca3ae0 160000 --- a/AI/Skirmish/BARb +++ b/AI/Skirmish/BARb @@ -1 +1 @@ -Subproject commit e6b33037dfbe81f2b0eb289f884ed90a1718eec0 +Subproject commit f4a6ca3ae096631894e194cfa9b4e8e53f4fb78c diff --git a/rts/Game/UI/KeyBindings.cpp b/rts/Game/UI/KeyBindings.cpp index 32c55dcfb6..b566ebb425 100644 --- a/rts/Game/UI/KeyBindings.cpp +++ b/rts/Game/UI/KeyBindings.cpp @@ -674,6 +674,11 @@ bool CKeyBindings::UnBind(const std::string& keystr, const std::string& command) if (debugEnabled) LOG("[CKeyBindings::%s] keystr=%s command=%s", __func__, keystr.c_str(), command.c_str()); + /* Bind does the same to the stored chain, so mirror it + * here or a stateful bind can never be named exactly. */ + if (statefulCommands.find(command) != statefulCommands.end()) + kc.back().SetAnyBit(); + const CKeySet& ks = kc.back(); KeyMap& bindings = ks.IsKeyCode() ? codeBindings : scanBindings; const auto it = bindings.find(ks); @@ -681,7 +686,7 @@ bool CKeyBindings::UnBind(const std::string& keystr, const std::string& command) if (it != bindings.end()) { ActionList& al = it->second; - if (RemoveCommandFromList(al, command)) + if (RemoveCommandFromList(al, kc, command)) buildHotkeyMap = true; if (al.empty()) @@ -816,6 +821,23 @@ bool CKeyBindings::RemoveCommandFromList(ActionList& al, const std::string& comm } +/* Chains are stored under their last keyset, so + * a bucket holds every chain ending in that key. */ +bool CKeyBindings::RemoveCommandFromList(ActionList& al, const CKeyChain& kc, const std::string& command) +{ + RECOIL_DETAILED_TRACY_ZONE; + + const auto removedCount = std::erase_if(al, [&kc, &command] (const auto& x) { + /* exact compare, not .fit(): naming one modifier + * combination must not remove a different one. + * operator== also rejects differing chain lengths. */ + return x.command == command && x.keyChain == kc; + }); + + return removedCount > 0; +} + + void CKeyBindings::ConfigNotify(const std::string& key, const std::string& value) { RECOIL_DETAILED_TRACY_ZONE; diff --git a/rts/Game/UI/KeyBindings.h b/rts/Game/UI/KeyBindings.h index 9caf37e610..94f163af6e 100644 --- a/rts/Game/UI/KeyBindings.h +++ b/rts/Game/UI/KeyBindings.h @@ -79,6 +79,7 @@ class CKeyBindings : public CommandReceiver bool AddKeySymbol(const std::string& keysym, const std::string& code); static bool RemoveCommandFromList(ActionList& al, const std::string& command); + static bool RemoveCommandFromList(ActionList& al, const CKeyChain& kc, const std::string& command); bool FileSave(FILE* file) const; diff --git a/rts/Sim/MoveTypes/MoveDefHandler.cpp b/rts/Sim/MoveTypes/MoveDefHandler.cpp index eb59743c08..0b350377af 100644 --- a/rts/Sim/MoveTypes/MoveDefHandler.cpp +++ b/rts/Sim/MoveTypes/MoveDefHandler.cpp @@ -51,7 +51,7 @@ CR_REG_METADATA(MoveDef, ( CR_MEMBER(followGround), CR_MEMBER(isSubmarine), - CR_MEMBER(isSubmersible), + CR_MEMBER(hasUnderwaterCollision), CR_MEMBER(overrideUnitWaterline), @@ -343,7 +343,7 @@ MoveDef::MoveDef(const LuaTable& moveDefTable): MoveDef() { } height = std::max(1, moveDefTable.GetInt("height", defaultHeight)); - isSubmersible = (isSubmarine || (followGround && depth > height)); + hasUnderwaterCollision = (isSubmarine || (followGround && depth > height) || (waterline > 0 && maxWaterDepth > waterline)); allowDirectionalPathing = moveDefTable.GetBool("allowDirectionalPathing", allowDirectionalPathing); preferShortestPath = moveDefTable.GetBool("preferShortestPath", preferShortestPath); } diff --git a/rts/Sim/MoveTypes/MoveDefHandler.h b/rts/Sim/MoveTypes/MoveDefHandler.h index 9c8d1db560..13bacb00a8 100644 --- a/rts/Sim/MoveTypes/MoveDefHandler.h +++ b/rts/Sim/MoveTypes/MoveDefHandler.h @@ -106,7 +106,7 @@ struct MoveDef { unsigned int CalcCheckSum() const; bool IsComplexSubmersible() const { - return isSubmersible && overrideUnitWaterline; + return hasUnderwaterCollision && overrideUnitWaterline; }; static float GetDefaultMinWaterDepth() { return -1e6f; } @@ -183,8 +183,8 @@ struct MoveDef { /// are we supposed to be a purely sub-surface ship? bool isSubmarine = false; - // can this unit completely submerge in water? - bool isSubmersible = false; + // can this unit at least partially submerge in water? + bool hasUnderwaterCollision = false; /// If false, this forces the use of simple underwater collisions, which can cause some pathing issues for /// amphibious units. i.e. they are blocked by obstacles above and below the water regardless of height.