From 2fc07ebe526b9722f020b879ba3b18c066cb72cc Mon Sep 17 00:00:00 2001 From: Templarfreak Date: Sat, 29 Aug 2026 01:17:53 -0400 Subject: [PATCH 1/3] Fix for SWs with same Action= shadowing each other SWs that have the same Action type shadow each other due to pulling which superweapon the player is targeting via `From_Action`, which only returns the first entry that matches the action. This adds new player state that tracks what the last SW the player started targeting and uses that instead. --- code/display.cpp | 12 +++++++++++- code/house.cpp | 4 +++- code/house.h | 5 +++++ code/sidebar.cpp | 8 ++++++-- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/code/display.cpp b/code/display.cpp index 373ac538..a3943d2e 100644 --- a/code/display.cpp +++ b/code/display.cpp @@ -136,6 +136,7 @@ #include "smudtype.h" #include "sidebar.h" #include "suprtype.h" +#include "super.h" #include "surface.h" #include "tactical.h" #include "tag.h" @@ -1831,6 +1832,7 @@ void DisplayClass::Mouse_Right_Release(Point2D const & point) } else { if (IsTargettingMode != SUPER_NONE) { IsTargettingMode = SUPER_NONE; + PlayerPtr->TargetingSW = NULL; } else { if (IsWaypointMode) { Waypoint_Mode_Control(0); @@ -2427,10 +2429,18 @@ void DisplayClass::Mouse_Left_Release(Coord const & coord, Cell const & cell, Ob } } - SuperWeaponTypeClass *stype = SuperWeaponTypeClass::From_Action(action); + SuperWeaponTypeClass *stype; + if (PlayerPtr->TargetingSW != NULL) { + stype = PlayerPtr->TargetingSW->Class; + } else { + stype = SuperWeaponTypeClass::From_Action(action); + } + if (stype != NULL) { OutList.push_back(EventClass(PlayerPtr->HeapID, EventClass::SPECIAL_PLACE, stype->HeapID, cell)); } + + PlayerPtr->TargetingSW = NULL; } IsTentative = false; diff --git a/code/house.cpp b/code/house.cpp index 9f259989..aff4be9a 100644 --- a/code/house.cpp +++ b/code/house.cpp @@ -355,7 +355,8 @@ HouseClass::HouseClass(HouseTypeClass const * type) : EnemyArmorForcePrediction(0.33f), EnemyAirForcePrediction(0.33f), EnemyInfantryForcePrediction(0.34f), - PowerSurplus(0) + PowerSurplus(0), + TargetingSW(NULL) { int index; @@ -6491,6 +6492,7 @@ void HouseClass::Serialize(SaveStreamClass & stream) stream.Serialize(EnemyAirForcePrediction); stream.Serialize(EnemyInfantryForcePrediction); stream.Serialize(PowerSurplus); + stream.Serialize(TargetingSW); } diff --git a/code/house.h b/code/house.h index 604f5f20..8e78e31b 100644 --- a/code/house.h +++ b/code/house.h @@ -416,6 +416,11 @@ class HouseClass : public AbstractClass */ DynamicVectorClass SuperWeapon; + /* + ** Superweapon class currently in targeting mode for house. + */ + SuperClass * TargetingSW; + /* ** This is a record of the last building that was built. For buildings that ** were built as a part of scenario creation, it will be the last one diff --git a/code/sidebar.cpp b/code/sidebar.cpp index 4ca14117..2eaaaf9f 100644 --- a/code/sidebar.cpp +++ b/code/sidebar.cpp @@ -2146,6 +2146,7 @@ int SidebarClass::StripClass::SelectClass::Action(unsigned flags, KeyNumType & k */ if (flags & RIGHTPRESS) { Map.IsTargettingMode = SUPER_NONE; + PlayerPtr->TargetingSW = NULL; } /* ** A left mouse press signal "activate". If our weapon type is @@ -2154,16 +2155,19 @@ int SidebarClass::StripClass::SelectClass::Action(unsigned flags, KeyNumType & k if (flags & LEFTPRESS) { if ((unsigned)spc < (unsigned)PlayerPtr->SuperWeapon.Count()) { - if (PlayerPtr->SuperWeapon[spc]->Can_Place()) { - if (PlayerPtr->SuperWeapon[spc]->Class->Action == ACTION_NONE) { + SuperClass* curr_sw = PlayerPtr->SuperWeapon[spc]; + if (curr_sw->Can_Place()) { + if (curr_sw->Class->Action == ACTION_NONE) { OutList.push_back(EventClass(PlayerPtr->HeapID, EventClass::SPECIAL_PLACE, PlayerPtr->SuperWeapon[spc]->Class->HeapID, Cell(0, 0))); } else { + PlayerPtr->TargetingSW = curr_sw; Map.IsTargettingMode = spc; Unselect_All(); Speak(VOX_SELECT_TARGET); } } else { PlayerPtr->SuperWeapon[spc]->Impatient_Click(); + PlayerPtr->TargetingSW = NULL; } } } From 15063c8c486ae641f3a614128c9b195c94a4d092 Mon Sep 17 00:00:00 2001 From: Templarfreak Date: Sat, 29 Aug 2026 22:22:12 -0400 Subject: [PATCH 2/3] ow-power, SW being removed, etc Adds clearing TargetingSW in places where IsTargetingMode is already being cleared. --- code/house.cpp | 3 +++ code/init.cpp | 1 + code/super.cpp | 5 +++++ 3 files changed, 9 insertions(+) diff --git a/code/house.cpp b/code/house.cpp index aff4be9a..56b299c2 100644 --- a/code/house.cpp +++ b/code/house.cpp @@ -8728,6 +8728,7 @@ void HouseClass::Update_Present_Super_Weapons(void) if (PlayerPtr != NULL && Fetch_ID() == PlayerPtr->Fetch_ID()) { if (Map.IsTargettingMode == s) { Map.IsTargettingMode = SUPER_NONE; + PlayerPtr->TargetingSW = NULL; } Map.Column[1].Flag_To_Redraw(); } @@ -8738,6 +8739,7 @@ void HouseClass::Update_Present_Super_Weapons(void) if (PlayerPtr != NULL && Fetch_ID() == PlayerPtr->Fetch_ID()) { if (s == Map.IsTargettingMode) { Map.IsTargettingMode = SUPER_NONE; + PlayerPtr->TargetingSW = NULL; } Map.Column[1].Flag_To_Redraw(); } @@ -8748,6 +8750,7 @@ void HouseClass::Update_Present_Super_Weapons(void) if (Fetch_ID() == PlayerPtr->Fetch_ID()) { if (Map.IsTargettingMode == s) { Map.IsTargettingMode = SUPER_NONE; + PlayerPtr->TargetingSW = NULL; } Map.Column[1].Flag_To_Redraw(); } diff --git a/code/init.cpp b/code/init.cpp index ed66b0c6..7e04014d 100644 --- a/code/init.cpp +++ b/code/init.cpp @@ -4927,6 +4927,7 @@ class ManualPlaceCommandClass : public CommandClass // Drop any superweapon cursor, so that placing the building does not return to it. Map.IsTargettingMode = SUPER_NONE; + PlayerPtr->TargetingSW = NULL; PlayerPtr->Manual_Place(builder, (BuildingClass *)pending); } diff --git a/code/super.cpp b/code/super.cpp index 2c204708..227eb6fd 100644 --- a/code/super.cpp +++ b/code/super.cpp @@ -609,6 +609,7 @@ void SuperClass::Place(Cell const & cell, bool player) Drop_Pods(cell); if (player) { Map.IsTargettingMode = SUPER_NONE; + PlayerPtr->TargetingSW = NULL; } House->IsRecalcNeeded = true; break; @@ -619,6 +620,7 @@ void SuperClass::Place(Cell const & cell, bool player) if (coord != COORD_NONE) { if (player) { Map.IsTargettingMode = SUPER_NONE; + PlayerPtr->TargetingSW = NULL; } House->IsRecalcNeeded = true; new IonBlastClass(coord); @@ -656,6 +658,7 @@ void SuperClass::Place(Cell const & cell, bool player) } if (player) { Map.IsTargettingMode = SUPER_NONE; + PlayerPtr->TargetingSW = NULL; } House->IsRecalcNeeded = true; } @@ -698,6 +701,7 @@ void SuperClass::Place(Cell const & cell, bool player) } if (player) { Map.IsTargettingMode = SUPER_NONE; + PlayerPtr->TargetingSW = NULL; } House->IsRecalcNeeded = true; } else { @@ -726,6 +730,7 @@ void SuperClass::Place(Cell const & cell, bool player) } if (player) { Map.IsTargettingMode = SUPER_NONE; + PlayerPtr->TargetingSW = NULL; } House->IsRecalcNeeded = true; } From 00515e544078f55024150f8b7747a97c3823968e Mon Sep 17 00:00:00 2001 From: Templarfreak Date: Sun, 30 Aug 2026 00:02:14 -0400 Subject: [PATCH 3/3] Create fix-sw-shadowing.md --- manual/changes/fix-sw-shadowing.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 manual/changes/fix-sw-shadowing.md diff --git a/manual/changes/fix-sw-shadowing.md b/manual/changes/fix-sw-shadowing.md new file mode 100644 index 00000000..bc0c28e9 --- /dev/null +++ b/manual/changes/fix-sw-shadowing.md @@ -0,0 +1,20 @@ +--- +title: Keep superweapons that share an Action from replacing each other +category: fix +release: 0.2.0 +targets: +- type: system + id: superweapons + effect: changed +credit: [Templarfreak] +--- + +Placing a superweapon on the map now fires the one that was actually armed, even when +another superweapon defines the same Action. Clicking a target cell previously resolved +back to whichever superweapon type first matched that Action, so two superweapons sharing +one Action value could not be fired independently: placing either one always discharged +the same type and left the other's charge untouched. + +The game now remembers the specific superweapon that was armed from the sidebar and fires +that one directly, falling back to the old Action lookup only when nothing was armed +through the sidebar.