diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bb1a4c802..1421d36463 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. @@ -81,6 +83,10 @@ 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. + +- 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 @@ -127,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 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. + - Techion Laser Rifle now has a constant range rather than being dependent on game resolution. - Various performance improvements. diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogDS015.png b/Data/Base.rte/GUIs/Controllers/DualAnalogDS015.png index 21bd39cae6..32b89f2d1c 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogDS015.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogDS015.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogDS016.png b/Data/Base.rte/GUIs/Controllers/DualAnalogDS016.png index 34d7fd5bae..ae5d21b811 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogDS016.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogDS016.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogDS017.png b/Data/Base.rte/GUIs/Controllers/DualAnalogDS017.png index 5b5c64ff41..06c5fedd5d 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogDS017.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogDS017.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogDS018.png b/Data/Base.rte/GUIs/Controllers/DualAnalogDS018.png index afb08f7c0a..b9a9927458 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogDS018.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogDS018.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogDS019.png b/Data/Base.rte/GUIs/Controllers/DualAnalogDS019.png index dc1c60635d..869a7d4cb1 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogDS019.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogDS019.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogDS020.png b/Data/Base.rte/GUIs/Controllers/DualAnalogDS020.png index b7a31ab39e..2e66cb3320 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogDS020.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogDS020.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogDS021.png b/Data/Base.rte/GUIs/Controllers/DualAnalogDS021.png index ff5462877a..e119dfb574 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogDS021.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogDS021.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogDS022.png b/Data/Base.rte/GUIs/Controllers/DualAnalogDS022.png index 434647977c..ba71d59041 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogDS022.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogDS022.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB002.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB002.png index 15ef1d9eac..42253cdb96 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogXB002.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogXB002.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB003.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB003.png index aec2a2c555..6a1e0c93a5 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogXB003.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogXB003.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB004.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB004.png index e16ba33fa3..735e5de773 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogXB004.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogXB004.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB005.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB005.png index b2a059c0ae..b039cf22ae 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogXB005.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogXB005.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB006.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB006.png index fd473f6ea7..e320d8878a 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogXB006.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogXB006.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB007.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB007.png index 1f578fc568..1e830c7f0a 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogXB007.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogXB007.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB008.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB008.png index 1df9730b39..005a16fe9f 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogXB008.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogXB008.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB009.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB009.png index a71de723ab..21e71a434f 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogXB009.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogXB009.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB010.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB010.png index 47ea1762e9..60b174ef18 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogXB010.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogXB010.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB011.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB011.png index 9612f5b59a..3f1ed83fb9 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogXB011.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogXB011.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB012.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB012.png index c87b28b085..3eb38fab55 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogXB012.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogXB012.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB013.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB013.png index a2dfb3b6f9..9d394a8d3b 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogXB013.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogXB013.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB014.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB014.png index 05ece84b25..004f434960 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogXB014.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogXB014.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB015.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB015.png index f1152b413e..29c985a099 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogXB015.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogXB015.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB016.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB016.png index c38b6255e6..ad3e42fa20 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogXB016.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogXB016.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB017.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB017.png index cd54251c5d..1dab8cf724 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogXB017.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogXB017.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB018.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB018.png index a43067fd73..36b38f7c43 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogXB018.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogXB018.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB019.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB019.png index 596046e5de..cb759b97c3 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogXB019.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogXB019.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB020.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB020.png index d5fa533063..521476f369 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogXB020.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogXB020.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB021.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB021.png index 8140a98afe..c0d543c635 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogXB021.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogXB021.png differ diff --git a/Data/Base.rte/GUIs/Controllers/DualAnalogXB022.png b/Data/Base.rte/GUIs/Controllers/DualAnalogXB022.png index 0c6d1c6563..642a188036 100644 Binary files a/Data/Base.rte/GUIs/Controllers/DualAnalogXB022.png and b/Data/Base.rte/GUIs/Controllers/DualAnalogXB022.png differ 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/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 5c0f32c5a1..3e59ae2fe2 100644 --- a/Source/Lua/LuaAdapterDefinitions.h +++ b/Source/Lua/LuaAdapterDefinitions.h @@ -512,6 +512,90 @@ 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 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) + /// @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& 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 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) + /// @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 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. + /// @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..a3f1b390df 100644 --- a/Source/Lua/LuaAdapters.cpp +++ b/Source/Lua/LuaAdapters.cpp @@ -612,6 +612,31 @@ 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 ignoreMOIDsVec = ConvertLuaTableToVectorOfType(ignoreMOIDs); + 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); +} + +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 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 ignoreMOIDsVec = ConvertLuaTableToVectorOfType(ignoreMOIDs); + 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 abd84e4a54..24470d05ca 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) @@ -325,9 +328,13 @@ 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("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", &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/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/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; diff --git a/Source/Managers/MovableMan.cpp b/Source/Managers/MovableMan.cpp index 25faaf869a..f976fce9b5 100644 --- a/Source/Managers/MovableMan.cpp +++ b/Source/Managers/MovableMan.cpp @@ -197,6 +197,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 e7f27763f0..00e2ba6141 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 7bb85f256f..4ec3ff231b 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; @@ -1993,7 +2003,7 @@ MOID SceneMan::CastMORay(const Vector& start, const Vector& ray, MOID ignoreMOID 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; @@ -2055,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 || (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 @@ -2085,7 +2095,109 @@ 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) { +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]; bool hitObstacle = false; @@ -2152,17 +2264,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..1806a51854 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,21 +670,52 @@ 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. - /// @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) /// @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. + /// @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. @@ -695,7 +726,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 +735,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(); 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); } 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& 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: