From 90d87c0b625596b3c25c11803f7ea972eb573683 Mon Sep 17 00:00:00 2001 From: pawnishoovy <54544349+pawnishoovy@users.noreply.github.com> Date: Wed, 27 Nov 2024 16:24:24 +0200 Subject: [PATCH 01/10] convert ray ignoreMOID to vector of MOIDs, broken and bad lua adapter --- Source/Lua/LuaAdapterDefinitions.h | 72 ++++++++++++++++++++++++++++++ Source/Lua/LuaAdapters.cpp | 28 ++++++++++++ Source/Lua/LuaBindingsManagers.cpp | 6 ++- Source/Managers/SceneMan.cpp | 29 ++++++++---- Source/Managers/SceneMan.h | 50 +++++++++++++++++++-- 5 files changed, 170 insertions(+), 15 deletions(-) diff --git a/Source/Lua/LuaAdapterDefinitions.h b/Source/Lua/LuaAdapterDefinitions.h index 5c0f32c5a1..8777761765 100644 --- a/Source/Lua/LuaAdapterDefinitions.h +++ b/Source/Lua/LuaAdapterDefinitions.h @@ -512,6 +512,78 @@ namespace RTE { #pragma region SceneMan Lua Adapters struct LuaAdaptersSceneMan { + /// Traces along a vector and returns MOID of the first non-ignored + /// non-NoMOID MO encountered. If a non-air terrain pixel is encountered + /// first, g_NoMOID will be returned. + /// @param start The starting position. + /// @param ray The vector to trace along. + /// @param ignoredMOIDs A vector of MOIDs to ignore. Any child MO's of this MOID will also be ignored. (default: g_NoMOID) + /// @param ignoreTeam To enable ignoring of all MOIDs associated with an object of a specific (default: Activity::NoTeam) + /// team which also has team ignoring enabled itself. + /// @param ignoreMaterial A specific material ID to ignore hits with. (default: 0) + /// @param ignoreAllTerrain Whether to ignore all terrain hits or not. (default: false) + /// @param skip For every pixel checked along the line, how many to skip between them (default: 0) + /// for optimization reasons. 0 = every pixel is checked. + /// @return The MOID of the hit non-ignored MO, or g_NoMOID if terrain or no MO was hit. + static MOID CastMORay1(SceneMan& sceneMan, const Vector& start, const Vector& ray, const luabind::object& ignoredMOIDs, int ignoreTeam = Activity::NoTeam, unsigned char ignoreMaterial = 0, bool ignoreAllTerrain = false, int skip = 0); + + /// Traces along a vector and returns MOID of the first non-ignored + /// non-NoMOID MO encountered. If a non-air terrain pixel is encountered + /// first, g_NoMOID will be returned. + /// @param start The starting position. + /// @param ray The vector to trace along. + /// @param ignoredMOID An MOID to ignore. Any child MO's of this MOID will also be ignored. (default: g_NoMOID) + /// @param ignoreTeam To enable ignoring of all MOIDs associated with an object of a specific (default: Activity::NoTeam) + /// team which also has team ignoring enabled itself. + /// @param ignoreMaterial A specific material ID to ignore hits with. (default: 0) + /// @param ignoreAllTerrain Whether to ignore all terrain hits or not. (default: false) + /// @param skip For every pixel checked along the line, how many to skip between them (default: 0) + /// for optimization reasons. 0 = every pixel is checked. + /// @return The MOID of the hit non-ignored MO, or g_NoMOID if terrain or no MO was hit. + static MOID CastMORay2(SceneMan& sceneMan, const Vector& start, const Vector& ray, MOID ignoredMOID = g_NoMOID, int ignoreTeam = Activity::NoTeam, unsigned char ignoreMaterial = 0, bool ignoreAllTerrain = false, int skip = 0); + + /// Traces along a vector and returns the length of how far the trace went + /// without hitting any non-ignored terrain material or MOID at all. + /// @param start The starting position. + /// @param ray The vector to trace along. + /// @param obstaclePos A reference to the vector screen will be filled out with the absolute + /// location of the first obstacle, or the end of the ray if none was hit. + /// @param freePos A reference to the vector screen will be filled out with the absolute + /// location of the last free position before hitting an obstacle, or the + /// end of the ray if none was hit. This is only altered if thre are any + /// free pixels encountered. + /// @param ignoreMOIDs A vector of MOIDs to ignore. Any child MO's of an MOID will also be ignored. (default: g_NoMOID) + /// @param ignoreTeam To enable ignoring of all MOIDs associated with an object of a specific (default: Activity::NoTeam) + /// team which also has team ignoring enabled itself. + /// @param ignoreMaterial A specific material ID to ignore hits with. (default: 0) + /// @param skip For every pixel checked along the line, how many to skip between them (default: 0) + /// for optimization reasons. 0 = every pixel is checked. + /// @return How far along, in pixel units, the ray the pixel of any obstacle was + /// encountered. If no pixel of the right material was found, < 0 is returned. + /// If an obstacle on the starting position was encountered, 0 is returned. + static float CastObstacleRay1(SceneMan& sceneMan, const Vector& start, const Vector& ray, Vector& obstaclePos, Vector& freePos, const luabind::object& ignoreMOIDs, int ignoreTeam = Activity::NoTeam, unsigned char ignoreMaterial = 0, int skip = 0); + + /// Traces along a vector and returns the length of how far the trace went + /// without hitting any non-ignored terrain material or MOID at all. + /// @param start The starting position. + /// @param ray The vector to trace along. + /// @param obstaclePos A reference to the vector screen will be filled out with the absolute + /// location of the first obstacle, or the end of the ray if none was hit. + /// @param freePos A reference to the vector screen will be filled out with the absolute + /// location of the last free position before hitting an obstacle, or the + /// end of the ray if none was hit. This is only altered if thre are any + /// free pixels encountered. + /// @param ignoreMOID An MOID to ignore. Any child MOs of this MOID will also be ignored. (default: g_NoMOID) + /// @param ignoreTeam To enable ignoring of all MOIDs associated with an object of a specific (default: Activity::NoTeam) + /// team which also has team ignoring enabled itself. + /// @param ignoreMaterial A specific material ID to ignore hits with. (default: 0) + /// @param skip For every pixel checked along the line, how many to skip between them (default: 0) + /// for optimization reasons. 0 = every pixel is checked. + /// @return How far along, in pixel units, the ray the pixel of any obstacle was + /// encountered. If no pixel of the right material was found, < 0 is returned. + /// If an obstacle on the starting position was encountered, 0 is returned. + static float CastObstacleRay2(SceneMan& sceneMan, const Vector& start, const Vector& ray, Vector& obstaclePos, Vector& freePos, MOID ignoreMOID = g_NoMOID, int ignoreTeam = Activity::NoTeam, unsigned char ignoreMaterial = 0, int skip = 0); + /// Takes a Box and returns a list of Boxes that describe the Box, wrapped appropriately for the current Scene. /// @param boxToWrap The Box to wrap. /// @return A list of Boxes that make up the Box to wrap, wrapped appropriately for the current Scene. diff --git a/Source/Lua/LuaAdapters.cpp b/Source/Lua/LuaAdapters.cpp index fd4d140bb3..4dc24af987 100644 --- a/Source/Lua/LuaAdapters.cpp +++ b/Source/Lua/LuaAdapters.cpp @@ -612,6 +612,34 @@ std::list* LuaAdaptersPresetMan::GetAllEntitiesOfGroup(PresetMan& prese return entityList; } +MOID LuaAdaptersSceneMan::CastMORay1(SceneMan& sceneMan, const Vector& start, const Vector& ray, const luabind::object& ignoreMOIDs, int ignoreTeam, unsigned char ignoreMaterial, bool ignoreAllTerrain, int skip) { + std::vector ptrVec = ConvertLuaTableToVectorOfType(ignoreMOIDs); + std::vector ignoreMOIDsVec; + for (auto ptr : ptrVec) { + ignoreMOIDsVec.push_back(*ptr); + } + return sceneMan.CastMORay(start, ray, ignoreMOIDsVec, ignoreTeam, ignoreMaterial, ignoreAllTerrain, skip); +} + +MOID LuaAdaptersSceneMan::CastMORay2(SceneMan& sceneMan, const Vector& start, const Vector& ray, MOID ignoreMOID, int ignoreTeam, unsigned char ignoreMaterial, bool ignoreAllTerrain, int skip) { + std::vector ignoreMOIDs = {ignoreMOID}; + return sceneMan.CastMORay(start, ray, ignoreMOIDs, ignoreTeam, ignoreMaterial, ignoreAllTerrain, skip); +} + +float LuaAdaptersSceneMan::CastObstacleRay1(SceneMan& sceneMan, const Vector& start, const Vector& ray, Vector& obstaclePos, Vector& freePos, const luabind::object& ignoreMOIDs, int ignoreTeam, unsigned char ignoreMaterial, int skip) { + std::vector ptrVec = ConvertLuaTableToVectorOfType(ignoreMOIDs); + std::vector ignoreMOIDsVec; + for (auto ptr : ptrVec) { + ignoreMOIDsVec.push_back(*ptr); + } + return sceneMan.CastObstacleRay(start, ray, obstaclePos, freePos, ignoreMOIDsVec, ignoreTeam, ignoreMaterial, skip); +} + +float LuaAdaptersSceneMan::CastObstacleRay2(SceneMan& sceneMan, const Vector& start, const Vector& ray, Vector& obstaclePos, Vector& freePos, MOID ignoreMOID, int ignoreTeam, unsigned char ignoreMaterial, int skip) { + std::vector ignoreMOIDs = {ignoreMOID}; + return sceneMan.CastObstacleRay(start, ray, obstaclePos, freePos, ignoreMOIDs, ignoreTeam, ignoreMaterial, skip); +} + const std::list* LuaAdaptersSceneMan::WrapBoxes(SceneMan& sceneMan, const Box& boxToWrap) { std::list* wrappedBoxes = new std::list(); sceneMan.WrapBox(boxToWrap, *wrappedBoxes); diff --git a/Source/Lua/LuaBindingsManagers.cpp b/Source/Lua/LuaBindingsManagers.cpp index 455f02d8da..a03fc6b6c0 100644 --- a/Source/Lua/LuaBindingsManagers.cpp +++ b/Source/Lua/LuaBindingsManagers.cpp @@ -325,9 +325,11 @@ LuaBindingRegisterFunctionDefinitionForType(ManagerLuaBindings, SceneMan) { .def("CastMaxStrengthRay", (float(SceneMan::*)(const Vector&, const Vector&, int)) & SceneMan::CastMaxStrengthRay) .def("CastStrengthRay", &SceneMan::CastStrengthRay) .def("CastWeaknessRay", &SceneMan::CastWeaknessRay) - .def("CastMORay", &SceneMan::CastMORay) + .def("CastMORay", &LuaAdaptersSceneMan::CastMORay1) + .def("CastMORay", &LuaAdaptersSceneMan::CastMORay2) .def("CastFindMORay", &SceneMan::CastFindMORay) - .def("CastObstacleRay", &SceneMan::CastObstacleRay) + .def("CastObstacleRay", &LuaAdaptersSceneMan::CastObstacleRay1) + .def("CastObstacleRay", &LuaAdaptersSceneMan::CastObstacleRay2) .def("CastTerrainPenetrationRay", &SceneMan::CastTerrainPenetrationRay) .def("GetLastRayHitPos", &SceneMan::GetLastRayHitPos) .def("FindAltitude", (float(SceneMan::*)(const Vector&, int, int)) & SceneMan::FindAltitude) diff --git a/Source/Managers/SceneMan.cpp b/Source/Managers/SceneMan.cpp index a504cbdcaa..b57dea5198 100644 --- a/Source/Managers/SceneMan.cpp +++ b/Source/Managers/SceneMan.cpp @@ -1902,7 +1902,7 @@ bool SceneMan::CastWeaknessRay(const Vector& start, const Vector& ray, float str return foundPixel; } -MOID SceneMan::CastMORay(const Vector& start, const Vector& ray, MOID ignoreMOID, int ignoreTeam, unsigned char ignoreMaterial, bool ignoreAllTerrain, int skip) { +MOID SceneMan::CastMORay(const Vector& start, const Vector& ray, const std::vector& ignoreMOIDs, int ignoreTeam, unsigned char ignoreMaterial, bool ignoreAllTerrain, int skip) { int hitCount = 0, error, dom, sub, domSteps, skipped = skip; int intPos[2], delta[2], delta2[2], increment[2]; MOID hitMOID = g_NoMOID; @@ -1965,7 +1965,17 @@ MOID SceneMan::CastMORay(const Vector& start, const Vector& ray, MOID ignoreMOID // Detect MOIDs hitMOID = GetMOIDPixel(intPos[X], intPos[Y], ignoreTeam); - if (hitMOID != g_NoMOID && hitMOID != ignoreMOID && g_MovableMan.GetRootMOID(hitMOID) != ignoreMOID) { + + // Loop through ignored MOIDs to see if the one we found is ignored + bool ignoredMOIDHit = false; + for (auto ignoredMOID : ignoreMOIDs) { + if (hitMOID == ignoredMOID || g_MovableMan.GetRootMOID(hitMOID) == ignoredMOID) { + ignoredMOIDHit = true; + break; + } + } + + if (hitMOID != g_NoMOID && !ignoredMOIDHit) { // Save last ray pos s_LastRayHitPos.SetXY(intPos[X], intPos[Y]); return hitMOID; @@ -2085,7 +2095,7 @@ bool SceneMan::CastFindMORay(const Vector& start, const Vector& ray, MOID target return false; } -float SceneMan::CastObstacleRay(const Vector& start, const Vector& ray, Vector& obstaclePos, Vector& freePos, MOID ignoreMOID, int ignoreTeam, unsigned char ignoreMaterial, int skip) { +float SceneMan::CastObstacleRay(const Vector& start, const Vector& ray, Vector& obstaclePos, Vector& freePos, const std::vector& ignoreMOIDs, int ignoreTeam, unsigned char ignoreMaterial, int skip) { int hitCount = 0, error, dom, sub, domSteps, skipped = skip; int intPos[2], delta[2], delta2[2], increment[2]; bool hitObstacle = false; @@ -2152,17 +2162,18 @@ float SceneMan::CastObstacleRay(const Vector& start, const Vector& ray, Vector& unsigned char checkMat = GetTerrMatter(intPos[X], intPos[Y]); MOID checkMOID = GetMOIDPixel(intPos[X], intPos[Y], ignoreTeam); - // Translate any found MOID into the root MOID of that hit MO - if (checkMOID != g_NoMOID) { - MovableObject* pHitMO = g_MovableMan.GetMOFromID(checkMOID); - if (pHitMO) { - checkMOID = pHitMO->GetRootID(); + // Loop through ignored MOIDs to see if the one we found is ignored + bool ignoredMOIDHit = false; + for (auto ignoredMOID : ignoreMOIDs) { + if (checkMOID == ignoredMOID || g_MovableMan.GetRootMOID(checkMOID) == ignoredMOID) { + ignoredMOIDHit = true; + break; } } // See if we found the looked-for pixel of the correct material, // Or an MO is blocking the way - if ((checkMat != g_MaterialAir && checkMat != ignoreMaterial) || (checkMOID != g_NoMOID && checkMOID != ignoreMOID)) { + if ((checkMat != g_MaterialAir && checkMat != ignoreMaterial) || (checkMOID != g_NoMOID && !ignoredMOIDHit)) { hitObstacle = true; obstaclePos.SetXY(intPos[X], intPos[Y]); // Save last ray pos diff --git a/Source/Managers/SceneMan.h b/Source/Managers/SceneMan.h index 9d739f73ef..f804b54b36 100644 --- a/Source/Managers/SceneMan.h +++ b/Source/Managers/SceneMan.h @@ -662,7 +662,7 @@ namespace RTE { /// first, g_NoMOID will be returned. /// @param start The starting position. /// @param ray The vector to trace along. - /// @param ignoreMOID An MOID to ignore. Any child MO's of this MOID will also be ignored. (default: g_NoMOID) + /// @param ignoreMOIDs A vector of MOIDs to ignore. Any child MOs of an MOID will also be ignored. (default: g_NoMOID) /// @param ignoreTeam To enable ignoring of all MOIDs associated with an object of a specific (default: Activity::NoTeam) /// team which also has team ignoring enabled itself. /// @param ignoreMaterial A specific material ID to ignore hits with. (default: 0) @@ -670,8 +670,26 @@ namespace RTE { /// @param skip For every pixel checked along the line, how many to skip between them (default: 0) /// for optimization reasons. 0 = every pixel is checked. /// @return The MOID of the hit non-ignored MO, or g_NoMOID if terrain or no MO was hit. - MOID CastMORay(const Vector& start, const Vector& ray, MOID ignoreMOID = g_NoMOID, int ignoreTeam = Activity::NoTeam, unsigned char ignoreMaterial = 0, bool ignoreAllTerrain = false, int skip = 0); + MOID CastMORay(const Vector& start, const Vector& ray, const std::vector& ignoreMOIDs = {g_NoMOID}, int ignoreTeam = Activity::NoTeam, unsigned char ignoreMaterial = 0, bool ignoreAllTerrain = false, int skip = 0); + /// Traces along a vector and returns MOID of the first non-ignored + /// non-NoMOID MO encountered. If a non-air terrain pixel is encountered + /// first, g_NoMOID will be returned. + /// @param start The starting position. + /// @param ray The vector to trace along. + /// @param ignoreMOID An MOID to ignore. Any child MOs of this MOID will also be ignored. (default: g_NoMOID) + /// @param ignoreTeam To enable ignoring of all MOIDs associated with an object of a specific (default: Activity::NoTeam) + /// team which also has team ignoring enabled itself. + /// @param ignoreMaterial A specific material ID to ignore hits with. (default: 0) + /// @param ignoreAllTerrain Whether to ignore all terrain hits or not. (default: false) + /// @param skip For every pixel checked along the line, how many to skip between them (default: 0) + /// for optimization reasons. 0 = every pixel is checked. + /// @return The MOID of the hit non-ignored MO, or g_NoMOID if terrain or no MO was hit. + MOID CastMORay(const Vector& start, const Vector& ray, MOID ignoreMOID = g_NoMOID, int ignoreTeam = Activity::NoTeam, unsigned char ignoreMaterial = 0, bool ignoreAllTerrain = false, int skip = 0) { + std::vector ignoreMOIDs = {ignoreMOID}; + return CastMORay(start, ray, ignoreMOIDs, ignoreTeam, ignoreMaterial, ignoreAllTerrain, skip); + } + /// Traces along a vector and shows where a specific MOID has been found. /// @param start The starting position. /// @param ray The vector to trace along. @@ -695,7 +713,7 @@ namespace RTE { /// location of the last free position before hitting an obstacle, or the /// end of the ray if none was hit. This is only altered if thre are any /// free pixels encountered. - /// @param ignoreMOID An MOID to ignore. Any child MO's of this MOID will also be ignored. (default: g_NoMOID) + /// @param ignoreMOIDs A vector of MOIDs to ignore. Any child MO's of an MOID will also be ignored. (default: g_NoMOID) /// @param ignoreTeam To enable ignoring of all MOIDs associated with an object of a specific (default: Activity::NoTeam) /// team which also has team ignoring enabled itself. /// @param ignoreMaterial A specific material ID to ignore hits with. (default: 0) @@ -704,8 +722,32 @@ namespace RTE { /// @return How far along, in pixel units, the ray the pixel of any obstacle was /// encountered. If no pixel of the right material was found, < 0 is returned. /// If an obstacle on the starting position was encountered, 0 is returned. - float CastObstacleRay(const Vector& start, const Vector& ray, Vector& obstaclePos, Vector& freePos, MOID ignoreMOID = g_NoMOID, int ignoreTeam = Activity::NoTeam, unsigned char ignoreMaterial = 0, int skip = 0); + float CastObstacleRay(const Vector& start, const Vector& ray, Vector& obstaclePos, Vector& freePos, const std::vector& ignoreMOIDs = {g_NoMOID}, int ignoreTeam = Activity::NoTeam, unsigned char ignoreMaterial = 0, int skip = 0); + /// Traces along a vector and returns the length of how far the trace went + /// without hitting any non-ignored terrain material or MOID at all. + /// @param start The starting position. + /// @param ray The vector to trace along. + /// @param obstaclePos A reference to the vector screen will be filled out with the absolute + /// location of the first obstacle, or the end of the ray if none was hit. + /// @param freePos A reference to the vector screen will be filled out with the absolute + /// location of the last free position before hitting an obstacle, or the + /// end of the ray if none was hit. This is only altered if thre are any + /// free pixels encountered. + /// @param ignoreMOID An MOID to ignore. Any child MO of this MOID will also be ignored. (default: g_NoMOID) + /// @param ignoreTeam To enable ignoring of all MOIDs associated with an object of a specific (default: Activity::NoTeam) + /// team which also has team ignoring enabled itself. + /// @param ignoreMaterial A specific material ID to ignore hits with. (default: 0) + /// @param skip For every pixel checked along the line, how many to skip between them (default: 0) + /// for optimization reasons. 0 = every pixel is checked. + /// @return How far along, in pixel units, the ray the pixel of any obstacle was + /// encountered. If no pixel of the right material was found, < 0 is returned. + /// If an obstacle on the starting position was encountered, 0 is returned. + float CastObstacleRay(const Vector& start, const Vector& ray, Vector& obstaclePos, Vector& freePos, MOID ignoreMOID = g_NoMOID, int ignoreTeam = Activity::NoTeam, unsigned char ignoreMaterial = 0, int skip = 0) { + std::vector ignoreMOIDs = {ignoreMOID}; + return CastObstacleRay(start, ray, obstaclePos, freePos, ignoreMOIDs, ignoreTeam, ignoreMaterial, skip); + } + /// Gets the abosulte pos of where the last cast ray hit somehting. /// @return A vector with the absolute pos of where the last ray cast hit somehting. const Vector& GetLastRayHitPos(); From 7304c562d4382725fa2df54701a18923c58139ca Mon Sep 17 00:00:00 2001 From: pawnishoovy <54544349+pawnishoovy@users.noreply.github.com> Date: Tue, 3 Dec 2024 20:36:38 +0200 Subject: [PATCH 02/10] fix config wizard, WEAPON_RELOADHELD state --- CHANGELOG.md | 6 +- .../GUIs/Controllers/DualAnalogDS015.png | Bin 622 -> 854 bytes .../GUIs/Controllers/DualAnalogDS016.png | Bin 663 -> 858 bytes .../GUIs/Controllers/DualAnalogDS017.png | Bin 672 -> 867 bytes .../GUIs/Controllers/DualAnalogDS018.png | Bin 670 -> 872 bytes .../GUIs/Controllers/DualAnalogDS019.png | Bin 669 -> 881 bytes .../GUIs/Controllers/DualAnalogDS020.png | Bin 671 -> 876 bytes .../GUIs/Controllers/DualAnalogDS021.png | Bin 663 -> 860 bytes .../GUIs/Controllers/DualAnalogDS022.png | Bin 662 -> 867 bytes .../GUIs/Controllers/DualAnalogXB002.png | Bin 693 -> 887 bytes .../GUIs/Controllers/DualAnalogXB003.png | Bin 695 -> 891 bytes .../GUIs/Controllers/DualAnalogXB004.png | Bin 691 -> 889 bytes .../GUIs/Controllers/DualAnalogXB005.png | Bin 696 -> 889 bytes .../GUIs/Controllers/DualAnalogXB006.png | Bin 691 -> 891 bytes .../GUIs/Controllers/DualAnalogXB007.png | Bin 688 -> 891 bytes .../GUIs/Controllers/DualAnalogXB008.png | Bin 686 -> 890 bytes .../GUIs/Controllers/DualAnalogXB009.png | Bin 659 -> 883 bytes .../GUIs/Controllers/DualAnalogXB010.png | Bin 656 -> 887 bytes .../GUIs/Controllers/DualAnalogXB011.png | Bin 684 -> 865 bytes .../GUIs/Controllers/DualAnalogXB012.png | Bin 1013 -> 898 bytes .../GUIs/Controllers/DualAnalogXB013.png | Bin 1017 -> 892 bytes .../GUIs/Controllers/DualAnalogXB014.png | Bin 647 -> 861 bytes .../GUIs/Controllers/DualAnalogXB015.png | Bin 645 -> 863 bytes .../GUIs/Controllers/DualAnalogXB016.png | Bin 685 -> 866 bytes .../GUIs/Controllers/DualAnalogXB017.png | Bin 694 -> 878 bytes .../GUIs/Controllers/DualAnalogXB018.png | Bin 690 -> 885 bytes .../GUIs/Controllers/DualAnalogXB019.png | Bin 693 -> 882 bytes .../GUIs/Controllers/DualAnalogXB020.png | Bin 690 -> 883 bytes .../GUIs/Controllers/DualAnalogXB021.png | Bin 685 -> 862 bytes .../GUIs/Controllers/DualAnalogXB022.png | Bin 682 -> 861 bytes Source/Lua/LuaBindingsSystem.cpp | 1 + .../Menus/SettingsInputMappingWizardGUI.cpp | 64 ++++++++++++++---- Source/Menus/SettingsInputMappingWizardGUI.h | 2 +- Source/System/Controller.cpp | 3 + Source/System/Controller.h | 1 + Source/System/InputScheme.cpp | 2 +- 36 files changed, 63 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8df89cd351..bc4def596f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,12 +58,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - New hotkey system for `Actor` and `HeldDevice`. Pressing a certain new hotkey will mark it as activated on `Actor` and `HeldDevice`, letting scripts make use of the new bindings easily. - `Enum` binding for `HeldDevice.HeldDeviceHotkeyType`: `PRIMARY = 0, AUXILIARY = 1, HELDDEVICEHOTKEYTYPECOUNT = 2`. - `Enum` binding for `Actor.ActorHotkeyType`: `PRIMARY = 0, AUXILIARY = 1, ACTORHOTKEYTYPECOUNT = 2`. + `Enum` binding for `HeldDevice.HeldDeviceHotkeyType`: `PRIMARYHOTKEY = 0, AUXILIARYHOTKEY = 1, HELDDEVICEHOTKEYTYPECOUNT = 2`. + `Enum` binding for `Actor.ActorHotkeyType`: `PRIMARYHOTKEY = 0, AUXILIARYHOTKEY = 1, ACTORHOTKEYTYPECOUNT = 2`. Both `Actor` and `HeldDevice` have the following functions: `HotkeyActionIsActivated(hotkeyType)` returns whether a certain hotkey action is being activated or not. `ActivateHotkeyAction(hotkeyType)` activates a certain hotkey action. `DeactivateHotkeyAction(hotkeyType)` deactivates a certain hotkey action. + +- New `Controller` state `WEAPON_RELOADHELD`, which is true every frame reload input is held (as opposed to `WEAPON_RELOAD` which is only true once when pressed). - New `GAScripted` Lua script method `IsCompatibleScene(scene)` to allow Activities to generically decide which Scenes are eligible by returning a boolean value. New `GAScripted` INI enumerating property `AddRequiredArea`, replacing Lua file scanning, to allow Activities to explicitly state which areas are strictly required. diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogDS015.png b/Data/Base.rte/GUIs/Controllers/DualAnalogDS015.png index 21bd39cae62aa09be420153f6e301526e21ec55f..32b89f2d1c7d397c66569879a8ecacabb7d90363 100644 GIT binary patch delta 831 zcmV-F1Hk<51l9(SB!2{FK}|sb0I`mI`%#ks00Rw4L_t(&f$dtcZsRZvWsCm70p7fO z>sMsS7c^Ut*|XOmYv-GTZ1ERl$yapCo-M%r!2!PEz(7$%ilQjjZS#PlfGv^YBSlhH z03Nu(Q_keJ>j&!H@AtPX*`K9bJ+bZj;c`Ba@2k2gMoLND&wuJweN#LL@$ix}xvCqh zb$lt^5By}PtH9rnUu4-syuAJ?R%K#iv{gnmNkRs~nv__{MQBTJ@&t)@ri4^d#8n1~ z*lpM3nE7l0004*MK4lGRNc7>lrNl%BNr>=Kni!4z$vbxpA~u#HC98Fx5`4n6(R9a< zBsyGAASB)kMT9?>dX_3*GA9%z>IexLkt2h9HYRQevCbVXs=B$BJ{P{e&=?60$9+-` zLEUZF4{nr*BP13D++voi4N&d&a<#dVA{|HRqbd`%u741cwhSfEV*8{(nlChYWt1wj z+pfv2;Cfv;t|Ue)ySwdL zG&Q=egkZ_F2+`PignE}FLz6(~v&CKMRp$`O`|d)xzC(I$(aO-`ju6~;oFb_qp`HT! z2}+NJ41Wozc||U&xCZNTK8d=~R2fJP{%Ip8NQj@ECBQ{+h9J-&Ur(+KOtzYXCW4F* z4Jj02w`}Ou92ru?qURZaKGeBks0A9r85HxXL`DqUR>DdHAgD4ZK>OkNay~&-H_l|ijb-Iz(iDZoZ2mK3YH34fk#aEs>1$VHK|yW6hG{f>r=AwvVx z({5EaSC3IgdG}+G``-mNUNIT-*~0vHB4&i(2ivym2Q(t&Md=M1cVp<1ggUJv#)J^} z>$PiW=we)Y$BN@5GAv2SCWN~Mv-lNa3V{}++;}rpSnQtkGmvYCy2?zE41oWUqP@xh z@HlSnr0hR8kf>)UUc@<(R(AdKM9KwJ0RfzEMoopE${{RdglQ8HRuHFCu002ov JPDHLkV1l0giDv)+ delta 597 zcmV-b0;>Ji2JQrqB!3BTNLh0L0003100031PbI|G00004V@X3$0t5g7feo)y00004 zXF*Lt006O%3;baP00062NklTW7>I$(;QP?IFtFX01R?Ek_Zud3Ob{_Mqb|E0_^i~5w zXDHI{Awbki<`6(U8mni@0AcqKHIQx1)$=KP2s=XF`$|MZddf5yiZkEpl;!bp)?tc@#Aqxnj;n_o6Ko}^fk(HsS zhIb~zK)i)4Gqc~eqZ-j*VGMyF_YW3GzZtSK#G}Fb_yfiB4kTlSC^gstbpzQJ7-e+* zM>MQHAxQ&amW^j*6&g&Y0ouZ$8qlhoS7d6i5@a-gWc_@6P?f zHDIOD*G?=2WM*(Qx+@T@hSWnuj4_!NQXh<1B^WJaKD(py@0^Z<=_?g_D^sH+STvD>cMKJ(cE000ih zeasxp(CEW?Yl#VV(h%XIG%*(W%hd(|!o-M;ZPyPmM7WsG7THNjmAPDPL{iv>R5B2f z0X|Pl-p@s_M1P9+VJ1_40DH0dBj!Tx~{DwEZ}JJ`$vP`4E*doPWR^=@SEYP2tuUZ9j^n7erd@ zwre&OsModqN@5a106q-Tc*r%p#BNtY6d_zbPLU=QhvQzgHfZ}%s0j%Xz~yibxN;81 zeNZ2^$41vk2$tL&AsRZ5aBV3vEDPv-wzw(1<~4-#KAniP@6euGtTL>)Aq4YIQlvG+ zx2M4U1b?R|hYSt4aYYVy(gy2tKB;!2u`-Yx{IN!kmk@V#)&M6V8G=BATs^5WaIv)< zG!blsSV-Xzx@AMJrpVAD6g@8h{GpD9p%rL|WKhVf8W|x-sf3jVKv88-fc3@k<$Qvw zZh|RLN=EFwqc>)jXh|VMD}$Std1I!9qyRTMp?^iOsvGaw22(UeMk|{H`kMkbULhIt*&_RQBH0MR7q)HJ4`_tXi`pAB>Bf+fggSFY zOcp}u+iPm5?_ykg$BO+lGIElVOo(&~mg7^17y@&Ua^=lfVWE4{&p@gj<|=cKWB`0b ziahly1Hiet)3ST7WKdXb@m^&Dq*aJ}fyEZ_a|rj@S0Td1BiS-J{sH4Hj{Ym~+)4ld N002ovPDHLkV1jZUg@XV9 delta 638 zcmV-^0)hS72A2hpB!3BTNLh0L0003100031PbI|G00001b5ch_0olnce*gdgAY({U zO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF*m;eA5aGbhPJOBUy1ZP1_K>z@;j|==^ z1poj707*naRCt{2n88g1F$_hw0B+C&9U;*JXU>#EJM@DDr+=(Mh@J26pPlR|mMp<4 z^KCyT8Sh>$+jRE!{`q71nPZy?y}W*yJ~Oc+V=tN12C`6WH>r`IG4{4?r0pZqB;;Lc zGcUIzW19)xlTQcn@bqkY>5jKX=}0^|7zD(v!7%y~Fi{Y_#Am?BJWoT(!axe>b=vE` z3UC;T3Wiq*`hQsj#`o9b)umAG5l9UKfdT_TVD#SmEEMF(M0baDm!LqR31`m#VL;HM z!T_-bCwAQk3JTkW;sy4O$msZZ<8~brUDw7OHP2g@0>W-@H4t=%BI^zTqCPUG020v{ zJ+llD_6|`4X=9F_pK^z=9g5B?84V_m38cVaW{T+d5q~sBL?bgBb)iIoSY50C_AW>C zXrUU@fS_VXA<@@oMk5NOjWZR9H&4_Bc|aJA$Q=>_!azX_85NY(i0)(#CI!b)*P}VkWxVXzcpoAU-OZ5H4J6$QXoap`>mrc@ZWpCGX{(_>X=Ibu?p;U zcLajfkk*h9V~U(*(mEKim0%Q;)e#k15k@gtEvV4SFp9})QM@5mF=;J|H^eG-rdn=p Yziru$gY>Eb0RR9107*qoM6N<$f`3E`-T(jq diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogDS017.png b/Data/Base.rte/GUIs/Controllers/DualAnalogDS017.png index 5b5c64ff413a1cf6050551a0b6238e921d16fafe..06c5fedd5d70640a35ea195c6b465729684ebf02 100644 GIT binary patch delta 844 zcmV-S1GD^~1>**gB!2{FK}|sb0I`mI`%#ks00SCHL_t(&f$dtcj@vK{We@#;8xG#Q z`#%m@@&!$&AhWv$-GXdI*LDsvHU5GuLH{FrwxC1*z#R%2iXu`JDdl{3dBEWUOCrTb zij*t^+;M>qmci|^>#4S%-#?jTzm#tEz;@a7=hKmFuj-~4DSst(Kd5K*MsX*^!$-^D zs%~=4<5lUt<2}PvWnz6wR+&<|RfA$>4^g7@me!p-K;oS-A(a$yl|dr5n-$q-I++0g z!2YmHnS&YC^G0{#EB7Br4Mk9Z|SOY+u7`Cxpc6|yFKBkjdc2cY|=ZiH<3fW*K z1Hl;(@-*lDTz>>}qy!)4A_EaJMEXq9=Jr9v`ckBrw(etsPnb5Et{9R;hwBN1#CxHL z@W)cmQsqm=grYG0KvSb@AOuTpju4HVN2oT73{3)^PG(o7SDiyB@4FM>_8ro5i&lmf zSA^iY<9`%M4GHZja6dum$st1mYFv?vDsF>yJ{?87(Nq~o4*qE)CrF5&oh86YaE2hz zAYYGF1}0n0K@&knh=vpjv0FCuszrtrvFLdKpbvF!7;1rra0bP^Dv=Qbx0JBb00^oK z3edhdKA(l#-D;@8pe{CR!|HNM%s-Qh#sEq~H|bMkkgOtGWrEZE%TNWLQz8 z>~1$Ja=oJ=w~(Ph)|bpx-3%V1j`HryAosru+<3)gOeeGK--%=+1Yg*;%dSTwLSB^K zpm8^bE=i~}SHxr?#C?118XCG7m)@~rKZ%T-q?ifeZozVV3Xwu!4pJ_>nJO%HPx=zD z+C`zRGGinI;D4lOuQC9#7HVz@;j|==^ z1poj72}wjjRCt{2m`zRtF${%!0CsQ(ZiK`gx@OIBxDNM0f`3({klN0({X9)av1Ez1 z89VQDemq<*+jw^U`1;lS%(>MGy}f^`UOBOQ=3a7A8^}Vr%}LGtjJdaM3)+*2Bw8U97Fr18Re*BKG=CV3JAd{*;%URt-!jdd2*nFT zt6KlJbvUA13yo0*1Pz7=@m`;q7+xS_o>CxIKhX=afJ9<=&JY)n2ozMvOi(t4cO}C> zyooF^+IM4BGclqtL?B525e3p8hS3$`i4oQD4+_$M%mOm1Td_jWg1Ui>2_(<%|4a;P zPKbwrM1Qu8r?QL~5ibQ|399NtmITrS^q;jZQ+v%v#`Q3mbEg7n0j>Xa^a5}0eW4AQ z#prV`1w<1lRd)s=8iT4K6D%UK%BVUb!B&FNjHbgIXhj&!Xj;%fE5m3;)55qRRxzp; i#tpHGok`2#_6K{2jtMX7hV%dc002ovPDHLkU;%>N@Ds5B diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogDS018.png b/Data/Base.rte/GUIs/Controllers/DualAnalogDS018.png index afb08f7c0a9073ba6f9409fcd01b2fa644f440f0..b9a9927458fb880e62853cacae527c469504c648 100644 GIT binary patch delta 849 zcmV-X1Frm@1?UElB!2{FK}|sb0I`mI`%#ks00SRML_t(&f$dtcZsRZv%kvZ2Ue!%8Qh!S7z7o&si{e6vhwqxf zRoz(4<5TIr;D3fH%cT00%rd2Piw33A9->6*Ev-9y0LMFHLM|!nEQ3UB)=RR_bTR_~ zfZcwZGY2s^`f%P{Vv?OWMEEF8j70u?u>ycJG111h>xUd7d`u@Zb5gW2=ZjU86tY1} z1|nua$kQ?JTYnK8BPICIiVQ@^5biTho7)GG>PwNLI=YVuK4H>mI$?+t9j+%39Pfo9 z!XHaL%azX=6N(aXgoKRH$cQ~VCyofQ-aA}Wb#q94E_{8VJ{;`!+pIkVb+=tVxKYB6 zkW>`JCNp2GfI4o^7pns)+79s9(c(}U+3Xx9klxH@XglV9K=!(bRo}YSYM&Y@pN0>?HM?Z>sJ@V&@L- zy+tZRihq;3jKA(exW2tP`S}yXGll;{11UWgGB}{fEK;b79k5)3EM*`$_>)FXkPr#; zIEk1c2sFsoqm_Z1t>mJKAR|N*jy_UVHuS1S1{bO5xdNasb#53+fri8kN_mwdBZb&f z!b}6e$TBEE`r`QI`3b7JNiKm>GIHmgeK3&Yg>BpQ z0~!(XBDaDTs~EZ@p-!uaF(Jf#d+iz;DvWb$tk{nu!;%y=A+ai$#itNC1X_@Cz@;j|==^ z1poj72T4RhRCt{2m`zRtF${%!0Cw~a+z5#~ueJ~ zZ8Nst7w2bsxtyl6_uJ>s$d8bHAd-3J~p+1f-D&(zN|}7Akl)O9kvM&bg8h( zd(MuVbuJ3qgkmMOmdI@RSl8`3Cpyj}el{)ygl%s%5VS*)ak~IfFPUY5e1AQ=z%d&u zay;(_r1m?E;^+~q0@Btqdp>0kX*;8J1R@K>16+2>6n_{Nd;ovCu%_!5GICa4{-ruprAr#f}%0JoeTr< zCbGngzH4VS5`%@&1%li^SRnOg$aaV)2CL%_6wiMk86BdG!A__fNSmPN(e)pRVbz2< z4TM=Xo_?8C#9%xXh$SfN9zQ-?`tp2FzmA zIhO)564;yF83;CpR6`^fBQndRI+$Q9!6+uv;SIDRjAAk^XrPs06q9LDoDi#+REy$- fSjCQ{Wpn!lhRco#4u=HF00000NkvXXu0mjfG!_nA diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogDS019.png b/Data/Base.rte/GUIs/Controllers/DualAnalogDS019.png index dc1c60635d7a3791ce83b9be862b96b766e1112a..869a7d4cb177d37fbbdc4a66b6fc04d8923768a1 100644 GIT binary patch delta 858 zcmV-g1Eu_(1@Q)uB!2{FK}|sb0I`mI`%#ks00SsVL_t(&f$dtcZrd;ry$1b&41qT7 z`j0}3zM$@8cy?E#o8YbJ+RlQe#$S-d$bWeEW@N}8I752wnc|VhBPlD19}onV$UENS z@$N_p;EFSRis`&uZI0Z#Kfk_4$-b0sb;spub3E*K?E9juvVW11Q}>N}RPPj5LJWM4 z>0Fdms&Tw2-B)~ML}eLYo19rDmu^)jU)n?DNWHmr2X~On&Xf>Jia5(45q;OPZJK%p z000l$`;alHA<>89mJ;J_Bq72?Zeld@=ZiG}_=$18T&_095F$)8^(;9lu`=h2wUZR~ zMJyQzmjSk!c7M%&DuP|4SRbY$17R~n`b_eUwn6yXa->9+?o)zEnAV#Hn>&ejJU>1S z{#*m=GTUzJL}3TMZ)(prPJ%A_P-z3K#Y5N4R$}GBg3Ssb{AG4O6c= zhH$e_2Y+Gv#2*DuROm8-xy?00Nxjgdk3 zK{1|VCB(KF^8p9pG6aDJnR;SnV6c_M4z3OBAsSLR_-@&3JKRtiQuw^*27uqxaoh0_ zpdl`Ue6uQ%;e%@_(W3xwmO%m9gX6<~2Sr(Vmw!Mm8KL72F3dFE5<`Ym1~)EsVJ3x3 z0Tw#GpjecZb#H@9G)6`&vZURlQ4< zr&ACi1g0S6Y&JuM`R++Cfml1#S!Rl40K9sNWb?>DbuTkjGAOjR42+UQ_oz@;j|==^ z1poj721!IgRCt{2n9EH>F$_hg0Cvy=9U;*JYu1!QJM@DDVt)}7g5%iN*Ka&ev1DmJ zdA9FyelwTLHlDq_zJJa9%(y9>t>6UzSFcuI;gF)g`z<5DOg=fHsJP$*O!mtRCI<0k| z1=tOR1w#{J{eR2@qd#S+P;L>3G}9VABAFBGDv*dEU^NK795>nhXAoI6*Rfz z=(yF)wZc}RXoc!7+0Qh{jqiC&Nf1c~92CQQA zIZFYV36#3K0)fV$YKR0wL}nRP2NJ9jjAk?)-ar*$G^1&;2C59B8BGi0gs5UvEsPVQ eik(Tz;r0#UM~(@d&&Nvu0000dmj@ILEQu5! zDN?cwaKjnC#0+k`exTa^{Q4dx`@M9l2ew^5oQ?;wy(p_}q<`epeW#w)C&i5r3twXf z7iE=d9v@2g4gWKus*JBs&MK2jw`!2D>>+ZL-rTx_2S~g#C4`b9t};l(X1yf)H1!Ms z0CxLr$Q;y==)-wSiSc%l5Md)XF&g>v#R>rY#ITKR*AF2?*l6lma#CVt&KE0|6tW?f z3Y%qiVTFy5a}~Xo7o59>r0UmwRN8oY{InBbit4$I!sR>B;IpH zgguse7Ajvd#uX*%2yqz^BZGT(O`H*uI(L{T%4#fqCTxAKJ`(Kq+n^kRy4$WF%qS5@ z$m{dV`1|qcvYngEe6a#*yFFj5MpC5xD1B6AqUPm-YJbW6{rMa2_YY1*+T{}hX}-|p z6?G1IeSU%aZx8;C@D`fXQZT(P?Uxg3LZoCMHtVIxL$={LcDo!@ggid|0D$W*6BE(| zs!6nBLd=M0YPWJ5sfe=W?Dku60u7C>kq|7oDMHkD9--P|WM~p-Q_n6+uR4cN-Zv-0 z?K`CB7Jsb_EiMSbb;l`^8sgeh;C_PAlR}0B)VM4cRon*abUcW5qoFd89Q@Npj*}2O zJ4=9*;0!^aLAIV)8JKJ}2TcSSAsSLB_-@(It1&X9@I}uZ0DY)4!%zz}gfqzJRf!BA zxTS=Z20&0{P=NNu@#%PgqO812AeW5Ld5g=gO@B-XV#tunpys9Cm`TAYz>SVCDHdhr zJlo(Bjgb+HEM<4IUXtq_4Y`I44U)cOF3M{376xB!3BTNLh0L0003100031PbI|G00001b5ch_0olnce*gdgAY({U zO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF*m;eA5aGbhPJOBUy1ZP1_K>z@;j|==^ z1poj72uVaiRCt{2n9WT@F${#a0B+C&9U;*JXU>#EJM@DD;(rhnLhQ`glegKYShBP~ zdA8?^^Rs)oY}47x>-(4GXU=UF^z{5@`pm+vnS05iHjssKyG4!sjJdaM3))^XO+ntK zHgj{kW^S{fTk`23?j9aZFSFx~Q96=O4h8{nG?++y2^bbcukaZ#GS7#hWMLozdNb|K zz6vl6MFqnXf`5L-z^G3dDU@3T((5z{5Clf=+>b&*mP{nRtV>WJ*@Ckjb_fu3sYH|a zJUVXFxhQNGikJBFt413^0!87Bi`LGflnwPcnA z!gL7o9rMg`K-fJ*4W!LEdVb0t5}hITzLJR{J!J|E#ebPU`aQy2!_n_DccU&87Kk-# z^=of)M3)vCV;T@N7$Sr{J~J^`AZ?zhK)m}zEyx2BiNWk46p#oMRLDqBHU`_tFc3D8 zC&v1$oz+Z?D2y%;@3>`Kur0ja45J;w#E9zn1BLkyWJZT5V?-yE2GS-j9e&!?NY8cAer9etR@4t>(;J-4Tdr45@}pu!zW6Ce;xMwi1kDG97H76=4*UX+Z<645OG#i{gY>#iUvk gC&VgtCM}2CHy{j-2`_4kmH+?%07*qoM6N<$f~-0YKmY&$ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogDS021.png b/Data/Base.rte/GUIs/Controllers/DualAnalogDS021.png index ff5462877a7c1a821d6f4c05fc692b65429e2c50..e119dfb57446f9e0e03ed6271efa58e27dc3e714 100644 GIT binary patch delta 837 zcmV-L1G@Z|1>6RZB!2{FK}|sb0I`mI`%#ks00R?AL_t(&f$dtojv_G(_O12-C|1)= zKku=k;R%ioQBzNgXs^Ai5gqdcH0a)go(^qsZ!lM^JQqUjICe72?(s=9`LW~Aj-5;Z zc;E`(ER$Dl*HeAJetb8{{wUq*iL18jFXt24U)4=9QcCK6Qh%@Ni{e3uhiA*=s%~6)Ev-9wg2X%bgj7<*RR)RJZP(ny70Ego~ zWesXb^x?Xt#6$;4i11OG7>)eJasvQyV%W}A+x00#_?S)S*-5d=Tr4*%DP)J03+jaJyh1V)FVzMu{68B{5pr-EG$*5BY|dIPG#sB81wHV{8)_(gdnWv|>VH1jG`W z1-_iaaW77wsnInMf+aUch{oL&CV02OEozZrMUk?*+pfv| zj)sgOLxZfh-KuT|k5N~CGz9xXWANY=lQEmlv;R*d8zK0?cGY%08WHlM^aYK3F?2~n zow*_=3nA{;YuC`w!?^T~6~{?ryZ1_l3#~1|r%V7_g}4`JY+?Tn;kSJjB7A%$TSmuU5cib*7XeO+ P00000NkvXXu0mjfNMw;Z delta 638 zcmV-^0)hS92A2hpB!3BTNLh0L0003100031PbI|G00001b5ch_0olnce*gdgAY({U zO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF*m;eA5aGbhPJOBUy1ZP1_K>z@;j|==^ z1poj707*naRCt{2n9WTDF${&b0B+C&9U;*JXU>#EJM@DDr+-KxIQFysJd+*8k|kJX zpZ&i4GPm0fUc9}3{><{qwWkfeynalxvavI3FWJ-vvQTZcDJ!p7d&iDo>?Jcaq-|=I zo7wSHQ@8KMW-c12G_tv^M%I zz-}lk7@86EGk*_^{*<9Yxkn(K+qYAJa-BZ_L8{-5RZoS zon?ST_YgLav8MI?l076kLf-pIMuU3FG#HFC-}-;VbAJs-|CYHMiBP;iW~0{stZky` z(n2-LfS_WC5$l+>HcXF(7syzr6o~cSQ=5$$4bL9p0uq6O8nFyzHM}z!2I4KGnVEey zj%r3D3PS{f+&`i~`pqypLp&N$AAg{D-houi5T-_SK;1yb0#atze?~*=3CS>!$g=T_ zEJGubrFTFyLsj>XC4n>p{qM6|=InI<@>~yt**g_T6V%>y^alT(`@%KA(&%e01!QJW z8eI!SRD~9FN_mnm7scIoDi$TmAo7t Yzms5vg7g0xumAu607*qoM6N<$f**gB!2{FK}|sb0I`mI`%#ks00SCHL_t(&f$dtoZsRZv<`wq<83J$K z{T@Mf9&430irH?7&<@H9&YP|)jEMKj+y;{hnkAKQc)Vf@VIx>{N6vrn9+;}00 zD}!X2$!tn`iFsu9yA63{avfzGgQeZcY|7dp+wdIKt`AX!Q0H-oV`73EKqY~eO-P7< zP(ahbmUBEE*a0-wyKaPF%1z;-q5BBcr;#BEpo{tPF7=9I2(|m>LRI5`PzFT=*1Vp%V&~oF5!Yd?WF<&PCok%i5@PlpLv>h7Z+C}aQ zn(xKXBnfq<@|Yxqm|w3=LtPK!+&5Mn$B~he6g45fSFjX6g@_?A1u4DVj1?AoC;bd) z?L`o0nK6<9@Zl-arwjn=<&MklSjjLUwZ-|A382dmV}ZmL@6RFZwy#2jjqha3;CKh% WhLLKIBjXqV0000z@;j|==^ z1poj6|4BqaRCt{2n9WTDF${&b0B+C&9U;*JXU>#EJM@DDr+-KxIQFysJd+*8lBNBb zdA7gANoH=hZ9IE>|NNQxm19p6dU^erdSzl~#$Gb14P>F%YEqV8G4{4?LE9}eB&02B zm5bY%v8M^$lb3^dczT|C8y)Q$rX%s_U=R>TgNf)82v6og>sKTq?twmg20gW{U{WqWg_~tS%Lz|CY+sNhX6raB@+Dm z>rr$mNy*W?yj!vgMGLI8h}Awb7$X$zSU%>47H?gb0ur6xY#`_iMXoyq2)ku20mP$W z-Lnjk=o-QXGRCy-FIhvPBji1=WHhL|OoPGL^R4F*&wnu-{V#Ji5}|m3%to#MtSydc zYoQutKu|HH5bySx(eMHp2P|!lGg0dRknG6H*2GWX|{Wgwj zMk5MC1cIDDqCon^Fgim#8qqrbK=Hf-shA;5jp%^7fs6qp&-Q;tL(2*AFpx;wct)0? z5%E$WT6RHI=a40Vv;z9?vs32mF(0|Ehr!I93Zw~Iul?G8|Mq?17+`7iF_!`|D^MC; z3q(|dT0=%GQe>4;>xhW01fv22w40fVCK#CI`J@0W! zlP9=bg{Vo3=n&oMTCPS^98ZuYFS7l1`x2x;&Ka-m@%)8Nj!!~Dvz{6I8?Wt|S%53f zaFf${zBnAUXMcYG$Qt`nb0>G4FAm49ZPe$Z@uV6lHRrxf)_>}Y;z|g^T~6oGcv4D_ zPc`=y|1+|(Oh~3?mZ>#&Qm0VbL)1vUwdaoR;8~p^A(j+(mO&zR+m$Nw`0xY(057k9 zV{}M{XFk;1OH5G6Lj*@{Vp7JR&ei}BCdPa?UmT7xL~uMlJQXJ;cg*Q*ZIYrs$Rz_| z86d5+wfdz9wtq+w8%vRakPPv*d7e=jL`YU6C98BF5;$S0-qhRNmG%yR(`wPxqiuXu zc^g2TShU-i779wHg}Q7K!)**oO*4oqPbp?*>ysh?L)LQD*y^U+um?IF|I8l=*B zI$NtsYkhb>uN;7Eyq1}`oP{VtEQPzaF-a*2ZvagRw0~|wEHV%pDZA~;^(uJfY9jl@ z%(L?ZI2q(wA#Qk$3}Ydg5In+*A*B>}8rKN(%26Z}(zOljmmB!`>sgiI^+YP98pazy zW4-G=-C)YqT$IO<{c`jEpOQj7#!}i_hI_|I37{xLQ?J`YFyNtQP@tzE8K{WlA@rGN z-(uA~HGkquuXLBnY^n$+1F>Ij&d8wSNiMFhOO$n|@j;Dpl(8i8k z!01ZVnm{U!to~dcUr}1~Xc&zr?)^~=2K#-;Zo5)r29i+&MUN0inck3s03^b*LmBRR_qkqm&7r)cN09wgt(43P|qR9kvRd7}H! q$v~voVtx+6+dc~s9AC+n562s}#;FpaBqYlK0000z@;j|==^ z1poj79!W$&RCt{2n9FU$Fbsw>KyU31*{DEw=(*>PlXbdJfq(WyKv4MjN&T{A!vu7Q zE%EV@lIYxSm+<8C>+xreGut*DdjI$~$4tlew7sNL7m$T)yG}*pjJ7Yiq$t;x=^XM7 zwV8+8p0-Vgjx?r&czL^<2 zJ_~Rf3JZo82!Hx41EalVs8EgwM5{Ck5H^em0J3G!>d3Bvplk_*xpoQ=6o%FSRn}3?%bWHG9h}3&eWnl`p!t zy){b$X|uOA5P81q8KPCg@6T(v*ZWZcg6g2&G7^YKvVVsm!`eok(GT<*3(A=5-HPQv`{ixiw;br=aKnYAibS35DQ8LfCmKad8~>= zs{;apmYg=wJTG?lNo~o}YAX!6J=~e({d!CA)E|92q$dq6ONK_$F&og>!JwZV} z>X05_7JrbD3PBT^2GSd_uGGEG5YH!Mlz|{wul~+JsUE0@1>!-;v1ev@#44S}cqkVilpr!nh$;ku$}zxfc8b6?}t(%06%+00000NkvXXu0mjf DkVYDI diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB003.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB003.png index aec2a2c555831afeb3e6f1ad11ac750380b3c2fe..6a1e0c93a538db5f27bacb804d927d1a24ae47f8 100644 GIT binary patch delta 868 zcmV-q1DpJ}1^Wh&B!2;OQb$4nuFf3k0009uNkl1&Z3}%BqK!@VC+wVOJ zFMfhLli}F`IvLpvZ$a0ztKp@IpCC(+_weq`$dEU12ZO1i1PZUX= z4&aP8_>|LmI$Q6#wqHNLXN`TTxsy9iXY2iLyJ6d_y6KFRE`R5~NY?6u;!H?{&pDl| zx+$f{yPErq{~1|XMw96>%XBq&QYS6#A-YJtUC-_AU|F3$!Apuc%ODY}<(!on4n_a~ z@bGx=(IFX@`A}~wF{+S-h!|ZHlQRBzvH$>`7_o6WTkkzY#25}n#YxE>b39pyq_7RS zWFRC1sFjvhzkd|L5-H@vQe+?~L#)p%ZJ`W8ljTUsD&6~pn6OlDYB3~v2L`4PR!`zQ z0zls~R`2lkp}fTGA>+vcsDfxbS-3J#2uk5&rECsw*x|h6<>?tNZ?4!us=850p}Y&A z?O|3q3Z57e&KG)#O32I8^XvaqQaJC5`&s1x?8a+yF@GVhpn7+G3zs)nP}L2q_%UFO z7b$VYon`K>Z{f$E-!4*C%eiSQSmnBen~;NtfZIb>%eiTVV#B+rb|tt7!5DJN?E-L! z1(q0Ml?$N~^5xst=w1bO{`0iMZA#uhy#eea9x7{Rrh*xiOP?b_Cr$nqsj;Cp4 zaASKH(4A$pqqatXR6OAp#hOR^D8_m|@}Rfhhpd)!HfC5}NTs4^9a7be$x8tKRiIQQ zis@9Vj)#L$@$W>65rXG|>1@46BdArh-k?c0h9OBfXDN>PmWS^q6=mHV|0000z@;j|==^ z1poj7AW1|)RCt{2m`hFrF${)#0Cw~a+z5#~bj`ZQ;X2$034hdur7-p5xASKvGa5@- zv`zf@?8Ju4AVbB%OtOWRXAbpn~lw(C^1j%fRoQ;Kq4nT12% zqc-w!+tRk_(4N+C5HHs^b4hl*JC^AfoPRR0ph{X+FCCZ+wD1YUnclyUl$O8qB*`M5cGN=`?`TV zmXvYk+Ay!oR6r^f5;>kdGYyd5hm{3HzTe~x5hxWH+JD{(5L5@X%SccjNfd_X6zXtR zM`aF?Jt~w4h#ZU_#rC|H-6+$DO-~;U2&ya!r1DvVfwtf*kfojJfp{}X3&pC)jISY( z3Y0cemSfs)TG>Z1JSdgKK|r#GtkSIjwB{TJ5N+=h5O0RamS6=)R3YtyS_Klt@ec|* zR3V*V1b>j83PBT^2C_6@wbZTN5YH!Mm4P5xuYS%zsXnN?1>!+rj0md$kpNm}trE8W z%wJBU(WJ`soeD%0M*sGc-=6xuG6qCCTANb=u>#bx8-b|mpvKUntPan;q!?IMmp>6{gM$Hsn?(Qs002ovPDHLk FV1njX8?*ob diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB004.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB004.png index e16ba33fa30ab95f37fa3bbdba21e0ef08b3496f..735e5de77321266bc4be8e360d1ee2840468ab5b 100644 GIT binary patch delta 866 zcmV-o1D*V{1^EV$B!2;OQb$4nuFf3k0009sNklIt7{2HRu*(E4sFGkg3TRWC{8o-n|(e`UmN7psUCvMTyeIcb7K>5oMB36iHbI zxZ(^SERz?@{fQg<`TdjW*_YCtJaMtypZcz4$E&(2MoLNDH-E`iy-{2V@$k_yxvHC7 zcDyRxSG;GKs!T|xWR)qUJ84p=>>)~&-qO0GCumk@N{A&zU1gAn?PkTwJU%=D0Knn6 zi?JaY8hvQDmYATBh6o>}iAj0>Y`zA7FfrobV!1!X5aHwT;VC;Q)@RPbE+PQJ zTSgllv2&;>Nsf@&d<|5CG@Gy06^SzVrAju3Gj_Dm!I6RZ_4Nnb-rtSpQ1JC>90~w{E%@-+o#Y_mk zsFBFnZdR(Tpp`2LGa-G~LRB~L`P-KuDVi1X9WT-CO31QhaNmbW$%Vslr^*dlITz7{ zU|4g>4@tSbzdJL=0{=OO<4&DGW20**H&}ADAYaFewKA)jsl_(L6% zlB;}j2(2!5!Up$H5%pSBy&>&wsHSPKl6MyVXfmDy5tez9E)K3z5M+ zJ9Yu1tBj<8YL2A&zC3QxP&W+lynSLCNi8P(eaLpRVsi$PQ36@}kg9G}Q3CM41Eo4q zET>#I>~^ZTzZ1zu2%ZNP%l!$RpjJ_PgC^Y=x+I~_ToIFn5chE8I!axPYwuW5PV6ko*8A^iVd3lTovk}ofge+_bz@;j|==^ z1poj797#k$RCt{2n9FU$Fbsw>KyU31-Kao!$hqf^({;K}fq(WyKvnqoe~PkY!vu7Q zBlGc*qL|!nm(dfd zwVBOrPur$LM_SWCJiWY{OS0qbsa%M?axe&pt-)mUmw;hGXpYZ-G4g&I$|wvZ04>vA z_NxHXP^w^ffq$US7#Qs>QwrsXK(tCL0m8u0t~nM8a%9lzVBdkDpg^nv$$Ed}{O<;2 z6o#yy?`No*G<)bi3krKByHF6r2n<=sJFQK09}|4EZwe53*20(x1U(+ezH%T^(mjm+ z*i;^wrGX$75;-1~d?wIcfkZu|8i+h!qKBYRdS}?~uYUy;=_tKr1O}?in?pROP={F^ znK?xEs8CoSqNrc(`(AdVOnWx8eba!jP?#(sPWLd-E0_h++gTn+)TgwHW_kz(Bm1;(3V%TpN(1Q)SXb&^J;d_~S!p0h*0Y}(DA|U3SRfvhiV_Dq0bS zNLeh*KV}=pNK08P6*t5xQW{Ie4Y7)xDVELU4;0Qc002ovPDHLkV1j*q BA!`5t diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB005.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB005.png index b2a059c0aeaae683846b32d08d92bc97d3c8a509..b039cf22ae5b3dbbf1248d850b43f3abeb922b5a 100644 GIT binary patch delta 866 zcmV-o1D*W11^EV$B!2;OQb$4nuFf3k0009sNkl9XyoGF<^c9E|#Mw%DCKAVLiXqvB9<>zqtiDirZWE)0}5 z0B)wW*)IiHgMY$4ECmC_4aEA)@{Zb|Vzv^LtgU;W6aq{2rWPTKcVK{`ij|Q(0wBI* ztlr@*!+D9@LnhM|a2un^bmhuK0K8jYD`iW%pcC^B2?naF8xacURRC?zvf6R-#1PsZ z^%Ap(#9#mb91nZeQ?#~+o26+f zSnax0GLYk8@A8oCW@(zCaNu3+b~R-!nOiIufO9Oc#0IM!l^F=SvnR{Y&ZO$+^EZI! z%V!@xeKZG9uXnws8%((|7nPt;7_sw+rK7{a=nO;9cs*AGre`xpQ?Gl;NP&;Sz>aVp zLf>iUmVc^lV7#8QP{!*yRCUuyd}#r}b*D8XMSQLtw=LJ&K^W+TA(ZiY4gmjxdMXsD z++7^*5DLQJloCKWu|O6JX{^Q>V4Y1)+rZN6bQFbl3W>Q zp7Q|f=SbYdl~gexcpjK7b|)MpHz?~3ns#GIA!3`QJgEo}dN`s3z@;j|==^ z1poj7AxT6*RCt{2n88iPFbswN0l2{qY=p!PoH;WN>#z?Jh<}5n&_A}{b6?uDswE%V zrm_9SvD4mem+0i}{qx7uGuw6@dU^eDb);i^+Md#>3&=#aL#Hx5qwPyBDay5F77j&4 zZDeuV)3)o-k#snSho@&(ZFQnCN=59+!5|>E22+_|0)_?Ab9@AhHSd?9tc8ID&|B$f z^;LjrC@L6HAb;pR21eUuq)?6sq?c(DAP9_Jd#gf0whWpb>^l&YEI99AgtTO3hHV0* z3Il=S9h|D;JSc2S4xwZLp+{!s-F7@WjtM>+Ck5i&8w~{A9>_QukT#u>ZKK>WQvzW! zBy&7V`AVR>0AUNO3W(j`wT2*2qQb{kf79=;$2+YCPk#ZiV6w@Ob4cVA>hRx~9t_iL zJD@gPC@2t{z$<#~`%#8OcG~*n!LaAUfuNH`2CCOf7^X`Y%c5QZ(mp>N5QE}%xn4#x zzNSDbP}-I99P2&nr9FG*srpI*VGVhyTLH+Pc`AN}K(ey~lY$i>S%ze79`!F8_YVsC zKO^f5Dt{md6tw1{3rYi78t_`GqK0HpkOLqJVl@zC)vMPY6y`&(s)qr>+MEhVbS_w? zu=knI{vlKPE(Kx}W1#o5dN_I29fCK>GBkA z`~)}^q9#(R6CI+9Xdx}43FZmh_$kuS(;?*zEa3tTS(cgIncY2eIDCz*+u5J_?%SCi z_JA8s(8}pNtk!#}Z9eT~jeV)PlRFNp^?tYAi0$o8w>DDhoPYZ+c~zejH$ptz=X7p& zx~0}}Rde6)KO-y4#BA!!GIhG~!Bt>k< zC4&%hfP2%Sw|`%X;1DV7!%}1rI7hV4G;OX8A!aL)l67=%5`4l^)pW*?MjaHOT*UfF ziU8tUMyn2MA5JA^h4cp#a0jFQU}DNd059v0O4$-l*omn_B7@NGbVX7)RRQP9(%Nyb z#1MBrS0!qN#K-`E-FCw&CDhlo*V+NR^HOH=?Lx@@J%2<~SCob}UZlj8WJ2f%8VxDS z#aOi!w03nOnULLfV^YX+F;=}H-|;$5yCGz4nM-UJ;1CNmu|aF+LQM$C*^*`4#pJ*r z=jHWT9YC$>I;I;+xiN`Kq_||n>JiOCtz)DFP_l7TuX)QzfzKs_7Q!jSZA-0NG-IUV zj1by)p?`^_h|l%oj^&|wEKX|HDnaVk_~K4mH>Ctn4lE%l%#(dAkcL#^ @K+%dH4 z4f!T2Bu9>+H0Umh`=1cXXi|xwLCmK+KrZTtlv3$ag8z0cb(0q42S>(oF+Tow9E~A< z#<)~@o?16q*R2k!p;Rg@!e20XA=R5Dzo`odmi u0(lvtDM;}p_&J3C>{^KM@tJ)2aJ&NzzMC4!hheV(0000z@;j|==^ z1poj797#k$RCt{2m_bg&FbqZK0PNrn+z5#~ux8D1xDNM00)NfIQq+m<|J|Q9t!gQY zNz?fI#fj6o-7eGF$LIH-*Us$Q74-K0<+hQ+_Vhias0+wMzC%%2JEQN*E-Tu#Wfp>> zLv7^Ywx@4b(2?435Kk|!ZnM>i#wZ)&PYwnFu{D^={1PxMh@S8fFxI?ZhO!n05l+OO-5$s|8IU%ek!_>gGE)L! zG9(k8rF z1%!3vrEV1*z-Gr=&E#lcQA zBMdWHEa*ft!!VP@qNotFm^2neg_y<86wBuJ4-{?_dai1aK7RlJ002ovPDHLkV1hIz BBzyn> diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB007.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB007.png index 1f578fc568f3a8a215a1796a046458a587dec400..1e830c7f0a7bf1193b53a191867d6aefa38740b6 100644 GIT binary patch delta 868 zcmV-q1DpJ?1^Wh&B!2;OQb$4nuFf3k0009uNkl-EOOXHY?#;-MKX8Ww9Yse{q@=SisUHv^xT8er>4~IH z2F`egFC~qqv-Mtj_xI0_qP|b%JGMIO>d)E`NPrWRL2T;!H?{uO*EK z!%?kqd??>%{Ld)LGAWxbvrJdMvl^w+9-)iW+qG|Z1Iz0430_jnS%!#ME$5=m_0^VJ$KU+(fL;Ebl@aLdsSmrKoi86Jo-0)zo6hq7DjBAyRE5 zMF8n7V^xQ@4W|;fLdKH?xWZ^WS-3J0z{~nrDOwW)ehh%FJ-3KPDAnc5P!?LqBgAYA}6k76G9(oETpWK zbJJF^+I5L+LU!AYOChV}+_XaR#Ji|=H56@`Q*0NYi3OI}V6_WjCWPed$ui+!N)Y$+ z`1D{7pk8$y(ha5Dltd*`LNZe45z9cmedGjCvI$eKd&@|HFC>Eo!YL$tr=43UXotSY zhoz5Pw0{VpeWy8+B0krSE6X)MM24jrwv1JR)UJ0IRrj}dVw|GFj{}iIf4RzGw@eQ6 zWSh>&Y3*bCZi2kiq?EmZx;JQ$8lDgoXq zP^qrqNa0SxwSOm4jSxByOlRvoO_Ezp>kXQAV;GW1K5Hqb3L)X)D4ZyFF>bwMB|A$W zHC;(5CPcdhtMO9^4}mpEX&wJPNZpg30;TiF&N6)@189^Y1!@ai_cDaOk`W?zF6>n% uP?jP3f}FXiKZl5)eH0>Me5Sb^9sd9eZIqJ{91!XN0000z@;j|==^ z1poj78A(JzRCt{2n9Xg&Fbst=KyS?s-Kao!=(*>N({;K}fqxb`5D*gnJkn1#ZI}QL zu_cQ9M3IUwms5E1`Sty0>5X(%ihUVk9yvkZ)}%TS^05r~#)6d(u;t-V#DAV&txj_e!=N)()RF+y50Gs9K^ zQiXv)u`W*4aTb(pOLn0|0ijps%-nH2IxZ7@G>!_ydNvyfdOVPEG$3O-Bgck$WLg5r zWJu(Al=788Hvy6@tSlh%eA60&K=BG+w)$6WP`iu-6Mq>)?jfF2sKZ$s=rPj9s8CQK zV!$eT<9u&-qn$lbX+vNyE)dn?&CB`a2&Jt=I6=R)Xh|uE58tMo` ygcb{Gs51-^S}cqX(M71SFgipRIZ`aE%Ri?8eGw~c0IQ?`00001^Nb%B!2;OQb$4nuFf3k0009tNkl{q5(O@p^$1 zKHw~;^L(+|OKrb@-DHh@EZ@l;=Zn>Tx7~>Cqw%B~DK&kcCx6fCo8m->hl`xfqw%EF zJie6g6MizXvP{gTW|pbtJE>DF?Gb9E-rBy+9W-yJPq31r&N4(q*EXWf_0=r^;C20C znL{!({%GD>VxmSGB7D>)CT0BTYzZJvOt5jjSnVxD__)5hElx`AnA6!ZNQ&5yO9mmd z0PanP-hL^9Lw}^O4@;3j;1;5NrfG9+2r*lUl&sRdPw)v#Rnq}O8g)>BauMqzDFTRZ z8Lc|3eK?hv6*8SI!4*c++0vAW0AALgm9iy#U?-*yi44MMJP}FZR0SL=OKZo$5<^^n zu1eGjiID*SyX}TmN~o`EueAgC#Y>sVw+kWrdx+*-QGXiRc##rUk_n*?G#XO6woz>b ztzAtd6SCWGObY4RM)ijLh1aNdL&(}P$Jj2wTP)DT2Cbb7H6bKtOO|mblLLR8*Y%4! zfLhh{o^B}R#w03{;*t?Nk7y=p9U~=xl8u{s&09tad@dO@5l$g)o8{cX`K%FN4hW%r z7jh&;e1EPVSC)tTNMuN=OeIC?*Zad=C~obx8$3TeVXz)11yBwwAsUtVAp2M#4XMQU z84Kdi4^IGqe}DdBa5+@ZH?%fUAt|J|ePhpEVl3H+Y9AuQirAXY0r^lzq?AgZ5~MWh zgR0{cGH4x~pRR4*za2+oh@UZzc|51;`0nvuO@E4Y-s+$lN~O{y{E3uM8pRZ!6lrYh z3p8h$kOQtb3ibEx{kRpYj)|1Pzx$8*IGJPZicvFh>T~-6ry$qqRWVlFO3wxCb tz@;j|==^ z1poj77fD1xRCt{2m`zT^Fbsv~0PNrn+z5#~ux35S;X2$034d0WLdQSP?n{$av6RKM zsbhb3>`ZRAB|Q1~{Q9-VmDe^6dV9Z{qo-jb*Pha-1!SVNU8ACL#kH3#DazV18-u)} z*0Z>cT-!A0Ortx9r;&2ZMk(8can$1xyx%W_S-6d%iD2*$V@4K#Q~& zeHP#}6c!B65r6bq21eUus8G%bM9VY^5Cn$S-l|ZLErVu9_8SOFDh3@d{tI`d4&NyNoy!DSt!GA)ZmF!C4*XHqz#(P*5PE zz$$v}_g-|PNF!@{`e;B+LCa)&8A=l2$~^MOt&x)Adw&cprH2|NN4B? zq>>?MK!4LfwhLG-byN-UY(hpE2om+`?5eb}R{;$$zO`cY9f6ATfWA6Z2+!VsbP wf-0IBh6v3UMu(V1sJ<{d#4K_pUk;Z)$S-{>cn@rw6951J07*qoM6N<$f?aA7$N&HU diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB009.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB009.png index a71de723ab3c2789da9c1bf334a8b88225ece789..21e71a434f01836f2937429d9cfbd4f1cf5174f3 100644 GIT binary patch delta 860 zcmV-i1Ec(t1@i`wB!2;OQb$4nuFf3k0009mNklP5 zMAzICE&)8mo z8_w{dM0vhgAEmY*-@g_0ZQ<|pC(-u(m*3g8vlZuy_3^OZiGS^*@uW9WG%^smq}=5w zy=UAANpN4HJQ`1GjpK$J-Uy1aj3v`omg&=WmXein5q+fIzHNsUJhL+-L`iXH86=`> z8&T%*;Ryf$HrrKX4B7D5!*P3wF@-!tr0AQNoc^b?B>>pOsEzZ*`WPW1#pAjgF`e7bW2cna-BL6-Lw9GL(q`_^^Jhlr7><=1jS_c+SY!YI9QHdlQZ!vE@0A1Koqv}yQ!1yS_&&sQuBZ*~evz}U zWD|myLmpDPws9>5uUwzVCgiZ+g(9SD8`lh_j`vaRYA9MV*H|t9FMEM!Z}7@dxCy~< zj$|1+m=dJ@Y_==bxj#RDoqm7(`uQXq!71Hf%C$mNB88G+oku(ajrKvwKp-iajm>s- zmU_cWMt|D)C>c0VE<$LV=iK78RSOq{;JVWcNjpBL$Cc%posb4=D*pEe+B^ala+hs){Y2?f~RN z9g8QMiuDXLyFkH!;MlmPs%K)Fg3)2XK_ zuKkTlHA3(_Fkh^X=ma;5-WN3O#gLMOHfu#p6+-CYh&swWjCi7rUU5$!T*Mpz{00008j4qcYJo);*-L+A@_V3T@T^rSFi+}QP`s4Gej!GyNjA2j~ zkc})L8?o|7bsm`#$dVYl59fp970>>$hZA`bY8@H zZypth_N*ERdOVPMG$4IABgck$WTpfXi4f0lFXS_h4gnHPtSlhy`OqAKK(P{EH2Y_C z^mnSLeicY_#xok}LoCBlFi{=SMKc2Bbnb4 z473DCfo#{A9tfJRv?z(#>H^6?Y4fcFD7}-8QM96EZ4Cj5E+jda1sLslGIp9kyxsw= z3Rxgtgm_)?-m3Kk1-;KeDnkX3JrRO#Xc)+L0j;Et$|06b$VdZ0c0Kz$0wtSJPYc9? z!e|i=0dvwE=#AAvSo@p5?MA&$m1#Q_NKpz7`jJsK6O1M_Kcb3egwcfN3#w>l7)@xtFe=0>LiL4FA!d>P(r UY%23y@&Et;07*qoM6N<$g43rGHUIzs diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB010.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB010.png index 47ea1762e9fe6b1a340977565677b0e200cb20de..60b174ef18307316b7e0cc1390e06c5558f9fe84 100644 GIT binary patch delta 864 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 Bq@@4= delta 991 zcmV<510ei@2lWS#B!3BTNLh0L0003100031PbI|G0004mX+uL$Nkc;*aB^>EX>4Tx z0C=2zkv&MmKp2MKrb?x>IM_kNAwzYtOBHb}RV;#q(pG5I!Q|3EXws0RxHt-~1qXi? zs}3&Cx;nTDg5VE`vxAeOitZJylGsICv)hJ&mxU6vA;;h!2 ztb0%X!ca+D$$xR3);LmFLK+!}kkLd9by$eeu90FQOXo=s|Cr;?kV__44U8NMXh4PJ z_`(0+cW=$|blgn}C4s>g+y0mU0=qz`W!vA!w%s`a{LjFZ*7G;oz}zS4t)3P=0*1GN zi|d{y?*W%P!03}M8ImLUX$j>r@P0<$R0KwDf#90kw}0+AP9K0g^=kPBI5-3*E0n$N z@$RAizWrO%?cWax;Bw<&-vej>00I|DL_t(|ob8xPPQ)+_hUWn6;11jfi94`n&2hL6 z_dx=&h!i@0{C55{ZdFTJOq=@g#fhD{-7ewD+xzE_HqLBYb?D{wLme|6TWPzbQx}jz zwoRwJaeqeJmt2yRYs+jLvJSPGhuccqszXN_(?L8uJ*%Uwjx~ol5PNhm2#CGGWb{+O zL_tW7&ww%VeHzLr3?u+)rLEOx0S-f9!LR~BpG9EwRfY=Xh(M%FqX0o*e1AROjVu&o z%b?j2{RV>K0g+%JP)7FuG9V)`JSbY@l%1zRiGP-46N+URfuTXM+U?#ZIxiBuH;)SB zZ~h7(==MP7(SY>njBFd`mMIA&k|CbsUdm?zT>>O}u(E)(=S$BJ6pH3d_QDs@L9H?k zhNldH;oV0fZ8-XFq?r?;pg=Szk|WmYqHVf$z*_ofKu~2~AerA1473DCfo$!R2V(Uk zJ%1D}BO|`LKr&GJmC_uO-brci!LXoY77hXuHKe6(2A~8)dzSUn1Y(ujXbNV4cp1_k zs97Lh9RHvow@IW2m<41cL(l~c1KAqTO6saJ#PSIlX&}g|XMabaWDnHC0r|P(Q-L&v-rs)h-B?}S7uo<%M{lzf5G_Dybv+PS9n=^`lx2dP zCDb@F$|}KVLW?7+s3MFev{+C@m0>iY#lol%RfHM~qe4`XGsUvI`~r|Ft$s}@O??0W N002ovPDHLkV1m=S&LRK+ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB013.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB013.png index a2dfb3b6f926fece8c6903b70153905b6c42a532..9d394a8d3b4eb5aa7934a60c8e975ac59c0ac461 100644 GIT binary patch delta 869 zcmV-r1DgE#2mA(*B!2;OQb$4nuFf3k0009vNkl22w4E9C$09&l+=y{J- znmoZpX%KBFQqdyXt5RHAL=%N4NE6+A(9@wS?hUvCnGCb`_-AIrCdb!=?07u(w;p?b z7T|&te9P%Povrs=+pnKLvUHzoYd)E`P_qa$EI9aUmqa_ngjy z;i!}ypK9z2{%2%W8A+zgD$~{2u1-?fLv&GkyB^!zLGyO{1S=`(DuYC#1*?MmwBF4@2ZE;d^b&e;CBq?k| zE*XfF1Js*Ny?^~u1gA(LAC@8mK{=v*rfCah5RxoMO4ic7PlyTgMpKI+O>|&_3L*93 zA_733GTP{{_MxK093kV$0;q-2c(O26A^A)0+fX=w9>C$G2(!2=o% zDXZmNH5IgSUBXSsZo4r>$Z9!Py`k9gE>^oKWKEfKOc#JdF3{u#ty~B-AsEhXjeo4eixwd`?@|MC8K3G$Ez48mNMzvis;O1Ba^U*)c5}y(5w=%Nef-~(Kq-)f zc$i0dDUqh41b<6pAP%Iw>(JVp@{NsFqu|Kb`#b0R5oGSuN+svtu!b#1-Ql+kf-NyL)$pSnXCP)l@0vjED`%i8P4} zPPg?1nyXA|0BUiR>L1JF6s;OvVy&9G_*$g5--m=H)zj`p(RIjRI8sFk!28JZUl>sJl01ND@=HYq|#xH$?Pr7p&`cdRI< z(OyxKlx#v$w_qhcg|HAEX>4Tx z0C=2zkv&MmKp2MKrb?x>IM_kNAwzYtOBHb}RV;#q(pG5I!Q|3EXws0RxHt-~1qXi? zs}3&Cx;nTDg5VE`vxAeOitZJylGsICv)hJ&mxU6vA;;h!2 ztb0%X!ca+D$$xR3);LmFLK+!}kkLd9by$eeu90FQOXo=s|Cr;?kV__44U8NMXh4PJ z_`(0+cW=$|blgn}C4s>g+y0mU0=qz`W!vA!w%s`a{LjFZ*7G;oz}zS4t)3P=0*1GN zi|d{y?*W%P!03}M8ImLUX$j>r@P0<$R0KwDf#90kw}0+AP9K0g^=kPBI5-3*E0n$N z@$RAizWrO%?cWax;Bw<&-vej>00J9HL_t(|ob8xRPQ)+_h35e5;11jfi94`n&2hL6 z_dx=&uoOD}d3Il#w2Gxj(>8VN&yJnx?Y4v`Z||Q!*0}Q8ra>>SALi(3*vPe~G-?5v zXl>W1Xn$OB?IlZ!vbM~|Ag`$PEN&y$HVrz{=nmrH>De3-9d8bEAnVb=ARvwgQ_)WW zlLes}-UG&-_sdZB!ay9*BJD+=1vm|b1;cX$y_bQ}b{Q&^GXl{vjRFLLp|!Uv6lBYw z*^zw*f)Y7r9gL8c%*?PufK*{1P^^Pfb)E$!+kcW>D3L?xkva2jJ0G2waXy+y1!CRn z4FugD$UGX5Hl2}e!`w1c0?A}ZWO$VF6-S2v$re@?5V=3Jh9FS9!k4Z76&=(rBhEz1 zkaLJ<6l!o*2fB^4IVuzsh$yg%Ui-cm-6+!X`}^zhZdhw|0fH)v9I0F*Ff1rpAno&0 z0Dtjdv{0;!%-9+NsX%EXWf`VD)6yP+VL_<`4g!*0$V%M`K+W+#`xro=vq*Gy$fRHe zNR%OM@vZ`i{P+h2{honzh8{rnWC$A2G?48AR!bdKLp+<1Q3irUy?UL6lF7)^1Bsw` zI;H_4$NJV-D}}AU`P-9k1cPZi6^JN|K3x0Bv%9{p90QPVD{T8IKr9Ef$VVWmI;cME zQC4xXmr(tvD4Pj}2+fbIq8VX`(0oA^%?v|?<_n`k%pz1@7#(63xsor3%P*MSt$zNA Rt#JSV002ovPDHLkV1j8d)2aXf diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB014.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB014.png index 05ece84b25e964761af1dca995b231e7059e6d0e..004f4349603414abd6d601d20a4591fb980a7fad 100644 GIT binary patch delta 838 zcmV-M1G)T%1>FXaB!2;OQb$4nuFf3k0009QNkljc>T(J< zK0(|Gs#U99s7;-Ev7L1SH$Fu=_38xV1_6}9phJ)NpIK||=v9K2GbG<|NY2gzT=529 zY6h=2yOZ?n=a27Ib6-k#df$%Mb>F0|`hTRj5>nu{X7FsjXl2KT z(tXAMjH)VQ$&6KH{`~rC>c0K&@;IA)>_n-9vLyYUf<8 zwkj#&gIY2Wntub_N^7g%ieQZt_Rm&iAUH?7|9PHK8H6P(ky6#VPYESq*=Rar$P*oy zpeU>{QbYjQTgDq5(J@?djzc7eP<=E?+!11t0RV73?Ab`s#!`8&902dURDYRDIStkCLp*1i*6`+wOkPP7 zf-h)1qzrxM+6rE|F_9+Zc-V&`WavBB3YCtJ(d}xe+A^2eE&wmNz>^!iaujYtFq|V* zh8k0Ya-OH>M|T2^M%Qb(!IEo*s6+}S!#a<642{l_NuVf0OK*6~NQsY`Q2U$~+K;9m#Ib)r~KJza6@??jprg6DztW_Lm-xK;GtplLUT zlqA&IDq@-tLJvpOQSM^gd&i1$o;g~QQcZ|<3)bROhzNl#NI5(HM_}EPUIMj#q^ryn z$v*&ii4^I*tOucc8N^h{pvd~dUS$H*Rfwq|@*^5xy}7uANCpITuV Q+yDRo07*qoM6N<$g4bSXlk3m@;jJUvb{+cqzPW3pV}E~RR?;FtUV?a6i8Fx6}|rb=ybD_W^4@sf`2N@0%3kzFwhoU1+ug=JrJ~B zc^O&pH3h;z=}*dY%=(*^_SKHY`dR`~HRPo(1F$;tFn)$Wve}`Mf((!>L$axOZP$8& zf_~3HI>QJcYcd2q&@zyv0k5U*RYM}5kVOMQPM!T-fx;Hlmjx0*QH%(i0BHgA&Uz{A z{hPm>MrX50Rq4AFNK+Vn>*xb~>ifnRfP7m~`!50F1!$da27=WgjbV*4Cdg4Dje}7( z6O1OZII4l7)@lcC_2O}B8^4SA!d;y#j?5l1OGdL!G(kcD*ylh07*qo IM6N<$f|I)uGXMYp diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB015.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB015.png index f1152b413e9f500c8deb86361b6c7bf4b3c31178..29c985a0997084f5955b7866cf07fe3e3c98bf90 100644 GIT binary patch delta 840 zcmV-O1GoHz1>XjcB!2;OQb$4nuFf3k0009SNkl=^xz4a@y z`opcO5EQ)q?6J* z=5n=FNf95kl7E5F9N<=3Tm3A8HB#6=v&cYjj#&S*Jfkv*nyf@hQ|mq@l!Qg2>5L&u zbYOy_sOd-%0Z`vE*68r+a8crpkmYI%Tw}CcZC#ZJfDh~UD%ld=uv3c;i44SSz7R>_ zq6*+VvaE6(JUN8UN2A0XAvH1p0FH+}8!4JDmAA?P@PE!rm8q1|(EL8ca<0gRHD5&X zN|+FQL1Q6h=sVL^u*!{zFd@go-W4H3-c*zBp++dZXFcX5| z?5Q%;m==`dJUu^}6R0=3Uds)Z+**iAq);+y=Mjsc-Z3Hx6lG}Xb#ECd@li6+5H3RK zGt0TfI)7Id&IrMMr%fbfd`^#R%e8q*GPJJPVygs6Z?cCwEnjgBU?hQZU)K-^v#ZjOi+&n|y zy}moH=8&>tT;h1{?TRV9cAJx`R!Su!N<&&At$#*_G`4pE-Bm`LfNPF4{ZbycsHZE= z?nNg1eaO&vV$RTBM71Kd51GvurYHgU*MV}KD3()8SDgKwNE#t{9$0U7Cv<{aMe7Zk zc4J6M!a1`dCWR1sIHHbn7vt7DR+O`hkx5E3A=)ii##e|Q0y9WCJN|o6yC=N_TKx!D znL#O%0q_zj(tBA8T=z1Fsggkv^@Y941Zb-eQ$fTR^>c{wzmGyhiO=NAyW=lmcbK0B SVTUsS0000n=^)-dKGoGu$J)bOh&?(O1jK4E8T}M6 zQ4o^jGhmFopN29D0|`JnY3uY^fWuH&Fswk(XAu~Em!U#=MIch9QGg&Yr1qADf?OFi zJEHGEP`u!@!G8#8$;=E}0wfCqfuapg*?k(6XiGMscmbg!bL8EAKe{gxytj`EM0++H z2zot`eKa6_IwRMHd1XohiDZc9xR>&oKz9KWEvzgc?fI@X1c71|zG(H&=%99)7L2D1 znL{k6P=}*B&}$^^5uuz#DQ))XM9GJh|S%x?(>+Jd7%wsy(`LF<*4 zkr7{AAQ>qANokHrf0NQa+R?JUhJZv3X{nn57@c`CewskM*&&jG86aMUcvJCc*Ls42 ze$PNU!weuJ8G;^Y7|7Ou)>8MXA(l_bN&`VoJ^MQXC0kHm7KjCfF(NDh(gNt6)lyjd zH-9^gdS#O;(|0P6rqKG<(Fgd{_k}S4`L@FLp8`Y+P&!=?L{y#fB!2;OQb$4nuFf3k0009VNkl^1i|e<dWP7bMO$6;^F==oRr!==Zm#Uiuj_I41_iS zZl<-_k0Mwjg@1h*MFxT!i1nG}9pdkw*W>SRKfbH75-C@+m!V{E|66g!ki|PNKvCq{ zNFD)@Uou|rK$LiidviBmtbr?x=8Lr}69MpX;-gZwgm>)Zyh9=bF`3RpQaG;yIQJ~8 z90yMfq57zom^~y%1^~c*w`Dy=YfI&=asa2L1#t2zj(-GBPDAy1h-F_9jWni6F~%xK zQA`LP&{#+r`p&czta2?;Ovrw>b$Q6pccvLi2i~IE)lju$F0oty-eQ3zHdy5-%!Hsj zd$J5QrUq$0&o576%%C##uNB91gDE%Xq7o^TjNE?2VyL%|k^qV_H1)cdj1>4N8E6RS zA@rSP-+yA&6@@cGaNTK&q=?V8002ovPDHLkV1nXKjHUnp delta 661 zcmV;G0&4x@2CW5z@;j|==^ z1poj77D+@wRCt{2m`zT^Fbsv~0PNrn+z5#~ux8D1xDNM0f`3&;Q75*aUtgNEilr>3 zr2hHh*rvDJ5}kZ}e*anP%C=31-rm2=)zh(&wx@Jz0h!3Q>r}L^XnV;LQr4B(IOG+z zp2cmXZPTGMt?nS6US7>rPRHA$T!=k67zD)8U>N-pFj){S$9uro^F9q_FAOAr)=7J( zuL7KgqJrTCf`2~C!1(=nzAq`1GXkk$AW&c+2#i*HW1%2dCYv47EQx}%1|y^;D>Lj6 zAS?_7iZwW~`ywbPY!^xt5IQnv-mUke`|7I|WlywE3dDNW8wgrskbN>Bbvh&0MtNnX z1d_>+$nhxUnLvjC$re@>kn((J4MCuIg%5E)3MkUS*ncsBlwcxd$Q_Y?b~M)46p*YTD|H!w*_ns&(*+XE4w)2WfJ7M*O~re=)&msudj`@OdH~szA?Sgo zfou&}Eq`@X4e@+J77YYBb@q1#3R_T53&ew>7!eKuQUa)*wNlvnH-9^gMw6=2cPWsf z(EHX=2l&wU8)E?SZAIvSU!tPW`mdz3Lj_7Z6vjIxi(Dy|!{r}yL5_oGG!7YG00000NkvXXu0mjfWEm1J diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB017.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB017.png index cd54251c5d68882d1cbe79b658fa4688b73e936f..1dab8cf724d31dab5601aabad547aee3bd15cd63 100644 GIT binary patch delta 855 zcmV-d1E~DA1?~orB!2;OQb$4nuFf3k0009hNkl(*}>Vy=zfl?S$#t%chV%S>>+BD-rBm|6D+GUBzQ?NR~aOtYa3SP?)Dx403M$< z9vhNj(T8?hiBW|tM8v2~Ov>};i!}h~#E65-)%NHiBF5eAeQ{E9pE+NwMN-&-Trv=n z1Jp`Ot6z#>iGLLG&r)O{C`YXSS;j&cgeJ?8lGVBo2{B=*(bQwe5*?VJLTGcihyc*H zj5RvEbEqhBN637!2C6ZdFV?O~1VD%NYn5ycFWAwdgChemo=jO%sHg(yN0wENf+vTB z`obtNM~FrS0Kj3tBO^tc8_HYd0BGmA$`s2<$bKJUIe%A_hBaTLn-L8bJEpv|T0`Qy*EV;od7s5;khO?*2gvR6`e$M05 z#+*RC(RC^}SaP)xPzod=Da@n1mPr5p{&V_0nr(Vp z4EMCBE5>O`@eTDs!W--#3> z1kVG@)%J)^P^)OYL6dF_Ly}NusfZ~;NO(939i=YDt#_;_XL&|RQnCq=Zox`?3gIEJ z1W+lxql~x86p_~&ym8tm$krkFM}8=86i@AA+It4@+!nokm8H@IYj*5 hTOlIGd-CPg@ekGApyLz@;j|==^ z1poj7A4x<(RCt{2m`zT_Fbss>0ocJExDgU}V9lE2a2@W01b?eYQ5xGb&ZJGNTFQcw z`sa&d`}Og-MJFGh-+$J+vTf6$xA!k|&2;QY+er}L^X#191l5$^}#v!k$ z%`9$5+BO|J)0z(A>E+d2<#fC~%7xgIgF!&-4JM;s0)_?Ab9@Gjk@wS3MqwZU^iJA4 zeHCCDiVB7o2!HyFfl+rEDU>q;>1CP(2m+(m-m*}TD}!bS`wj#p3eFmgkd~~>uw8&; zVIWYf!701Xg2J|B7fKWmIx;iw*89gRyX97J02wPZHK+5w&YX}0xD|~GA&*+eLnG#H-41bwJJf~2HSsmy#>h0-5L4gzn zR?(~9|NVL1EX3jZf2gf#Ku~2-AQ2GDP74EV!7Py0&hkLedevqLb0uLQ87TEh)vJcl zD~`RiXFFQfR|*Jg$V%OkDJVb-h&S_O{B(gtvjdZYsB=t)L{sr-*V;fqzh@wwVFr+q z3_%Z+27l5T=q>9CSno1Gq8j4)gse0W3Y$p8QV diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB018.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB018.png index a43067fd7322e5629ce5f65fb51668481cc1332c..36b38f7c434388a2fc5ba09f89e3b60eccee1111 100644 GIT binary patch delta 862 zcmV-k1EKt~1@#7yB!2;OQb$4nuFf3k0009oNklRFE&ALHtMhbP)xA5Q@lXGHZM6nOU+xUKM3LYx|AI_UtTh z!U4`oCQoOpoiz6U->;%)A4_-k#OZ9c+iuq4_+U8djFc{QpMPgt^+jgk3!G9Vl?4PyBAaIUY|FevRGK7?@L`qTX-Y3L_50kEx?+p15~O*(J=|&eifaIK5-10jkR0YoK9xwdC<*tprz@s; zR(mzy#0V(~N39HoMsdF-)ar^;KAi*dp^iwYRX!!8RyXX5b3uM^dX|gk{oQdghr|^l zCt_ZoUvP2x(>;&i?TSNq?KUS>t&~be0Kon29e;p5DZl^zv8rn!MTTUTcLCj1MpF=n zax!T9~{-9e?+eoGJt)gNbhAWaNWxg`btKKTwmC$OhC`>eJ6vE oz@;j|==^ z1poj78%ab#RCt{2m`hH?Fbsz00PNrn+z5#~ux8D1xDNM00)NfIQk3!IxAUh>t6Iu} zlKSz*u|2)rF5$_?=l7qr&TQLs=Tr(Zp)Ao{1T|gGH?K%~$Gupo7lA>H!rgO+E zYBP)5p0-Vgjjh6?3~K(tJw06}1A?X3z0xiV;WWZ!|HM8R2u5z>;G8MXn*4rg_s*GSu=LP3Fu z0;}k??|Y{kopi<46d zSG>cQoWYCb<|sY;^XpsI+?UdwJaDnx91r`Q_bWwV{)@>f3S)D$?N{YJ55D`sXi89m4JpkZw zySCVn42?drTT4t-NJE5+u8B#Re>PtMh!YchxL9tE79w0sC-=ok$(?gHUj<1KALNoj z2sz+e>CozzB7ZnUiucD-WDtCgXn)f@<1&PptVBvy>)t20gr!DPiy=*PP=ex!jgcY( zh;JEfbXdpuqQo2_v-t|X#%MNQnJN+B59@Q4Yzgn!iA9G*24OfFi=_CX3TQ``R?Y`Y z4&nNEl&B*lMg{;J_B(H+gvN4ttsLNYUaCy4TnO3kLw_{qiqg>LiQObET8(U8*A zm1-+!<+?;NA&33W6d_GrsaD8!yo+u(gsd%diR}WMa)Bl{XyrK6gittJsth+K2ktzN z+qF7@TBGZ=+)&Alg{VXdCnI(q(HLr-BPD^73@^RrEh8m9P6iqB^7P!28{Dm<2J>fH zU8T?>gn#y3NRgEBEe1+@TrxskvBp*j(zxCp?n3#>*8rv@P#?U6q%cqN+^FwAfxi#G z+5bN9|18EkLy^7M?s-7SFjsn-2lLaDAe=F<%zAL@vd z-12!MLq=?Mc~_hY^24X6sjJs_$I%?Z!ZIxtqcOrYBq!2hWJq&c z7tmZ~LJEA%QE0p?Pg~T|6_@Tsdi#AyQ&(cn2)&5PMbSQFI2x;>1bFK}eVr(kQ%zS~ z`a6+ggwT0lvD_TV3EwJeZ_q+FhMXkQSt??R5W){f+)>}fxb}{f2!!#e0{p5Oog delta 669 zcmV;O0%HC02DJr{B!3BTNLh0L0003100031PbI|G00001b5ch_0olnce*gdgAY({U zO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF*m;eA5aGbhPJOBUy1ZP1_K>z@;j|==^ z1poj79!W$&RCt{2m`zT^Fbsv~0PNrn+z5#~ux8D1xDNM00)MdxiZZeNp8L|IRV`&P zRqCHFj_v8~c8N~j-amh=b!OY9Locr%<{IhPOxsI3bpct(w(C^1&S?9ROOkS3nZ_Zn zsEsUcGi{p=9cc{*@$mF)u5vow9_2#p$-y8X_6C#DF9E}X=s7+D#+LWfP`1KA0_dHz zcls*8G!zvKFMkm983Uv4GEyi<1k%ei2@nKEuf1iVAXf&>4)z@gN)((m7$GfLnPIyC z$-+ROSc6k`p9O_&$u5*AAarDA-mUke`w)Z(0jbj&xi-oxvm_8E zLn6ncl+Oe@1qfSMRY1z~sWk+F;uSu&`e$@VyG#itQh$cbA)ZsH!>kVU8uj*cp`bvD z0;}lN?|Y{kopi?55Fn_sD3HwW9t^Yvvp`xq%L75{m6efA_LfOmbrGX@~vR@DAWfLH(acNX~trOA#7gOr1y00000NkvXXu0mjf D=zSy+ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB020.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB020.png index d5fa533063bb7ec1be5ceb1e1f9022eb461935e2..521476f369782b1752cbc23e7475c9ee0a1e1c56 100644 GIT binary patch delta 860 zcmV-i1Ec)11@i`wB!2;OQb$4nuFf3k0009mNklW?P~L-{4yDK&km6)y2HRuL&#`yms}O6C$KQBt&&~qe zaE4Dg%FET}C_Vf6{Y%!^*Rq|gxLj?Hhy6}`J{*m!ky6w4U4QbdJ}7R41o)hzJRFTn z&Es9!zTtmHR+Wj#)T}bKY$qwj${wOd>8)+stzcQ5KEX?hxym3BUE7E<)5#0~0A9Aw zo;f7LVh`tSB_=9lAtFR=Vp7JRFV+AMCq{j^Ty2gXB0@|jv*M)WjyYefRZ_$Uxnv+T z2e_5iR=*U%8h=OMCxnEhM$-jDmgv9)MG@1HA_5@3 zWvtQR)#0MV9U=3@8o0)2zF4~|5da_7Z&k7-oUs#&4v7rJa5NT4;i3xQGP10496ULM z+M`ioj*u7`004*mj*S#em&#k^0C?x6$`s0J$bKJUIe%A_hBaTLq{K(bz=?1XLZ4aAEmm8la6t&} zJI#=k@qalzt}WN>gk)%4v1P6jB)#4q?zDWxHGnAzlmkmh3iBxc_xGREe~(YRoMeaY zX-`*-de-@BzKIc%6OM>q-+sVgdw(`2ofP+5LaDAe=F=U3e5gZGa>^%-7zwe}rCo6< z&=1Z|*EXkj$I%=TRt#^%3?A;|LJ@eoVhZoP&3{Q%E2R=1pS}VBzfHV|ks*!kT|jr0 z(F{x{GZ;Kj0(AW_gmH^{y5iEkNN>Ln>Dorj8QP1eTomm?hNCgtLUX_ll`BLvR_%hl$HPH?Mey+PA%3@J%yvsAz@;j|==^ z1poj78%ab#RCt{2m`zT^Fbsv~0PNrn+z5#~ux8D1xDNM00)MdxiaP#z&wXjrs+O{t zD)rA7$M*DgyF@2%@1H;3IBn>u8s1_ObLX^ zkj(KckVU8d-ZxC@7Go zz$<$F`_buUCta~M1PH1u3#9Vff`PVR7Rb`h^gz&hMI3=HDm$#TiJdK5t<807*qoM6N<$f@Lol A=>Px# diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB021.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB021.png index 8140a98afe6f341adc8c146b9e48afe40f60fdb2..c0d543c63508a0f5aecfb2d4d3b807305faa2adf 100644 GIT binary patch delta 839 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 diff --git a/Source/Lua/LuaBindingsSystem.cpp b/Source/Lua/LuaBindingsSystem.cpp index 333673a6e5..784cdc4251 100644 --- a/Source/Lua/LuaBindingsSystem.cpp +++ b/Source/Lua/LuaBindingsSystem.cpp @@ -74,6 +74,7 @@ LuaBindingRegisterFunctionDefinitionForType(SystemLuaBindings, Controller) { luabind::value("AIM_SHARP", ControlState::AIM_SHARP), luabind::value("WEAPON_FIRE", ControlState::WEAPON_FIRE), luabind::value("WEAPON_RELOAD", ControlState::WEAPON_RELOAD), + luabind::value("WEAPON_RELOADHELD", ControlState::WEAPON_RELOADHELD), luabind::value("PIE_MENU_OPENED", ControlState::PIE_MENU_OPENED), luabind::value("PIE_MENU_ACTIVE", ControlState::PIE_MENU_ACTIVE), luabind::value("WEAPON_CHANGE_NEXT", ControlState::WEAPON_CHANGE_NEXT), diff --git a/Source/Menus/SettingsInputMappingWizardGUI.cpp b/Source/Menus/SettingsInputMappingWizardGUI.cpp index 4f68ce42c6..4ef95030e2 100644 --- a/Source/Menus/SettingsInputMappingWizardGUI.cpp +++ b/Source/Menus/SettingsInputMappingWizardGUI.cpp @@ -40,8 +40,8 @@ SettingsInputMappingWizardGUI::SettingsInputMappingWizardGUI(GUIControlManager* m_InputWizardScreenBox = dynamic_cast(m_GUIControlManager->GetControl("CollectionBoxInputMappingWizard")); m_InputWizardTitleLabel = dynamic_cast(m_GUIControlManager->GetControl("LabelPlayerInputMappingWizardTitle")); - int dpadDiagramBitampCount = 13; - ContentFile("Base.rte/GUIs/Controllers/D-Pad.png").GetAsAnimation(m_DPadDiagramBitmaps, dpadDiagramBitampCount, COLORCONV_8_TO_32); + int dpadDiagramBitmapCount = 13; + ContentFile("Base.rte/GUIs/Controllers/D-Pad.png").GetAsAnimation(m_DPadDiagramBitmaps, dpadDiagramBitmapCount, COLORCONV_8_TO_32); int analogDiagramBitmapCount = 23; ContentFile("Base.rte/GUIs/Controllers/DualAnalogDS.png").GetAsAnimation(m_DualAnalogDSDiagramBitmaps, analogDiagramBitmapCount, COLORCONV_8_TO_32); @@ -708,6 +708,46 @@ bool SettingsInputMappingWizardGUI::UpdateMouseAndKeyboardConfigSequence() { m_ConfigStepChange = false; } if (!m_ConfigFinished && m_NewInputScheme.CaptureKeyMapping(InputElements::INPUT_WEAPON_CHANGE_NEXT)) { + return true; + } + break; + case 13: + if (m_ConfigStepChange) { + m_WizardManualConfigScreen.ConfigStepDescriptionLabel->SetText("PRIMARY WEAPON HOTKEY"); + m_WizardManualConfigScreen.ConfigStepRecommendedKeyLabel->SetText("[V]"); + m_ConfigStepChange = false; + } + if (!m_ConfigFinished && m_NewInputScheme.CaptureKeyMapping(InputElements::INPUT_WEAPON_PRIMARY_HOTKEY)) { + return true; + } + break; + case 14: + if (m_ConfigStepChange) { + m_WizardManualConfigScreen.ConfigStepDescriptionLabel->SetText("AUXILIARY WEAPON HOTKEY"); + m_WizardManualConfigScreen.ConfigStepRecommendedKeyLabel->SetText("[B]"); + m_ConfigStepChange = false; + } + if (!m_ConfigFinished && m_NewInputScheme.CaptureKeyMapping(InputElements::INPUT_WEAPON_AUXILIARY_HOTKEY)) { + return true; + } + break; + case 15: + if (m_ConfigStepChange) { + m_WizardManualConfigScreen.ConfigStepDescriptionLabel->SetText("PRIMARY ACTOR HOTKEY"); + m_WizardManualConfigScreen.ConfigStepRecommendedKeyLabel->SetText("[X]"); + m_ConfigStepChange = false; + } + if (!m_ConfigFinished && m_NewInputScheme.CaptureKeyMapping(InputElements::INPUT_ACTOR_PRIMARY_HOTKEY)) { + return true; + } + break; + case 16: + if (m_ConfigStepChange) { + m_WizardManualConfigScreen.ConfigStepDescriptionLabel->SetText("AUXILIARY ACTOR HOTKEY"); + m_WizardManualConfigScreen.ConfigStepRecommendedKeyLabel->SetText("[O]"); + m_ConfigStepChange = false; + } + if (!m_ConfigFinished && m_NewInputScheme.CaptureKeyMapping(InputElements::INPUT_ACTOR_AUXILIARY_HOTKEY)) { m_ConfigFinished = true; return true; } @@ -1020,41 +1060,41 @@ bool SettingsInputMappingWizardGUI::UpdateGamepadAnalogConfigSequence() { break; case 16: if (m_ConfigStepChange) { - m_WizardManualConfigScreen.ConfigStepDescriptionLabel->SetText("PICK UP DEVICE"); - m_WizardManualConfigScreen.GamepadConfigStepRecommendedInputLabel->SetText("[D-Pad Up]"); + m_WizardManualConfigScreen.ConfigStepDescriptionLabel->SetText("PRIMARY WEAPON HOTKEY"); + m_WizardManualConfigScreen.GamepadConfigStepRecommendedInputLabel->SetText("[D-Pad Right]"); m_ConfigStepChange = false; } - if (m_NewInputScheme.CaptureJoystickMapping(m_ConfiguringGamepadIndex, InputElements::INPUT_WEAPON_PICKUP)) { + if (m_NewInputScheme.CaptureJoystickMapping(m_ConfiguringGamepadIndex, InputElements::INPUT_WEAPON_PRIMARY_HOTKEY)) { return true; } break; case 17: if (m_ConfigStepChange) { - m_WizardManualConfigScreen.ConfigStepDescriptionLabel->SetText("DROP DEVICE"); + m_WizardManualConfigScreen.ConfigStepDescriptionLabel->SetText("AUXILIARY WEAPON HOTKEY"); m_WizardManualConfigScreen.GamepadConfigStepRecommendedInputLabel->SetText("[D-Pad Down]"); m_ConfigStepChange = false; } - if (m_NewInputScheme.CaptureJoystickMapping(m_ConfiguringGamepadIndex, InputElements::INPUT_WEAPON_DROP)) { + if (m_NewInputScheme.CaptureJoystickMapping(m_ConfiguringGamepadIndex, InputElements::INPUT_WEAPON_AUXILIARY_HOTKEY)) { return true; } break; case 18: if (m_ConfigStepChange) { - m_WizardManualConfigScreen.ConfigStepDescriptionLabel->SetText("NEXT DEVICE"); - m_WizardManualConfigScreen.GamepadConfigStepRecommendedInputLabel->SetText("[D-Pad Right]"); + m_WizardManualConfigScreen.ConfigStepDescriptionLabel->SetText("PRIMARY ACTOR HOTKEY"); + m_WizardManualConfigScreen.GamepadConfigStepRecommendedInputLabel->SetText("[D-Pad Up]"); m_ConfigStepChange = false; } - if (m_NewInputScheme.CaptureJoystickMapping(m_ConfiguringGamepadIndex, InputElements::INPUT_WEAPON_CHANGE_NEXT)) { + if (m_NewInputScheme.CaptureJoystickMapping(m_ConfiguringGamepadIndex, InputElements::INPUT_ACTOR_PRIMARY_HOTKEY)) { return true; } break; case 19: if (m_ConfigStepChange) { - m_WizardManualConfigScreen.ConfigStepDescriptionLabel->SetText("PREVIOUS DEVICE"); + m_WizardManualConfigScreen.ConfigStepDescriptionLabel->SetText("AUXILIARY ACTOR HOTKEY"); m_WizardManualConfigScreen.GamepadConfigStepRecommendedInputLabel->SetText("[D-Pad Left]"); m_ConfigStepChange = false; } - if (m_NewInputScheme.CaptureJoystickMapping(m_ConfiguringGamepadIndex, InputElements::INPUT_WEAPON_CHANGE_PREV)) { + if (m_NewInputScheme.CaptureJoystickMapping(m_ConfiguringGamepadIndex, InputElements::INPUT_ACTOR_AUXILIARY_HOTKEY)) { return true; } break; diff --git a/Source/Menus/SettingsInputMappingWizardGUI.h b/Source/Menus/SettingsInputMappingWizardGUI.h index aafe27004b..1b706b8d26 100644 --- a/Source/Menus/SettingsInputMappingWizardGUI.h +++ b/Source/Menus/SettingsInputMappingWizardGUI.h @@ -90,7 +90,7 @@ namespace RTE { }; static constexpr int m_KeyboardConfigSteps = 16; //!< The step count for keyboard only manual configuration. - static constexpr int m_MouseAndKeyboardConfigSteps = 11; //!< The step count for mouse + keyboard manual configuration. + static constexpr int m_MouseAndKeyboardConfigSteps = 17; //!< The step count for mouse + keyboard manual configuration. static constexpr int m_DPadConfigSteps = 12; //!< The step count for DPad type gamepad manual configuration. static constexpr int m_DualAnalogConfigSteps = 22; //!< The step count for DualAnalog type gamepad manual configuration. diff --git a/Source/System/Controller.cpp b/Source/System/Controller.cpp index 6080aaf697..2e7c463a11 100644 --- a/Source/System/Controller.cpp +++ b/Source/System/Controller.cpp @@ -355,6 +355,9 @@ void Controller::UpdatePlayerPieMenuInput(std::array Date: Tue, 3 Dec 2024 13:59:57 -0600 Subject: [PATCH 03/10] Fix insufficient input mapping menu height obscuring ~12 inputs, and made all visible to all devices. --- Data/Base.rte/GUIs/SettingsGUI.ini | 26 ++++++++++++------------ Data/Base.rte/GUIs/SettingsPauseGUI.ini | 26 ++++++++++++------------ Source/Menus/SettingsInputMappingGUI.cpp | 2 +- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/Data/Base.rte/GUIs/SettingsGUI.ini b/Data/Base.rte/GUIs/SettingsGUI.ini index e2b1343156..cea632ea4d 100644 --- a/Data/Base.rte/GUIs/SettingsGUI.ini +++ b/Data/Base.rte/GUIs/SettingsGUI.ini @@ -1612,7 +1612,7 @@ Parent = CollectionBoxScrollingMappingClipBox X = 0 Y = 0 Width = 440 -Height = 369 +Height = 540 Visible = True Enabled = True Name = CollectionBoxScrollingMappingBox @@ -2465,7 +2465,7 @@ Text = [InputKey] [LabelInputName29] ControlType = LABEL Parent = CollectionBoxScrollingMappingBox -X = 215 +X = 5 Y = 355 Width = 110 Height = 20 @@ -2481,7 +2481,7 @@ VAlignment = middle [ButtonInputKey29] ControlType = BUTTON Parent = CollectionBoxScrollingMappingBox -X = 330 +X = 120 Y = 355 Width = 95 Height = 20 @@ -2496,7 +2496,7 @@ Text = [InputKey] ControlType = LABEL Parent = CollectionBoxScrollingMappingBox X = 215 -Y = 380 +Y = 355 Width = 110 Height = 20 Visible = True @@ -2512,7 +2512,7 @@ VAlignment = middle ControlType = BUTTON Parent = CollectionBoxScrollingMappingBox X = 330 -Y = 380 +Y = 355 Width = 95 Height = 20 Visible = True @@ -2525,7 +2525,7 @@ Text = [InputKey] [LabelInputName31] ControlType = LABEL Parent = CollectionBoxScrollingMappingBox -X = 215 +X = 5 Y = 380 Width = 110 Height = 20 @@ -2541,7 +2541,7 @@ VAlignment = middle [ButtonInputKey31] ControlType = BUTTON Parent = CollectionBoxScrollingMappingBox -X = 330 +X = 120 Y = 380 Width = 95 Height = 20 @@ -2585,8 +2585,8 @@ Text = [InputKey] [LabelInputName33] ControlType = LABEL Parent = CollectionBoxScrollingMappingBox -X = 215 -Y = 380 +X = 5 +Y = 405 Width = 110 Height = 20 Visible = True @@ -2601,8 +2601,8 @@ VAlignment = middle [ButtonInputKey33] ControlType = BUTTON Parent = CollectionBoxScrollingMappingBox -X = 330 -Y = 380 +X = 120 +Y = 405 Width = 95 Height = 20 Visible = True @@ -2616,7 +2616,7 @@ Text = [InputKey] ControlType = LABEL Parent = CollectionBoxScrollingMappingBox X = 215 -Y = 380 +Y = 405 Width = 110 Height = 20 Visible = True @@ -2632,7 +2632,7 @@ VAlignment = middle ControlType = BUTTON Parent = CollectionBoxScrollingMappingBox X = 330 -Y = 380 +Y = 405 Width = 95 Height = 20 Visible = True diff --git a/Data/Base.rte/GUIs/SettingsPauseGUI.ini b/Data/Base.rte/GUIs/SettingsPauseGUI.ini index 39b59564b3..0b33f6117d 100644 --- a/Data/Base.rte/GUIs/SettingsPauseGUI.ini +++ b/Data/Base.rte/GUIs/SettingsPauseGUI.ini @@ -1613,7 +1613,7 @@ Parent = CollectionBoxScrollingMappingClipBox X = 0 Y = 0 Width = 440 -Height = 369 +Height = 540 Visible = True Enabled = True Name = CollectionBoxScrollingMappingBox @@ -2466,7 +2466,7 @@ Text = [InputKey] [LabelInputName29] ControlType = LABEL Parent = CollectionBoxScrollingMappingBox -X = 215 +X = 5 Y = 355 Width = 110 Height = 20 @@ -2482,7 +2482,7 @@ VAlignment = middle [ButtonInputKey29] ControlType = BUTTON Parent = CollectionBoxScrollingMappingBox -X = 330 +X = 120 Y = 355 Width = 95 Height = 20 @@ -2497,7 +2497,7 @@ Text = [InputKey] ControlType = LABEL Parent = CollectionBoxScrollingMappingBox X = 215 -Y = 380 +Y = 355 Width = 110 Height = 20 Visible = True @@ -2513,7 +2513,7 @@ VAlignment = middle ControlType = BUTTON Parent = CollectionBoxScrollingMappingBox X = 330 -Y = 380 +Y = 355 Width = 95 Height = 20 Visible = True @@ -2526,7 +2526,7 @@ Text = [InputKey] [LabelInputName31] ControlType = LABEL Parent = CollectionBoxScrollingMappingBox -X = 215 +X = 5 Y = 380 Width = 110 Height = 20 @@ -2542,7 +2542,7 @@ VAlignment = middle [ButtonInputKey31] ControlType = BUTTON Parent = CollectionBoxScrollingMappingBox -X = 330 +X = 120 Y = 380 Width = 95 Height = 20 @@ -2586,8 +2586,8 @@ Text = [InputKey] [LabelInputName33] ControlType = LABEL Parent = CollectionBoxScrollingMappingBox -X = 215 -Y = 380 +X = 5 +Y = 405 Width = 110 Height = 20 Visible = True @@ -2602,8 +2602,8 @@ VAlignment = middle [ButtonInputKey33] ControlType = BUTTON Parent = CollectionBoxScrollingMappingBox -X = 330 -Y = 380 +X = 120 +Y = 405 Width = 95 Height = 20 Visible = True @@ -2617,7 +2617,7 @@ Text = [InputKey] ControlType = LABEL Parent = CollectionBoxScrollingMappingBox X = 215 -Y = 380 +Y = 405 Width = 110 Height = 20 Visible = True @@ -2633,7 +2633,7 @@ VAlignment = middle ControlType = BUTTON Parent = CollectionBoxScrollingMappingBox X = 330 -Y = 380 +Y = 405 Width = 95 Height = 20 Visible = True diff --git a/Source/Menus/SettingsInputMappingGUI.cpp b/Source/Menus/SettingsInputMappingGUI.cpp index 6dc12f8a47..683a3492b2 100644 --- a/Source/Menus/SettingsInputMappingGUI.cpp +++ b/Source/Menus/SettingsInputMappingGUI.cpp @@ -123,7 +123,7 @@ void SettingsInputMappingGUI::UpdateMappingButtonLabels() { m_InputMapButton[i]->SetText(!inputDescription.empty() ? "[" + inputDescription + "]" : "[Undefined]"); } // Adjust the scrolling box scroll range to hide mappings that are only relevant to gamepads. - m_InputMapScrollingBoxScrollbar->SetMaximum(m_InputMapScrollingBox->GetHeight() - ((m_ConfiguringPlayerInputScheme->GetDevice() < InputDevice::DEVICE_GAMEPAD_1) ? 141 : -8)); + m_InputMapScrollingBoxScrollbar->SetMaximum(m_InputMapScrollingBox->GetHeight()); m_InputMapScrollingBoxScrollbar->SetPageSize(m_InputMapScrollingBoxScrollbar->GetMaximum() / 2); } From e0cca096b9af795d554474cdc290e6e90372fea6 Mon Sep 17 00:00:00 2001 From: pawnishoovy <54544349+pawnishoovy@users.noreply.github.com> Date: Wed, 4 Dec 2024 00:54:28 +0200 Subject: [PATCH 04/10] GetMOsAtPosition, currently-untestable CastAllMOsRay --- CHANGELOG.md | 2 + Source/Entities/MOPixel.cpp | 4 +- Source/Entities/MOPixel.h | 3 +- Source/Entities/MOSprite.cpp | 4 +- Source/Entities/MOSprite.h | 3 +- Source/Entities/MovableObject.h | 3 +- Source/Lua/LuaAdapterDefinitions.h | 20 ++++- Source/Lua/LuaAdapters.cpp | 9 +++ Source/Lua/LuaBindingsManagers.cpp | 3 + Source/Managers/MovableMan.cpp | 6 ++ Source/Managers/MovableMan.h | 8 ++ Source/Managers/SceneMan.cpp | 102 +++++++++++++++++++++++++ Source/Managers/SceneMan.h | 12 +++ Source/System/SpatialPartitionGrid.cpp | 26 +++++++ Source/System/SpatialPartitionGrid.h | 8 ++ 15 files changed, 202 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc4def596f..5ae867c394 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -83,6 +83,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - New `ACraft` INI and Lua (R/W) property `CanEnterOrbit`, which determines whether a craft can enter orbit (and refund gold appropriately) or not. If false, default out-of-bounds deletion logic applies. +- New `MovableMan` function `GetMOsAtPosition(posX, posY, ignoreTeam, getsHitByMOsOnly)` that will return an iterator with all the `MovableObject`s that intersect that exact position with their sprite. +
Changed diff --git a/Source/Entities/MOPixel.cpp b/Source/Entities/MOPixel.cpp index 4768b4cf62..534541929b 100644 --- a/Source/Entities/MOPixel.cpp +++ b/Source/Entities/MOPixel.cpp @@ -140,8 +140,8 @@ void MOPixel::SetTrailLength(int trailLength) { m_Atom->SetTrailLength(trailLength); } -bool MOPixel::HitTestAtPixel(int pixelX, int pixelY) const { - if (!GetsHitByMOs() || GetRootParent()->GetTraveling()) { +bool MOPixel::HitTestAtPixel(int pixelX, int pixelY, bool validOnly) const { + if (validOnly && (!GetsHitByMOs() || GetRootParent()->GetTraveling())) { return false; } diff --git a/Source/Entities/MOPixel.h b/Source/Entities/MOPixel.h index c451790b51..e64d28b078 100644 --- a/Source/Entities/MOPixel.h +++ b/Source/Entities/MOPixel.h @@ -125,8 +125,9 @@ namespace RTE { /// Whether a set of X, Y coordinates overlap us (in world space). /// @param pixelX The given X coordinate, in world space. /// @param pixelY The given Y coordinate, in world space. + /// @param validOnly Whether to return false if this MO isn't validly owned by MovableMan or not. /// @return Whether the given coordinate overlap us. - bool HitTestAtPixel(int pixelX, int pixelY) const override; + bool HitTestAtPixel(int pixelX, int pixelY, bool validOnly = true) const override; #pragma endregion #pragma region Virtual Override Methods diff --git a/Source/Entities/MOSprite.cpp b/Source/Entities/MOSprite.cpp index 235176c0b2..efd9fdd72c 100644 --- a/Source/Entities/MOSprite.cpp +++ b/Source/Entities/MOSprite.cpp @@ -240,8 +240,8 @@ void MOSprite::Destroy(bool notInherited) { Clear(); } -bool MOSprite::HitTestAtPixel(int pixelX, int pixelY) const { - if (!GetsHitByMOs() || GetRootParent()->GetTraveling()) { +bool MOSprite::HitTestAtPixel(int pixelX, int pixelY, bool validOnly) const { + if (validOnly && (!GetsHitByMOs() || GetRootParent()->GetTraveling())) { return false; } diff --git a/Source/Entities/MOSprite.h b/Source/Entities/MOSprite.h index b5b1fe1ae9..9c84ee79da 100644 --- a/Source/Entities/MOSprite.h +++ b/Source/Entities/MOSprite.h @@ -127,8 +127,9 @@ namespace RTE { /// Whether a set of X, Y coordinates overlap us (in world space). /// @param pixelX The given X coordinate, in world space. /// @param pixelY The given Y coordinate, in world space. + /// @param validOnly Whether to return false if this MO isn't validly owned by MovableMan or not. /// @return Whether the given coordinate overlap us. - bool HitTestAtPixel(int pixelX, int pixelY) const override; + bool HitTestAtPixel(int pixelX, int pixelY, bool validOnly = true) const override; /// Gets the current angular velocity of this MovableObject. Positive is /// a counter-clockwise rotation. diff --git a/Source/Entities/MovableObject.h b/Source/Entities/MovableObject.h index 580b914570..6bbc73c0de 100644 --- a/Source/Entities/MovableObject.h +++ b/Source/Entities/MovableObject.h @@ -588,8 +588,9 @@ namespace RTE { /// Whether a set of X, Y coordinates overlap us (in world space). /// @param pixelX The given X coordinate, in world space. /// @param pixelY The given Y coordinate, in world space. + /// @param validOnly Whether to return false if this MO isn't validly owned by MovableMan or not. /// @return Whether the given coordinate overlap us. - virtual bool HitTestAtPixel(int pixelX, int pixelY) const { return false; } + virtual bool HitTestAtPixel(int pixelX, int pixelY, bool validOnly = true) const { return false; } /// Shows whether this is or carries a specifically named object in its /// inventory. Also looks through the inventories of potential passengers, diff --git a/Source/Lua/LuaAdapterDefinitions.h b/Source/Lua/LuaAdapterDefinitions.h index 8777761765..3e59ae2fe2 100644 --- a/Source/Lua/LuaAdapterDefinitions.h +++ b/Source/Lua/LuaAdapterDefinitions.h @@ -517,7 +517,7 @@ namespace RTE { /// first, g_NoMOID will be returned. /// @param start The starting position. /// @param ray The vector to trace along. - /// @param ignoredMOIDs A vector of MOIDs to ignore. Any child MO's of this MOID will also be ignored. (default: g_NoMOID) + /// @param ignoreMOIDs A vector of MOIDs to ignore. Any child MO's of this MOID will also be ignored. (default: g_NoMOID) /// @param ignoreTeam To enable ignoring of all MOIDs associated with an object of a specific (default: Activity::NoTeam) /// team which also has team ignoring enabled itself. /// @param ignoreMaterial A specific material ID to ignore hits with. (default: 0) @@ -525,14 +525,14 @@ namespace RTE { /// @param skip For every pixel checked along the line, how many to skip between them (default: 0) /// for optimization reasons. 0 = every pixel is checked. /// @return The MOID of the hit non-ignored MO, or g_NoMOID if terrain or no MO was hit. - static MOID CastMORay1(SceneMan& sceneMan, const Vector& start, const Vector& ray, const luabind::object& ignoredMOIDs, int ignoreTeam = Activity::NoTeam, unsigned char ignoreMaterial = 0, bool ignoreAllTerrain = false, int skip = 0); + static MOID CastMORay1(SceneMan& sceneMan, const Vector& start, const Vector& ray, const luabind::object& ignoreMOIDs, int ignoreTeam = Activity::NoTeam, unsigned char ignoreMaterial = 0, bool ignoreAllTerrain = false, int skip = 0); /// Traces along a vector and returns MOID of the first non-ignored /// non-NoMOID MO encountered. If a non-air terrain pixel is encountered /// first, g_NoMOID will be returned. /// @param start The starting position. /// @param ray The vector to trace along. - /// @param ignoredMOID An MOID to ignore. Any child MO's of this MOID will also be ignored. (default: g_NoMOID) + /// @param ignoreMOID An MOID to ignore. Any child MO's of this MOID will also be ignored. (default: g_NoMOID) /// @param ignoreTeam To enable ignoring of all MOIDs associated with an object of a specific (default: Activity::NoTeam) /// team which also has team ignoring enabled itself. /// @param ignoreMaterial A specific material ID to ignore hits with. (default: 0) @@ -540,8 +540,20 @@ namespace RTE { /// @param skip For every pixel checked along the line, how many to skip between them (default: 0) /// for optimization reasons. 0 = every pixel is checked. /// @return The MOID of the hit non-ignored MO, or g_NoMOID if terrain or no MO was hit. - static MOID CastMORay2(SceneMan& sceneMan, const Vector& start, const Vector& ray, MOID ignoredMOID = g_NoMOID, int ignoreTeam = Activity::NoTeam, unsigned char ignoreMaterial = 0, bool ignoreAllTerrain = false, int skip = 0); + static MOID CastMORay2(SceneMan& sceneMan, const Vector& start, const Vector& ray, MOID ignoreMOID = g_NoMOID, int ignoreTeam = Activity::NoTeam, unsigned char ignoreMaterial = 0, bool ignoreAllTerrain = false, int skip = 0); + /// Traces along a vector and returns a vector of all MOs encountered. + /// @param start The starting position. + /// @param ray The vector to trace along. + /// @param ignoreMOIDs A vector of MOIDs to ignore. Any child MOs of an MOID will also be ignored. (default: g_NoMOID) + /// @param ignoreTeam To enable ignoring of all MOIDs associated with an object of a specific team (default: Activity::NoTeam) + /// @param ignoreMaterial A specific material ID to ignore hits with. (default: 0) + /// @param ignoreAllTerrain Whether to ignore all terrain hits or not. (default: false) + /// @param skip For every pixel checked along the line, how many to skip between them (default: 0) + /// for optimization reasons. 0 = every pixel is checked. + /// @return A vector of pointers to all MovableObjects met along the ray, who aren't ignored. + static const std::vector* CastAllMOsRay(SceneMan& sceneMan, const Vector& start, const Vector& ray, const luabind::object& ignoreMOIDs, int ignoreTeam = Activity::NoTeam, unsigned char ignoreMaterial = 0, bool ignoreAllTerrain = false, int skip = 0); + /// Traces along a vector and returns the length of how far the trace went /// without hitting any non-ignored terrain material or MOID at all. /// @param start The starting position. diff --git a/Source/Lua/LuaAdapters.cpp b/Source/Lua/LuaAdapters.cpp index 4dc24af987..a362d1c961 100644 --- a/Source/Lua/LuaAdapters.cpp +++ b/Source/Lua/LuaAdapters.cpp @@ -626,6 +626,15 @@ MOID LuaAdaptersSceneMan::CastMORay2(SceneMan& sceneMan, const Vector& start, co return sceneMan.CastMORay(start, ray, ignoreMOIDs, ignoreTeam, ignoreMaterial, ignoreAllTerrain, skip); } +const std::vector* LuaAdaptersSceneMan::CastAllMOsRay(SceneMan& sceneMan, const Vector& start, const Vector& ray, const luabind::object& ignoreMOIDs, int ignoreTeam, unsigned char ignoreMaterial, bool ignoreAllTerrain, int skip) { + std::vector ptrVec = ConvertLuaTableToVectorOfType(ignoreMOIDs); + std::vector ignoreMOIDsVec; + for (auto ptr : ptrVec) { + ignoreMOIDsVec.push_back(*ptr); + } + return sceneMan.CastAllMOsRay(start, ray, ignoreMOIDsVec, ignoreTeam, ignoreMaterial, ignoreAllTerrain, skip); +} + float LuaAdaptersSceneMan::CastObstacleRay1(SceneMan& sceneMan, const Vector& start, const Vector& ray, Vector& obstaclePos, Vector& freePos, const luabind::object& ignoreMOIDs, int ignoreTeam, unsigned char ignoreMaterial, int skip) { std::vector ptrVec = ConvertLuaTableToVectorOfType(ignoreMOIDs); std::vector ignoreMOIDsVec; diff --git a/Source/Lua/LuaBindingsManagers.cpp b/Source/Lua/LuaBindingsManagers.cpp index a03fc6b6c0..b5d1329524 100644 --- a/Source/Lua/LuaBindingsManagers.cpp +++ b/Source/Lua/LuaBindingsManagers.cpp @@ -168,6 +168,9 @@ LuaBindingRegisterFunctionDefinitionForType(ManagerLuaBindings, MovableMan) { .def("GetMOsInRadius", (const std::vector* (MovableMan::*)(const Vector& centre, float radius) const) & MovableMan::GetMOsInRadius, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) .def("GetMOsInRadius", (const std::vector* (MovableMan::*)(const Vector& centre, float radius, int ignoreTeam) const) & MovableMan::GetMOsInRadius, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) .def("GetMOsInRadius", (const std::vector* (MovableMan::*)(const Vector& centre, float radius, int ignoreTeam, bool getsHitByMOsOnly) const) & MovableMan::GetMOsInRadius, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) + .def("GetMOsAtPosition", (const std::vector* (MovableMan::*)(int pixelX, int pixelY) const) & MovableMan::GetMOsAtPosition, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) + .def("GetMOsAtPosition", (const std::vector* (MovableMan::*)(int pixelX, int pixelY, int ignoreTeam) const) & MovableMan::GetMOsAtPosition, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) + .def("GetMOsAtPosition", (const std::vector* (MovableMan::*)(int pixelX, int pixelY, int ignoreTeam, bool getsHitByMOsOnly) const) & MovableMan::GetMOsAtPosition, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator) .def("SendGlobalMessage", &LuaAdaptersMovableMan::SendGlobalMessage1) .def("SendGlobalMessage", &LuaAdaptersMovableMan::SendGlobalMessage2) diff --git a/Source/Managers/MovableMan.cpp b/Source/Managers/MovableMan.cpp index 3692c6b0d0..ca883f532b 100644 --- a/Source/Managers/MovableMan.cpp +++ b/Source/Managers/MovableMan.cpp @@ -193,6 +193,12 @@ const std::vector* MovableMan::GetMOsInRadius(const Vector& cent return vectorForLua; } +const std::vector* MovableMan::GetMOsAtPosition(int pixelX, int pixelY, int ignoreTeam, bool getsHitByMOsOnly) const { + std::vector* vectorForLua = new std::vector(); + *vectorForLua = std::move(g_SceneMan.GetMOIDGrid().GetMOsAtPosition(pixelX, pixelY, ignoreTeam, getsHitByMOsOnly)); + return vectorForLua; +} + void MovableMan::PurgeAllMOs() { for (std::deque::iterator itr = m_Actors.begin(); itr != m_Actors.end(); ++itr) { (*itr)->DestroyScriptState(); diff --git a/Source/Managers/MovableMan.h b/Source/Managers/MovableMan.h index cf3dfa0196..408392ef46 100644 --- a/Source/Managers/MovableMan.h +++ b/Source/Managers/MovableMan.h @@ -539,6 +539,14 @@ namespace RTE { /// @return Pointers to the MOs that are within the specified radius of the given centre position. const std::vector* GetMOsInRadius(const Vector& centre, float radius) const { return GetMOsInRadius(centre, radius, Activity::NoTeam); } + /// Gets pointers to the MOs that are at a particular position in the Scene. + /// @param pixelX The X coordinate of the Scene pixel to test. + /// @param pixelY The Y coordinate of the Scene pixel to test. + /// @param ignoreTeam The team to ignore. + /// @param getsHitByMOsOnly Whether to only include MOs that have GetsHitByMOs enabled, or all MOs. + /// @return Pointers to the MOs that are within the specified radius of the given centre position. + const std::vector* GetMOsAtPosition(int pixelX, int pixelY, int ignoreTeam, bool getsHitByMOsOnly) const; + /// Runs a lua function on all MOs in the simulation, including owned child MOs. void RunLuaFunctionOnAllMOs(const std::string& functionName, bool includeAdded, const std::vector& functionEntityArguments = std::vector(), const std::vector& functionLiteralArguments = std::vector(), const std::vector& functionObjectArguments = std::vector()); diff --git a/Source/Managers/SceneMan.cpp b/Source/Managers/SceneMan.cpp index b57dea5198..b906f25814 100644 --- a/Source/Managers/SceneMan.cpp +++ b/Source/Managers/SceneMan.cpp @@ -2095,6 +2095,108 @@ bool SceneMan::CastFindMORay(const Vector& start, const Vector& ray, MOID target return false; } +const std::vector* SceneMan::CastAllMOsRay(const Vector& start, const Vector& ray, const std::vector& ignoreMOIDs, int ignoreTeam, unsigned char ignoreMaterial, bool ignoreAllTerrain, int skip) const { + std::vector* vectorForLua = new std::vector(); + + const SpatialPartitionGrid& partitionGrid = GetMOIDGrid(); + + int hitCount = 0, error, dom, sub, domSteps, skipped = skip; + int intPos[2], delta[2], delta2[2], increment[2]; + unsigned char hitTerrain = 0; + + intPos[X] = std::floor(start.m_X); + intPos[Y] = std::floor(start.m_Y); + delta[X] = std::floor(start.m_X + ray.m_X) - intPos[X]; + delta[Y] = std::floor(start.m_Y + ray.m_Y) - intPos[Y]; + + if (delta[X] == 0 && delta[Y] == 0) + return vectorForLua; + + ///////////////////////////////////////////////////// + // Bresenham's line drawing algorithm preparation + + if (delta[X] < 0) { + increment[X] = -1; + delta[X] = -delta[X]; + } else + increment[X] = 1; + + if (delta[Y] < 0) { + increment[Y] = -1; + delta[Y] = -delta[Y]; + } else + increment[Y] = 1; + + // Scale by 2, for better accuracy of the error at the first pixel + delta2[X] = delta[X] << 1; + delta2[Y] = delta[Y] << 1; + + // If X is dominant, Y is submissive, and vice versa. + if (delta[X] > delta[Y]) { + dom = X; + sub = Y; + } else { + dom = Y; + sub = X; + } + + error = delta2[sub] - delta[dom]; + + ///////////////////////////////////////////////////// + // Bresenham's line drawing algorithm execution + + for (domSteps = 0; domSteps < delta[dom]; ++domSteps) { + intPos[dom] += increment[dom]; + if (error >= 0) { + intPos[sub] += increment[sub]; + error -= delta2[dom]; + } + error += delta2[sub]; + + // Only check pixel if we're not due to skip any, or if this is the last pixel + if (++skipped > skip || domSteps + 1 == delta[dom]) { + + // Scene wrapping, if necessary + g_SceneMan.WrapPosition(intPos[X], intPos[Y]); + + // Detect MOs + std::vector hitMOs; + hitMOs = std::move(partitionGrid.GetMOsAtPosition(intPos[X], intPos[Y], ignoreTeam, false)); + + // Loop through the gotten MOs and check if we're ignoring their IDs - if not, put them onto our return vector + for (MovableObject* mo : hitMOs) { + MOID moid = mo->GetID(); + for (auto ignoredMOID : ignoreMOIDs) { + if (moid != ignoredMOID && g_MovableMan.GetRootMOID(moid) != ignoredMOID) { + // Save last ray pos + s_LastRayHitPos.SetXY(intPos[X], intPos[Y]); + vectorForLua->push_back(mo); + } + } + } + + // Detect terrain hits + if (!ignoreAllTerrain) { + hitTerrain = g_SceneMan.GetTerrMatter(intPos[X], intPos[Y]); + if (hitTerrain != g_MaterialAir && hitTerrain != ignoreMaterial) { + // Save last ray pos + s_LastRayHitPos.SetXY(intPos[X], intPos[Y]); + return vectorForLua; + } + } + + skipped = 0; + + if (m_pDebugLayer && m_DrawRayCastVisualizations) { + m_pDebugLayer->SetPixel(intPos[X], intPos[Y], 13); + } + } + } + + // Didn't hit anything but air + return vectorForLua; +} + float SceneMan::CastObstacleRay(const Vector& start, const Vector& ray, Vector& obstaclePos, Vector& freePos, const std::vector& ignoreMOIDs, int ignoreTeam, unsigned char ignoreMaterial, int skip) { int hitCount = 0, error, dom, sub, domSteps, skipped = skip; int intPos[2], delta[2], delta2[2], increment[2]; diff --git a/Source/Managers/SceneMan.h b/Source/Managers/SceneMan.h index f804b54b36..801af44420 100644 --- a/Source/Managers/SceneMan.h +++ b/Source/Managers/SceneMan.h @@ -703,6 +703,18 @@ namespace RTE { /// @return Whether the target MOID was found along the ray or not. bool CastFindMORay(const Vector& start, const Vector& ray, MOID targetMOID, Vector& resultPos, unsigned char ignoreMaterial = 0, bool ignoreAllTerrain = false, int skip = 0); + /// Traces along a vector and returns a vector of all MOs encountered. + /// @param start The starting position. + /// @param ray The vector to trace along. + /// @param ignoreMOIDs A vector of MOIDs to ignore. Any child MOs of an MOID will also be ignored. (default: g_NoMOID) + /// @param ignoreTeam To enable ignoring of all MOIDs associated with an object of a specific team (default: Activity::NoTeam) + /// @param ignoreMaterial A specific material ID to ignore hits with. (default: 0) + /// @param ignoreAllTerrain Whether to ignore all terrain hits or not. (default: false) + /// @param skip For every pixel checked along the line, how many to skip between them (default: 0) + /// for optimization reasons. 0 = every pixel is checked. + /// @return A vector of pointers to all MovableObjects met along the ray, who aren't ignored. + const std::vector* CastAllMOsRay(const Vector& start, const Vector& ray, const std::vector& ignoreMOIDs = {g_NoMOID}, int ignoreTeam = Activity::NoTeam, unsigned char ignoreMaterial = 0, bool ignoreAllTerrain = false, int skip = 0) const; + /// Traces along a vector and returns the length of how far the trace went /// without hitting any non-ignored terrain material or MOID at all. /// @param start The starting position. diff --git a/Source/System/SpatialPartitionGrid.cpp b/Source/System/SpatialPartitionGrid.cpp index d65000e2e6..01099f5bb2 100644 --- a/Source/System/SpatialPartitionGrid.cpp +++ b/Source/System/SpatialPartitionGrid.cpp @@ -176,6 +176,32 @@ const std::vector& SpatialPartitionGrid::GetMOIDsAtPosition(int x, int y, return cells[ignoreTeam + 1][GetCellIdForCellCoords(cellX, cellY)]; } +std::vector SpatialPartitionGrid::GetMOsAtPosition(int x, int y, int ignoreTeam, bool getsHitByMOsOnly) const { + RTEAssert(ignoreTeam >= Activity::NoTeam && ignoreTeam < Activity::MaxTeamCount, "Invalid ignoreTeam given to SpatialPartitioningGrid::GetMOsAtPosition()!"); + + std::unordered_set potentialMOIDs; + + int cellX = x / m_CellSize; + int cellY = y / m_CellSize; + + // Note - GetCellIdForCellCoords accounts for wrapping automatically, so we don't have to deal with it here. + auto& cells = getsHitByMOsOnly ? m_PhysicsCells : m_Cells; + const std::vector& moidsInCell = cells[ignoreTeam + 1][GetCellIdForCellCoords(cellX, cellY)]; + for (MOID moid: moidsInCell) { + potentialMOIDs.insert(moid); + } + + std::vector MOList; + for (MOID moid: potentialMOIDs) { + MovableObject* mo = g_MovableMan.GetMOFromID(moid); + if (mo && mo->HitTestAtPixel(x, y, false)) { + MOList.push_back(mo); + } + } + + return MOList; +} + int SpatialPartitionGrid::GetCellIdForCellCoords(int cellX, int cellY) const { // We act like we wrap, even if the Scene doesn't. The only cost is some duplicate collision checks, but that's a minor cost to pay :) int wrappedX = cellX % m_Width; diff --git a/Source/System/SpatialPartitionGrid.h b/Source/System/SpatialPartitionGrid.h index 0370d5ee26..347ce1d59e 100644 --- a/Source/System/SpatialPartitionGrid.h +++ b/Source/System/SpatialPartitionGrid.h @@ -68,6 +68,14 @@ namespace RTE { /// @param getsHitByMOsOnly Whether to only include MOs that have GetsHitByMOs enabled, or all MOs. /// @return A vector of MOIDs that are potentially overlapping the x and y coordinates. const std::vector& GetMOIDsAtPosition(int x, int y, int ignoreTeam, bool getsHitByMOsOnly) const; + + /// Get a vector of pointers to all the MovableObjects that are potentially overlapping the given X and Y Scene coordinates. + /// @param x The X coordinate to check. + /// @param y The Y coordinate to check. + /// @param ignoreTeam The team to ignore when getting MOs. + /// @param getsHitByMOsOnly Whether to only include MOs that have GetsHitByMOs enabled, or all MOs. + /// @return A vector of pointers to all MovableObjects within the given x and y coordinates, who aren't of the ignored team. + std::vector GetMOsAtPosition(int x, int y, int ignoreTeam, bool getsHitByMOsOnly) const; #pragma endregion private: From 87bd1d3aaec105a0fe0a7f7f797b220af4eb08c2 Mon Sep 17 00:00:00 2001 From: Causeless Date: Sun, 8 Dec 2024 14:27:09 +0000 Subject: [PATCH 05/10] Fixed ConvertLuaTableToVectorOfType() to work with non-pointer types --- Source/Lua/LuaAdapters.cpp | 18 +++--------------- Source/Lua/LuabindDefinitions.h | 6 +++++- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/Source/Lua/LuaAdapters.cpp b/Source/Lua/LuaAdapters.cpp index a362d1c961..a3f1b390df 100644 --- a/Source/Lua/LuaAdapters.cpp +++ b/Source/Lua/LuaAdapters.cpp @@ -613,11 +613,7 @@ std::list* LuaAdaptersPresetMan::GetAllEntitiesOfGroup(PresetMan& prese } MOID LuaAdaptersSceneMan::CastMORay1(SceneMan& sceneMan, const Vector& start, const Vector& ray, const luabind::object& ignoreMOIDs, int ignoreTeam, unsigned char ignoreMaterial, bool ignoreAllTerrain, int skip) { - std::vector ptrVec = ConvertLuaTableToVectorOfType(ignoreMOIDs); - std::vector ignoreMOIDsVec; - for (auto ptr : ptrVec) { - ignoreMOIDsVec.push_back(*ptr); - } + std::vector ignoreMOIDsVec = ConvertLuaTableToVectorOfType(ignoreMOIDs); return sceneMan.CastMORay(start, ray, ignoreMOIDsVec, ignoreTeam, ignoreMaterial, ignoreAllTerrain, skip); } @@ -627,20 +623,12 @@ MOID LuaAdaptersSceneMan::CastMORay2(SceneMan& sceneMan, const Vector& start, co } const std::vector* LuaAdaptersSceneMan::CastAllMOsRay(SceneMan& sceneMan, const Vector& start, const Vector& ray, const luabind::object& ignoreMOIDs, int ignoreTeam, unsigned char ignoreMaterial, bool ignoreAllTerrain, int skip) { - std::vector ptrVec = ConvertLuaTableToVectorOfType(ignoreMOIDs); - std::vector ignoreMOIDsVec; - for (auto ptr : ptrVec) { - ignoreMOIDsVec.push_back(*ptr); - } + std::vector ignoreMOIDsVec = ConvertLuaTableToVectorOfType(ignoreMOIDs); return sceneMan.CastAllMOsRay(start, ray, ignoreMOIDsVec, ignoreTeam, ignoreMaterial, ignoreAllTerrain, skip); } float LuaAdaptersSceneMan::CastObstacleRay1(SceneMan& sceneMan, const Vector& start, const Vector& ray, Vector& obstaclePos, Vector& freePos, const luabind::object& ignoreMOIDs, int ignoreTeam, unsigned char ignoreMaterial, int skip) { - std::vector ptrVec = ConvertLuaTableToVectorOfType(ignoreMOIDs); - std::vector ignoreMOIDsVec; - for (auto ptr : ptrVec) { - ignoreMOIDsVec.push_back(*ptr); - } + std::vector ignoreMOIDsVec = ConvertLuaTableToVectorOfType(ignoreMOIDs); return sceneMan.CastObstacleRay(start, ray, obstaclePos, freePos, ignoreMOIDsVec, ignoreTeam, ignoreMaterial, skip); } diff --git a/Source/Lua/LuabindDefinitions.h b/Source/Lua/LuabindDefinitions.h index 41b90af847..edfd37d16f 100644 --- a/Source/Lua/LuabindDefinitions.h +++ b/Source/Lua/LuabindDefinitions.h @@ -72,7 +72,11 @@ namespace RTE { std::vector outVector = {}; if (luaObject.is_valid() && luabind::type(luaObject) == LUA_TTABLE) { for (luabind::iterator tableItr(luaObject), tableEnd; tableItr != tableEnd; ++tableItr) { - outVector.emplace_back(luabind::object_cast(*tableItr, luabind::adopt(luabind::result))); + if constexpr (std::is_pointer_v) { + outVector.emplace_back(luabind::object_cast(*tableItr, luabind::adopt(luabind::result))); + } else { + outVector.emplace_back(luabind::object_cast(*tableItr)); + } } } return outVector; From e31b466fa203eec8c65afff4850fc7da264db6ee Mon Sep 17 00:00:00 2001 From: pawnishoovy <54544349+pawnishoovy@users.noreply.github.com> Date: Mon, 9 Dec 2024 03:16:00 +0200 Subject: [PATCH 06/10] actually bind CastAllMOsRay --- Source/Lua/LuaBindingsManagers.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Lua/LuaBindingsManagers.cpp b/Source/Lua/LuaBindingsManagers.cpp index b5d1329524..df3148eefd 100644 --- a/Source/Lua/LuaBindingsManagers.cpp +++ b/Source/Lua/LuaBindingsManagers.cpp @@ -330,6 +330,7 @@ LuaBindingRegisterFunctionDefinitionForType(ManagerLuaBindings, SceneMan) { .def("CastWeaknessRay", &SceneMan::CastWeaknessRay) .def("CastMORay", &LuaAdaptersSceneMan::CastMORay1) .def("CastMORay", &LuaAdaptersSceneMan::CastMORay2) + .def("CastAllMOsRay", &LuaAdaptersSceneMan::CastAllMOsRay) .def("CastFindMORay", &SceneMan::CastFindMORay) .def("CastObstacleRay", &LuaAdaptersSceneMan::CastObstacleRay1) .def("CastObstacleRay", &LuaAdaptersSceneMan::CastObstacleRay2) From f83fec12d5566fbcbf13b8e9e10912d50d0b9ae5 Mon Sep 17 00:00:00 2001 From: pawnishoovy <54544349+pawnishoovy@users.noreply.github.com> Date: Mon, 9 Dec 2024 03:19:04 +0200 Subject: [PATCH 07/10] actually properly bind CastAllMOsRay --- Source/Lua/LuaBindingsManagers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Lua/LuaBindingsManagers.cpp b/Source/Lua/LuaBindingsManagers.cpp index df3148eefd..b7989686f3 100644 --- a/Source/Lua/LuaBindingsManagers.cpp +++ b/Source/Lua/LuaBindingsManagers.cpp @@ -330,7 +330,7 @@ LuaBindingRegisterFunctionDefinitionForType(ManagerLuaBindings, SceneMan) { .def("CastWeaknessRay", &SceneMan::CastWeaknessRay) .def("CastMORay", &LuaAdaptersSceneMan::CastMORay1) .def("CastMORay", &LuaAdaptersSceneMan::CastMORay2) - .def("CastAllMOsRay", &LuaAdaptersSceneMan::CastAllMOsRay) + .def("CastAllMOsRay", &LuaAdaptersSceneMan::CastAllMOsRay, luabind::return_stl_iterator) .def("CastFindMORay", &SceneMan::CastFindMORay) .def("CastObstacleRay", &LuaAdaptersSceneMan::CastObstacleRay1) .def("CastObstacleRay", &LuaAdaptersSceneMan::CastObstacleRay2) From 0b99ca244f364bc54827e5da4c734a3f88d83ce0 Mon Sep 17 00:00:00 2001 From: pawnishoovy <54544349+pawnishoovy@users.noreply.github.com> Date: Mon, 9 Dec 2024 03:44:07 +0200 Subject: [PATCH 08/10] make FindMORay only find the specific MOID no vanilla code uses it to find child MOIDs, and i suspect no mod code does it either --- Source/Managers/SceneMan.cpp | 2 +- Source/Managers/SceneMan.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Managers/SceneMan.cpp b/Source/Managers/SceneMan.cpp index b906f25814..f8e513ea16 100644 --- a/Source/Managers/SceneMan.cpp +++ b/Source/Managers/SceneMan.cpp @@ -2065,7 +2065,7 @@ bool SceneMan::CastFindMORay(const Vector& start, const Vector& ray, MOID target // Detect MOIDs hitMOID = GetMOIDPixel(intPos[X], intPos[Y], Activity::NoTeam); - if (hitMOID == targetMOID || g_MovableMan.GetRootMOID(hitMOID) == targetMOID) { + if (hitMOID == targetMOID) { // Found target MOID, so save result and report success resultPos.SetXY(intPos[X], intPos[Y]); // Save last ray pos diff --git a/Source/Managers/SceneMan.h b/Source/Managers/SceneMan.h index 801af44420..3e623defdd 100644 --- a/Source/Managers/SceneMan.h +++ b/Source/Managers/SceneMan.h @@ -693,7 +693,7 @@ namespace RTE { /// Traces along a vector and shows where a specific MOID has been found. /// @param start The starting position. /// @param ray The vector to trace along. - /// @param targetMOID An MOID to find. Any child MO's of this MOID will also be found. ------------ ??? + /// @param targetMOID An MOID to find. /// @param resultPos A reference to the vector screen will be filled out with the absolute /// location of the found MO pixel of the above MOID. /// @param ignoreMaterial A specific material ID to ignore hits with. (default: 0) From 05cae4e03b5994c273ece5599f2788af4960dde7 Mon Sep 17 00:00:00 2001 From: pawnishoovy <54544349+pawnishoovy@users.noreply.github.com> Date: Mon, 9 Dec 2024 08:41:55 +0200 Subject: [PATCH 09/10] Update CHANGELOG.md --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 610c2be8bb..fe507eb712 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -85,6 +85,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - New `MovableMan` function `GetMOsAtPosition(posX, posY, ignoreTeam, getsHitByMOsOnly)` that will return an iterator with all the `MovableObject`s that intersect that exact position with their sprite. +- New `SceneMan` function `CastAllMOsRay(startVector, rayVector, table ignoreMOIDs, ignoreTeam, ignoreMaterial, bool ignoreAllTerrain, int skip)` which returns an iterator with pointers to all the non-ignored MOs met along the ray. +
Changed @@ -131,6 +133,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - `MOSRotating` Lua function `AddWound` now additionally accepts the format `MOSRotating:AddWound(AEmitter* woundToAdd, const Vector& parentOffsetToSet, bool checkGibWoundLimit, bool isEntryWound, bool isExitWound)`, allowing modders to specify added wounds as entry- or exit wounds, for the purpose of not playing multiple burst sounds on the same frame. These new arguments are optional. +- `SceneMan` function `CastFindMORay` now only intersects with and finds the exact MOID specified and not any child MOIDs of that MOID. + +- `SceneMan` function `CastMORay` now can also accept a table of MOIDs instead of a single MOID, letting you ignore any arbitrary set of MOIDs. +
Fixed From 4b3a1a6ef67d6541bfd0dcf833f0981da6109848 Mon Sep 17 00:00:00 2001 From: pawnishoovy <54544349+pawnishoovy@users.noreply.github.com> Date: Mon, 9 Dec 2024 12:43:31 +0200 Subject: [PATCH 10/10] turn whether FindMORay finds children or not into a parameter --- CHANGELOG.md | 2 +- Source/Lua/LuaBindingsManagers.cpp | 1 + Source/Managers/SceneMan.cpp | 4 ++-- Source/Managers/SceneMan.h | 3 ++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe507eb712..c27a8b3c34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -133,7 +133,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - `MOSRotating` Lua function `AddWound` now additionally accepts the format `MOSRotating:AddWound(AEmitter* woundToAdd, const Vector& parentOffsetToSet, bool checkGibWoundLimit, bool isEntryWound, bool isExitWound)`, allowing modders to specify added wounds as entry- or exit wounds, for the purpose of not playing multiple burst sounds on the same frame. These new arguments are optional. -- `SceneMan` function `CastFindMORay` now only intersects with and finds the exact MOID specified and not any child MOIDs of that MOID. +- `SceneMan` function `CastFindMORay` now has an extra bool parameter `findChildMOIDs` that denotes whether it also triggers on child MOIDs or not, which defaults to true for the same default behavior as before. - `SceneMan` function `CastMORay` now can also accept a table of MOIDs instead of a single MOID, letting you ignore any arbitrary set of MOIDs. diff --git a/Source/Lua/LuaBindingsManagers.cpp b/Source/Lua/LuaBindingsManagers.cpp index b7989686f3..20f009fd7e 100644 --- a/Source/Lua/LuaBindingsManagers.cpp +++ b/Source/Lua/LuaBindingsManagers.cpp @@ -331,6 +331,7 @@ LuaBindingRegisterFunctionDefinitionForType(ManagerLuaBindings, SceneMan) { .def("CastMORay", &LuaAdaptersSceneMan::CastMORay1) .def("CastMORay", &LuaAdaptersSceneMan::CastMORay2) .def("CastAllMOsRay", &LuaAdaptersSceneMan::CastAllMOsRay, luabind::return_stl_iterator) + .def("CastFindMORay", (bool(SceneMan::*)(const Vector&, const Vector&, MOID, const Vector&, unsigned char, bool, int)) & SceneMan::CastFindMORay) .def("CastFindMORay", &SceneMan::CastFindMORay) .def("CastObstacleRay", &LuaAdaptersSceneMan::CastObstacleRay1) .def("CastObstacleRay", &LuaAdaptersSceneMan::CastObstacleRay2) diff --git a/Source/Managers/SceneMan.cpp b/Source/Managers/SceneMan.cpp index f8e513ea16..ce01e9c9bd 100644 --- a/Source/Managers/SceneMan.cpp +++ b/Source/Managers/SceneMan.cpp @@ -2003,7 +2003,7 @@ MOID SceneMan::CastMORay(const Vector& start, const Vector& ray, const std::vect return g_NoMOID; } -bool SceneMan::CastFindMORay(const Vector& start, const Vector& ray, MOID targetMOID, Vector& resultPos, unsigned char ignoreMaterial, bool ignoreAllTerrain, int skip) { +bool SceneMan::CastFindMORay(const Vector& start, const Vector& ray, MOID targetMOID, Vector& resultPos, unsigned char ignoreMaterial, bool ignoreAllTerrain, int skip, bool findChildMOIDs) { int hitCount = 0, error, dom, sub, domSteps, skipped = skip; int intPos[2], delta[2], delta2[2], increment[2]; MOID hitMOID = g_NoMOID; @@ -2065,7 +2065,7 @@ bool SceneMan::CastFindMORay(const Vector& start, const Vector& ray, MOID target // Detect MOIDs hitMOID = GetMOIDPixel(intPos[X], intPos[Y], Activity::NoTeam); - if (hitMOID == targetMOID) { + if (hitMOID == targetMOID || (findChildMOIDs && hitMOID == g_MovableMan.GetRootMOID(targetMOID))) { // Found target MOID, so save result and report success resultPos.SetXY(intPos[X], intPos[Y]); // Save last ray pos diff --git a/Source/Managers/SceneMan.h b/Source/Managers/SceneMan.h index 3e623defdd..1806a51854 100644 --- a/Source/Managers/SceneMan.h +++ b/Source/Managers/SceneMan.h @@ -699,9 +699,10 @@ namespace RTE { /// @param ignoreMaterial A specific material ID to ignore hits with. (default: 0) /// @param ignoreAllTerrain Whether to ignore all terrain hits or not. (default: false) /// @param skip For every pixel checked along the line, how many to skip between them (default: 0) + /// @param findChildMOIDs Whether to also find children of the target MOID. /// for optimization reasons. 0 = every pixel is checked. /// @return Whether the target MOID was found along the ray or not. - bool CastFindMORay(const Vector& start, const Vector& ray, MOID targetMOID, Vector& resultPos, unsigned char ignoreMaterial = 0, bool ignoreAllTerrain = false, int skip = 0); + bool CastFindMORay(const Vector& start, const Vector& ray, MOID targetMOID, Vector& resultPos, unsigned char ignoreMaterial = 0, bool ignoreAllTerrain = false, int skip = 0, bool findChildMOIDs = true); /// Traces along a vector and returns a vector of all MOs encountered. /// @param start The starting position.