From 350754a6da446c746cb649059871a984901adf8b Mon Sep 17 00:00:00 2001 From: BlackDog86 <122568778+BlackDog86@users.noreply.github.com> Date: Mon, 11 Aug 2025 15:14:25 +0100 Subject: [PATCH 1/2] add X2Camera_FollowMouseCursor to CHL --- .../Classes/X2Camera_FollowMouseCursor.uc | 551 ++++++++++++++++++ .../X2WOTCCommunityHighlander.x2proj | 3 + 2 files changed, 554 insertions(+) create mode 100644 X2WOTCCommunityHighlander/Src/XComGame/Classes/X2Camera_FollowMouseCursor.uc diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/X2Camera_FollowMouseCursor.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/X2Camera_FollowMouseCursor.uc new file mode 100644 index 000000000..738f52e39 --- /dev/null +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/X2Camera_FollowMouseCursor.uc @@ -0,0 +1,551 @@ +//--------------------------------------------------------------------------------------- +// FILE: X2Camera_FollowMouseCursor.uc +// AUTHOR: David Burchanowski -- 2/10/2014 +// PURPOSE: Simple camera that just tracks the 3d cursor in mouse mode. The default. +// +//--------------------------------------------------------------------------------------- +// Copyright (c) 2016 Firaxis Games, Inc. All rights reserved. +//--------------------------------------------------------------------------------------- + +class X2Camera_FollowMouseCursor extends X2Camera_Lookat + config(Camera); + +// the location this camera currently wants to look at +var protected Vector LookAt; + +// track scroll input separately, so we can apply it at a higher rate than the normal interpolation +var private Vector RemainingEdgeScroll; + +// Is the camera in the process of centering on a unit. +var private bool IsCenteringOnUnit; + +var private bool HasStoredMouseCoords; +var private Vector2D StoredMouseCoordsAfterCentering; +var private float EnablePathingDistance; +var private bool MoveAbilitySubmitted; // Was a move ability just submitted +var private XComGameState_Unit LastPlayerControlledUnit; + +// Holds the previous cameras vis focus points. Used during alien (non player) turns to prevent vis poping, as this camera is the default camera in between camera shots. +var private array PreviousCamerasVisFocusPoints; + +function Activated(TPOV CurrentPOV, X2Camera PreviousActiveCamera, X2Camera_LookAt LastActiveLookAtCamera) +{ + local XComGameStateHistory History; + local XComTacticalController LocalController; + local XComGameState_Unit ActiveUnit; + local XCom3DCursor Cursor; + local X2EventManager EventManager; + local Object ThisObj; + + super.Activated(CurrentPOV, PreviousActiveCamera, LastActiveLookAtCamera); + + if (PreviousActiveCamera != none) + { + PreviousActiveCamera.GetCameraFocusPoints(PreviousCamerasVisFocusPoints); + } + else + { + PreviousCamerasVisFocusPoints.Length = 0; + } + + // kill any leftover scroll amount + RemainingEdgeScroll.X = 0; + RemainingEdgeScroll.Y = 0; + + LocalController = XComTacticalController(`BATTLE.GetALocalPlayerController()); + + if (LastActiveLookAtCamera != none && LocalController != none && LocalController.bManuallySwitchedUnitsWhileVisualizerBusy == false) + { + // make our desired look at the same as the previous look at point, we don't do this if have just manually switched units so the lookat tranitions to the new unit + LookAt = LastActiveLookAtCamera.GetCameraLookat(); + } + + // scroll to the currently active unit if it is offscreen and it's the human player's turn and the visualizer is idle + if(!class'XComGameStateVisualizationMgr'.static.VisualizerBusy()) + { + History = `XCOMHISTORY; + ActiveUnit = XComGameState_Unit(History.GetGameStateForObjectID(LocalController.GetActiveUnitStateRef().ObjectID)); + if(ActiveUnit != none + && !ActiveUnit.ControllingPlayerIsAI() + && ActiveUnit.ControllingPlayer == GetActivePlayer()) + { + CenterOnUnitIfOffscreen(ActiveUnit); + } + } + + if(X2Camera_OTSTargeting(PreviousActiveCamera) != none) + { + // when returning from a targeting camera, snap the camera to the unit lookat from + // the get go so we don't blend and interpolate at the same time. + CurrentLookAt = GetCameraLookat(); + } + + // whenever we get control back, set the 3D cursor's pathing floor to be the floor we are looking at + Cursor = `CURSOR; + Cursor.m_iRequestedFloor = Cursor.WorldZToFloor(LookAt); + Cursor.m_iLastEffectiveFloorIndex = Cursor.m_iRequestedFloor; + + MoveAbilitySubmitted = false; + + EventManager = `XEVENTMGR; + ThisObj = self; + EventManager.RegisterForEvent(ThisObj, 'CameraFocusActiveUnit', OnCameraFocusUnit, ELD_Immediate); + EventManager.RegisterForEvent(ThisObj, 'AbilityActivated', OnAbilityActivated, ELD_Immediate, , ); + EventManager.RegisterForEvent(ThisObj, 'PlayerTurnEnded', OnTurnEnded, ELD_OnVisualizationBlockStarted, , ); +} + +function Deactivated() +{ + local Object ThisObj; + + ThisObj = self; + `XEVENTMGR.UnRegisterFromAllEvents(ThisObj); +} + +function EventListenerReturn OnCameraFocusUnit(Object EventData, Object EventSource, XComGameState GameState, Name Event, Object CallbackData) +{ + local XComTacticalController LocalController; + local XComGameStateHistory History; + local XComGameState_Unit ActiveUnit; + + LocalController = XComTacticalController(`BATTLE.GetALocalPlayerController()); + if(LocalController != none && !class'XComGameStateVisualizationMgr'.static.VisualizerBusy()) + { + History = `XCOMHISTORY; + ActiveUnit = XComGameState_Unit(History.GetGameStateForObjectID(LocalController.GetActiveUnitStateRef().ObjectID)); + if(ActiveUnit != none + && !ActiveUnit.ControllingPlayerIsAI() + && ActiveUnit.ControllingPlayer == GetActivePlayer()) + { + CenterOnUnitIfOffscreen(ActiveUnit); + } + } + + return ELR_NoInterrupt; +} + +function StateObjectReference GetActivePlayer() +{ + local XComGameStateHistory History; + local XComGameStateContext_TacticalGameRule Context; + local StateObjectReference NullReference; + + History = `XCOMHISTORY; + + foreach History.IterateContextsByClassType(class'XComGameStateContext_TacticalGameRule', Context) + { + if(Context.GameRuleType == eGameRule_PlayerTurnBegin) + { + return Context.PlayerRef; + } + } + + return NullReference; +} + +private function bool ShouldScrollCamera() +{ + local XComGameStateVisualizationMgr VisManager; + + if(!`XENGINE.IsMultiplayerGame()) + { + if((`TACTICALRULES.GetUnitActionTeam() != eTeam_XCom) && (`CHEATMGR == None || !`CHEATMGR.bAllowSelectAll) && (`REPLAY == none || !`REPLAY.bInReplay)) + { + return false; // no scrolling during the alien turn + } + } + + VisManager = `XCOMVISUALIZATIONMGR; + + if( VisManager.VisualizerBusy() && + (VisManager.VisualizationTree == none || !VisManager.VisualizationTree.bNewUnitSelected) ) + { + return false; // no scrolling during visualizations unless quick selecting (tab select) new unit + } + + return true; +} + +// Internal helper for normal and raw scrolling. Immediate == true will disable any smoothing +private function InternalScrollCamera(Vector2D Offset, bool Immediate) +{ + local float YawInRadians; + local float CosYaw; + local float SinYaw; + local Vector Delta; + + if( !ShouldScrollCamera() ) + { + return; + } + + YawInRadians = UnrRotToRad * CurrentRotation.Yaw; + CosYaw = Cos(YawInRadians); + SinYaw = Sin(YawInRadians); + + // note that X and Y are flipped because the offset is in screen space and at yaw=0 degrees "up" + // in screen space looks down the world y axis + Delta.X = Offset.Y * CosYaw + Offset.X * -SinYaw; + Delta.Y = Offset.Y * SinYaw + Offset.X * CosYaw; + LookAt += Delta; + + if(Immediate) + { + CurrentLookAt += Delta; + } + + IsCenteringOnUnit = false; +} + +function ScrollCamera(Vector2D Offset) +{ + InternalScrollCamera(Offset, false); +} + +/// +/// Notifies the camera that the user is attempting to scroll without smoothing +/// +function RawScrollCamera(Vector2D Offset) +{ + InternalScrollCamera(Offset, true); +} + +function EdgeScrollCamera(Vector2D Offset) +{ + local float YawInRadians; + local float CosYaw; + local float SinYaw; + local Vector Delta; + + if( !ShouldScrollCamera() ) + { + return; + } + + YawInRadians = UnrRotToRad * CurrentRotation.Yaw; + CosYaw = Cos(YawInRadians); + SinYaw = Sin(YawInRadians); + + // note that X and Y are flipped because the offset is in screen space and at yaw=0 degrees "up" + // in screen space looks down the world y axis + Delta.X = Offset.Y * CosYaw + Offset.X * -SinYaw; + Delta.Y = Offset.Y * SinYaw + Offset.X * CosYaw; + RemainingEdgeScroll += Delta; + + IsCenteringOnUnit = false; +} + +function UpdateCamera(float DeltaTime) +{ + local float RemainingScrollBrakeAlpha; + local Vector UsedScrollDelta; + + super.UpdateCamera(DeltaTime); + + // If we're close to our destination, store the current mouse coordinates so we can check how much the mouse has moved before enabling pathing line + if (!HasStoredMouseCoords && bCameraIsMoving && CameraIsCloseToDestination(EnablePathingDistance)) + { + `PRES.GetMouseCoords(StoredMouseCoordsAfterCentering); + HasStoredMouseCoords = true; + } + + if (bCameraIsMoving == false && IsCenteringOnUnit) + { + IsCenteringOnUnit = false; + if (!HasStoredMouseCoords) + { + `PRES.GetMouseCoords(StoredMouseCoordsAfterCentering); + HasStoredMouseCoords = true; + } + } + + // add in more of the edge scroll input if we have some. this allows us to skip ramp up on the edge scroll, + // which is much more pc-esque + RemainingScrollBrakeAlpha = ComputeLocationBrakeAlpha(VSize(RemainingEdgeScroll)); + if(RemainingScrollBrakeAlpha > 0.01f) // only until we are almost there, or we may never arrive due to numerical limits + { + UsedScrollDelta = RemainingScrollBrakeAlpha * RemainingEdgeScroll; + + LookAt += UsedScrollDelta; + CurrentLookAt += UsedScrollDelta; + RemainingEdgeScroll -= UsedScrollDelta; + } + + ClampLookAtToWorldBounds(); +} + +protected function ClampLookAtToWorldBounds() +{ + local XComWorldData WorldData; + local vector BoundsMin; + local vector BoundsMax; + local vector VerticalBuffer; + + // clamp the lookat point to the level bounds (with some vertical buffer to account for camera floor adjustments, + // we just need to keep it from completely falling out of the level) + WorldData = `XWORLD; + VerticalBuffer.Z = class'XComWorldData'.const.WORLD_FloorHeight * 3; + BoundsMin = WorldData.Volume.CollisionComponent.Bounds.Origin - WorldData.Volume.CollisionComponent.Bounds.BoxExtent - VerticalBuffer; + BoundsMax = WorldData.Volume.CollisionComponent.Bounds.Origin + WorldData.Volume.CollisionComponent.Bounds.BoxExtent + VerticalBuffer; + LookAt.X = FClamp(LookAt.X, BoundsMin.X, BoundsMax.X); + LookAt.Y = FClamp(LookAt.Y, BoundsMin.Y, BoundsMax.Y); + CurrentLookAt.X = FClamp(CurrentLookAt.X, BoundsMin.X, BoundsMax.X); + CurrentLookAt.Y = FClamp(CurrentLookAt.Y, BoundsMin.Y, BoundsMax.Y); +} + +protected function Vector GetCameraLookat() +{ + local Vector Result; + local XCom3DCursor Cursor; + + Cursor = `CURSOR; + + Result = LookAt; + Result.Z = Cursor.GetFloorMinZ(Cursor.m_iLastEffectiveFloorIndex); + return Result; +} + +event OnActiveUnitChanged(XComGameState_Unit NewActiveUnit) +{ + super.OnActiveUnitChanged(NewActiveUnit); + + MoveAbilitySubmitted = false; + + if( NewActiveUnit.IsPlayerControlled() ) + { + CenterOnUnitIfOffscreen(NewActiveUnit); + LastPlayerControlledUnit = NewActiveUnit; + } + else + { + CenterOnUnitIfOffscreen(LastPlayerControlledUnit); + } +} + +function EventListenerReturn OnTurnEnded(Object EventData, Object EventSource, XComGameState GameState, Name Event, Object CallbackData) +{ + CenterOnUnitIfOffscreen(LastPlayerControlledUnit); + + return ELR_NoInterrupt; +} + +private function CenterOnUnitIfOffscreen(XComGameState_Unit Unit) +{ + local XComPresentationLayer Pres; + local Vector UnitLocation; + local XCom3DCursor Cursor; + local int UnitFloor; + + if(Unit == none) return; + + Pres = `PRES; + if(Pres.GetTacticalHUD().IsMenuRaised()) + { + return; + } + + if(Pres.m_kTacticalHUD.m_kAbilityHUD.TargetingMethod != none) + { + return; + } + + Cursor = `CURSOR; + + // snap the lookat to the bottom of the current unit's floor. Smooths out small bumps + // and vertical motions his root makes. + UnitLocation = Unit.GetVisualizer().Location; + UnitFloor = Cursor.WorldZToFloor(UnitLocation); + UnitLocation.Z = Cursor.GetFloorMinZ(UnitFloor); + + LookAt = UnitLocation; + IsCenteringOnUnit = true; + HasStoredMouseCoords = false; +} + +function bool DisableFocusPointExpiration() +{ + return !CameraIsCloseToDestination(EnablePathingDistance) || bCameraIsRotating || bCameraIsZooming || MoveAbilitySubmitted; +} + +function bool HidePathing() +{ + local Vector2D CurrentMouseCoords, vDiff; + + return false; // Per Dan K we don't want to remove pathing information based on the camera and i couldn't think of a reason to refute + + if (HasStoredMouseCoords) + { + if (!IsCenteringOnUnit || (IsCenteringOnUnit && CameraIsCloseToDestination(EnablePathingDistance))) + { + `PRES.GetMouseCoords(CurrentMouseCoords); + vDiff = CurrentMouseCoords - StoredMouseCoordsAfterCentering; + + if (vDiff.X*vDiff.X + vDiff.Y*vDiff.Y > 2) + { + return false; + } + + return true; + } + } + + return true; +} + +function bool HidePathingBorder() +{ + return false; // Per Dan K we don't want to remove pathing information based on the camera and i couldn't think of a reason to refute + //return !CameraIsCloseToDestination(EnablePathingDistance); +} + +function bool CameraIsCloseToDestination(float Dist) +{ + local Vector NewLookAt; + local Vector LookAtDelta; + local float DeltaLength; + + NewLookAt = GetCameraLookAt(); + LookAtDelta = NewLookAt - CurrentLookAt; + DeltaLength = VSize(LookAtDelta); + + if (DeltaLength > Dist) + { + return false; + } + else + { + return true; + } +} + +function EventListenerReturn OnAbilityActivated(Object EventData, Object EventSource, XComGameState GameState, Name Event, Object CallbackData) +{ + local XComGameStateContext_Ability AbilityContext; + local XComGameState_Unit UnitState; + + AbilityContext = XComGameStateContext_Ability(GameState.GetContext()); + if (AbilityContext != none) + { + if (AbilityContext.InputContext.AbilityTemplateName == 'StandardMove') + { + UnitState = XComGameState_Unit(`XCOMHISTORY.GetGameStateForObjectID(AbilityContext.InputContext.SourceObject.ObjectID)); + if (UnitState != none && !UnitState.ControllingPlayerIsAI() && UnitState.ControllingPlayer == GetActivePlayer()) + { + // A move action was just submitted, will cause disabling of focuspointexpiry so building vis doesnt fluctuate + //while we are waiting for the camera to switch to the follow moving unit camera + MoveAbilitySubmitted = true; + } + } + } + return ELR_NoInterrupt; +} + +function AddCameraFocusPoints() +{ + local XCom3DCursor Cursor; + local XComTacticalController TacticalController; + local XComPawn ActivePawn; + local vector Offset; + local TPOV CameraPOV; + local bool bIgnoreCursor; + local TFocusPoints FocusPoint; + local Plane FloorPlane; + local vector ProjectedPoint; + local vector CameraToCursorNoZ; + local vector CursorLocation; + local bool bDisableExpiration; + local Vector NewLookAt; + local Vector LookAtDelta; + local float FinalDistanceFromPoint; + + bDisableExpiration = DisableFocusPointExpiration(); + + Cursor = `CURSOR; + bIgnoreCursor = false; + + CameraPOV = GetCameraLocationAndOrientation(); + FocusPoint.vCameraLocation = CameraPOV.Location; + + TacticalController = XComTacticalController(`LEVEL.GetALocalPlayerController()); + ActivePawn = TacticalController.GetActivePawn(); + + // the cursor location (the thing the user is pointing at) is of interest + if (Cursor != none && bIgnoreCursor == false) + { + FloorPlane.X = 0; + FloorPlane.Y = 0; + FloorPlane.Z = 1.0; + FloorPlane.W = Cursor.m_fLogicalCameraFloorHeight + 1; // Offset to ensure in proper volume if needed; + + Offset = vect(0, 0, 0); + Offset.Z = Cursor.CollisionComponent.Bounds.BoxExtent.Z; + + CursorLocation = Cursor.Location - Offset; + + NewLookAt = GetCameraLookAt(); + FinalDistanceFromPoint = Lerp(DistanceFromCursor, ZoomedDistanceFromCursor, TargetZoom); + CameraPOV.Location = NewLookAt - (Vector(TargetRotation) * FinalDistanceFromPoint); + + if (bDisableExpiration) + { + + LookAtDelta = NewLookAt - CurrentLookAt; + CursorLocation += LookAtDelta; + } + + CameraToCursorNoZ = CursorLocation - CameraPOV.Location; + CameraToCursorNoZ.Z = 0; + CameraToCursorNoZ = Normal(CameraToCursorNoZ); + + //// Offset the projection ray X units towards the camera (NoZ) + RayPlaneIntersection(CameraPOV.Location, (CursorLocation - (CameraToCursorNoZ * 25.0f)) - CameraPOV.Location, FloorPlane, ProjectedPoint); + + FocusPoint.vFocusPoint = ProjectedPoint; + FocusPoint.vCameraLocation = CameraPOV.Location; + VisFocusPoints.AddItem(FocusPoint); + } + + // the active unit, if any, is of interest + if (ActivePawn != none && bDisableExpiration == false) + { + FocusPoint.vFocusPoint = ActivePawn.Location; + if (ActivePawn.CollisionComponent != none) + FocusPoint.vFocusPoint.Z = ActivePawn.Location.Z - ActivePawn.CollisionComponent.Bounds.BoxExtent.Z; + + FocusPoint.vCameraLocation = CameraPOV.Location; + VisFocusPoints.AddItem(FocusPoint); + } + + Super.AddCameraFocusPoints(); +} + +function GetCameraFocusPoints(out array OutFocusPoints) +{ + local XComGameState_Player PlayerState; + local X2TacticalGameRuleset RuleSet; + local XComGameStateHistory History; + + Super.GetCameraFocusPoints(OutFocusPoints); + + RuleSet = `TACTICALRULES; + History = `XCOMHISTORY; + PlayerState = XComGameState_Player(History.GetGameStateForObjectID(RuleSet.GetCachedUnitActionPlayerRef().ObjectID)); + + if (PlayerState != none && PlayerState.IsLocalPlayer() == false) + { + OutFocusPoints = PreviousCamerasVisFocusPoints; + } +} + +function bool GetCameraIsPrimaryFocusOn() +{ + return true; +} + +defaultproperties +{ + Priority = eCameraPriority_Default + TurnOffHidingAtTargetTile = false + IsCenteringOnUnit=false + EnablePathingDistance = 150 +} diff --git a/X2WOTCCommunityHighlander/X2WOTCCommunityHighlander.x2proj b/X2WOTCCommunityHighlander/X2WOTCCommunityHighlander.x2proj index 83d3259d0..aa1906d79 100644 --- a/X2WOTCCommunityHighlander/X2WOTCCommunityHighlander.x2proj +++ b/X2WOTCCommunityHighlander/X2WOTCCommunityHighlander.x2proj @@ -595,6 +595,9 @@ Content + + Content + Content From 09c1578b9b91a5bd6b8f5e29d96daa6edeafd41e Mon Sep 17 00:00:00 2001 From: BlackDog86 <122568778+BlackDog86@users.noreply.github.com> Date: Mon, 11 Aug 2025 15:16:43 +0100 Subject: [PATCH 2/2] Fix X2AllowSelectAll --- X2WOTCCommunityHighlander/Config/XComGame.ini | 7 ++++++ .../Src/XComGame/Classes/CHHelpers.uc | 13 ++++++++++ .../Classes/X2Camera_FollowMouseCursor.uc | 25 +++++++++++++------ .../XComGame/Classes/X2TacticalGameRuleset.uc | 7 ++++-- .../Classes/XComTacticalCheatManager.uc | 12 +++++++++ .../Classes/XComTacticalController.uc | 20 ++++++++++++--- .../Src/XComGame/Classes/XComTacticalInput.uc | 3 ++- 7 files changed, 74 insertions(+), 13 deletions(-) diff --git a/X2WOTCCommunityHighlander/Config/XComGame.ini b/X2WOTCCommunityHighlander/Config/XComGame.ini index e28d2a7d0..460f86bb1 100644 --- a/X2WOTCCommunityHighlander/Config/XComGame.ini +++ b/X2WOTCCommunityHighlander/Config/XComGame.ini @@ -321,3 +321,10 @@ InterruptionsUpdateTurnStartLocation = false ; Should interruptions update tur InterruptionsResetPanicTestsPerformedThisTurn = false ; Should interruptions reset the tracker for the amount of panic tests performed this turn, just like a normal turn? Default is false, because the unit isn't taking a typical turn. InterruptionsTriggerGroupTurnBegunEvent = true ; Should interruptions trigger the GroupTurnBegunEvent, just like what happens in a normal turn. Default is true, because interruptions work closely with "groups" (XComGameState_AIGroup) in the code side of things. ; End Issue #1325 + +; Start Issue #1486 +;Uncomment to exclude civilians from being selected in the X2AllowSelectAll Console Command +;ExcludeCiviliansFromX2AllowSelectAll = true +;Uncomment to alert & scamper all aliens when using X2AllowSelectAll - allows all alien units to move normally +;UseImprovedX2AllowSelectAllBehavior = true +; End Issue #1486 diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/CHHelpers.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/CHHelpers.uc index 996311f6d..75e2fa382 100644 --- a/X2WOTCCommunityHighlander/Src/XComGame/Classes/CHHelpers.uc +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/CHHelpers.uc @@ -286,6 +286,19 @@ var config bool bDisableAutomaticPromotionPhoto; var config bool bDisableAutomaticBondPhoto; // End Issue #1453 +// Start Issue #1486 +/// HL-Docs: ref:Bugfixes; issue:1486 +/// This set of changes fixes seveal issues with the behavior of the debugging console command X2AllowSelectAll - in particular: +/// 1. With the command active, when selecting units non on the XCom team, the camera would not pan to those units +/// 2. When carrying out other debug commands on non-XCom units (e.g. grantactionpoints), the camera would pan back to the first active unit on the player team +/// 3. Turns which were ended while the command was active would not be processed properly +/// 4. Non-XCom units would not move correctly when the command was issued due to XCom not being considered visible (game resorts to AI-like patrol behavior) +/// All of these are now fixed in a minimally invasive way by gating small setions of basegame code when the command is active and will have no effect otherwise +/// Disabling selection of civilians & 'Improved Behavior' (scamper & alert all aliens) are also provided as optional flags to improve the overall experience. +var config bool ExcludeCiviliansFromX2AllowSelectAll; +var config bool UseImprovedX2AllowSelectAllBehavior; +// End Issue #1486 + // Start Issue #885 enum EHLDelegateReturn { diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/X2Camera_FollowMouseCursor.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/X2Camera_FollowMouseCursor.uc index 738f52e39..86f349c2c 100644 --- a/X2WOTCCommunityHighlander/Src/XComGame/Classes/X2Camera_FollowMouseCursor.uc +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/X2Camera_FollowMouseCursor.uc @@ -65,9 +65,12 @@ function Activated(TPOV CurrentPOV, X2Camera PreviousActiveCamera, X2Camera_Look { History = `XCOMHISTORY; ActiveUnit = XComGameState_Unit(History.GetGameStateForObjectID(LocalController.GetActiveUnitStateRef().ObjectID)); + // Begin Issue #1486 - Allow the default camera to pan to units owned by the AI when the X2AllowSelectAll command is used if(ActiveUnit != none - && !ActiveUnit.ControllingPlayerIsAI() - && ActiveUnit.ControllingPlayer == GetActivePlayer()) + && ((!ActiveUnit.ControllingPlayerIsAI() + && ActiveUnit.ControllingPlayer == GetActivePlayer()) + || (`CHEATMGR != None && `CHEATMGR.bAllowSelectAll))) + // End Issue #1486 { CenterOnUnitIfOffscreen(ActiveUnit); } @@ -113,9 +116,12 @@ function EventListenerReturn OnCameraFocusUnit(Object EventData, Object EventSou { History = `XCOMHISTORY; ActiveUnit = XComGameState_Unit(History.GetGameStateForObjectID(LocalController.GetActiveUnitStateRef().ObjectID)); + // Begin Issue #1486 - Allow the default camera to pan to units owned by the AI when the X2AllowSelectAll command is used if(ActiveUnit != none - && !ActiveUnit.ControllingPlayerIsAI() - && ActiveUnit.ControllingPlayer == GetActivePlayer()) + && ((!ActiveUnit.ControllingPlayerIsAI() + && ActiveUnit.ControllingPlayer == GetActivePlayer()) + || (`CHEATMGR != None && `CHEATMGR.bAllowSelectAll))) + // End Issue #1486 { CenterOnUnitIfOffscreen(ActiveUnit); } @@ -310,8 +316,8 @@ event OnActiveUnitChanged(XComGameState_Unit NewActiveUnit) super.OnActiveUnitChanged(NewActiveUnit); MoveAbilitySubmitted = false; - - if( NewActiveUnit.IsPlayerControlled() ) + // Single Line for Issue #1486 - Allow the camera to focus on non-player controlled units when X2AllowSelectAll is used + if( NewActiveUnit.IsPlayerControlled() || (`CHEATMGR != None && `CHEATMGR.bAllowSelectAll)) { CenterOnUnitIfOffscreen(NewActiveUnit); LastPlayerControlledUnit = NewActiveUnit; @@ -429,7 +435,12 @@ function EventListenerReturn OnAbilityActivated(Object EventData, Object EventSo if (AbilityContext.InputContext.AbilityTemplateName == 'StandardMove') { UnitState = XComGameState_Unit(`XCOMHISTORY.GetGameStateForObjectID(AbilityContext.InputContext.SourceObject.ObjectID)); - if (UnitState != none && !UnitState.ControllingPlayerIsAI() && UnitState.ControllingPlayer == GetActivePlayer()) + // Begin Issue #1486 - Allow the default camera to pan to units owned by the AI when the X2AllowSelectAll command is used + if (UnitState != none + && ((!UnitState.ControllingPlayerIsAI() + && UnitState.ControllingPlayer == GetActivePlayer()) + || (`CHEATMGR != None && `CHEATMGR.bAllowSelectAll))) + // End Issue #1486 { // A move action was just submitted, will cause disabling of focuspointexpiry so building vis doesnt fluctuate //while we are waiting for the camera to switch to the follow moving unit camera diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/X2TacticalGameRuleset.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/X2TacticalGameRuleset.uc index 024ecebd9..26c727895 100644 --- a/X2WOTCCommunityHighlander/Src/XComGame/Classes/X2TacticalGameRuleset.uc +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/X2TacticalGameRuleset.uc @@ -5059,8 +5059,11 @@ simulated state TurnPhase_UnitActions if( bActionsAvailable ) { bWaitingForNewStates = true; //If there are actions available, indicate that we are waiting for a decision on which one to take - - if( !UnitActionPlayerIsRemote() ) + // Single Line for Issue #1486 - When using X2AllowSelectAll, we need to bypass the reselection of the player visualizer when + // a new gamestate is submitted but the unit we're controlling (which may not belong to us) still has actions left - + // this prevents the game from 'tabbing away' from units which are not on our team but which we may still may be controlling. + // This is most obvious when issuing debug commands such as ttc / giveactionpoints + if( !UnitActionPlayerIsRemote() && (`CHEATMGR == none || !`CHEATMGR.bAllowSelectAll)) { PlayerState = XComGameState_Player(CachedHistory.GetGameStateForObjectID(UnitState.ControllingPlayer.ObjectID)); `assert(PlayerState != none); diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComTacticalCheatManager.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComTacticalCheatManager.uc index 43327cf07..d9ee75942 100644 --- a/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComTacticalCheatManager.uc +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComTacticalCheatManager.uc @@ -3949,10 +3949,22 @@ exec function X2AllowSelectAll(bool bSetting) if( bSetting && `XWORLD.bDebugEnableFOW ) { ToggleFOW(); + // Begin Issue #1486 - Force visibility to allow proper pathing of alien units + // (They will still walk if not activated / alerted) + ForceAllUnitsVisible = true; + // Improved functionality alerts and scampers, breaking the default patrol mechanics and allowing the units to move normally + if(class'CHHelpers'.default.UseImprovedX2AllowSelectAllBehavior == true) + { + ToggleIndividualConcealment(); + X2DebugPodReveals(); + } + // End Issue #1486 } else if ( bSetting && !`XWORLD.bDebugEnableFOW ) { ToggleFOW(); + // Single Line for Isuee #1486 - Turn off forced visibility if we're also turning the FOW back on + ForceAllUnitsVisible = false; } //Force all units to be visible diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComTacticalController.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComTacticalController.uc index 4463d85e2..25463d41d 100644 --- a/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComTacticalController.uc +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComTacticalController.uc @@ -574,9 +574,15 @@ simulated function bool Visualizer_CycleToNextAvailableUnit(int Direction) // Force all units to be selectable regardless of action points, if AllowSelectAll is on. if ((`CHEATMGR != None && `CHEATMGR.bAllowSelectAll)) { - bActionsAvailable = true; + if(class'CHHelpers'.default.ExcludeCiviliansFromX2AllowSelectall && SelectNewUnit.GetTeam() == eTeam_Neutral) + { + bActionsAvailable = false; + } + else + { + bActionsAvailable = true; + } } - if( bActionsAvailable && Visualizer_SelectUnit(SelectNewUnit) ) { return true; @@ -1373,7 +1379,15 @@ function bool GameStateMoveUnit(XGUnit kUnit, // --------------------------------------------------------------------- simulated function bool PerformEndTurn(EPlayerEndTurnType eEndTurnType) { - // Aural feedback for player input + // Begin Issue #1486 - When ending the turn using 'improved' mechanics, switch off bAllowSelectAll to allow the AI to process + // the alien turn normally. This maintains FOW and Unit Visibility selections applied previously. + if(class'CHHelpers'.default.UseImprovedX2AllowSelectAllBehavior) + { + `CHEATMGR.bAllowSelectAll = false; + } + // End Issue #1486 + + // Aural feedback for player input if(eEndTurnType == ePlayerEndTurnType_PlayerInput) { PlaySound(SoundCue'SoundUI.PositiveUISelctionCue', true, true); diff --git a/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComTacticalInput.uc b/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComTacticalInput.uc index 04e700b51..370111b0d 100644 --- a/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComTacticalInput.uc +++ b/X2WOTCCommunityHighlander/Src/XComGame/Classes/XComTacticalInput.uc @@ -2884,7 +2884,8 @@ state ActiveUnit_Moving bChangeUnitSuccess = false; bHandled = false; - if( XComTacticalController(Outer).m_XGPlayer.m_eTeam == kTargetedUnit.m_eTeam ) + // Single Line for Issue #1486 - Left click now allows selection of units that don't belong to the player when X2AllowSelectAll is used + if( XComTacticalController(Outer).m_XGPlayer.m_eTeam == kTargetedUnit.m_eTeam || (`CHEATMGR != none && `CHEATMGR.bAllowSelectAll)) { //`log("Want to target: " $ kTargetedUnit.GetHumanReadableName(),,'uixcom');