Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Core/GameEngine/Include/GameClient/View.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ class View : public Snapshot
virtual Bool isTimeFrozen(){ return false;} ///< Freezes time during the next camera movement.
virtual Int getTimeMultiplier() {return 1;}; ///< Get the time multiplier.
virtual void setTimeMultiplier(Int multiple) {}; ///< Set the time multiplier.
virtual void setDefaultView(Real pitch, Real angle, Real maxHeight) {}; // TheSuperHackers @todo Replace with setDefaultPitch(), setMaxHeightScale()
virtual void setCameraHeightAboveGroundLimitsToDefault(Real heightScale = 1.0f) {};
virtual void setDefaultView(Real pitch, Real angle, Real maxHeight) {};
virtual void zoomCamera( Real finalZoom, Int milliseconds, Real easeIn=0.0f, Real easeOut=0.0f ) {};
virtual void pitchCamera( Real finalPitch, Int milliseconds, Real easeIn=0.0f, Real easeOut=0.0f ) {};

Expand All @@ -190,6 +191,7 @@ class View : public Snapshot
virtual Real getHeightAboveGround() { return m_heightAboveGround; }
virtual void setHeightAboveGround(Real z);
virtual void zoom( Real height ); ///< Zoom in/out, closer to the ground, limit to min, or farther away from the ground, limit to max
virtual void setZoomToMax();
virtual void setZoomToDefault() { m_zoom = 1.0f; } ///< Set zoom to default value
virtual void setOkToAdjustHeight( Bool val ) { m_okToAdjustHeight = val; } ///< Set this to adjust camera height

Expand Down
5 changes: 5 additions & 0 deletions Core/GameEngine/Source/GameClient/View.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ void View::zoom( Real height )
setHeightAboveGround(getHeightAboveGround() + height);
}

void View::setZoomToMax()
{
setHeightAboveGround(getHeightAboveGround() + m_maxHeightAboveGround);
Comment on lines +132 to +134

Copilot AI Mar 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

View::setZoomToMax() currently adds m_maxHeightAboveGround to the current height. If m_zoomLimited is false (no clamping), this can overshoot the intended max. Setting the height directly to m_maxHeightAboveGround would better match the method name/intent and be consistent with W3DView::setZoomToMax() semantics.

Suggested change
void View::setZoomToMax()
{
setHeightAboveGround(getHeightAboveGround() + m_maxHeightAboveGround);
// GeneralsX @bugfix ChatGPT 24/03/2026 Make setZoomToMax set absolute max height instead of adding to current height.
void View::setZoomToMax()
{
setHeightAboveGround(m_maxHeightAboveGround);

Copilot uses AI. Check for mistakes.
}

/**
* Center the view on the given coordinate.
*/
Expand Down
4 changes: 3 additions & 1 deletion Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DView.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,12 +204,14 @@ class W3DView : public View, public SubsystemInterface
virtual Int getTimeMultiplier() {return m_timeMultiplier;};///< Get the time multiplier.
virtual void setTimeMultiplier(Int multiple) {m_timeMultiplier = multiple;}; ///< Set the time multiplier.
virtual void setDefaultView(Real pitch, Real angle, Real maxHeight);
virtual void setCameraHeightAboveGroundLimitsToDefault(Real heightScale = 1.0f);
virtual void zoomCamera( Real finalZoom, Int milliseconds, Real easeIn, Real easeOut );
virtual void pitchCamera( Real finalPitch, Int milliseconds, Real easeIn, Real easeOut );

virtual void setHeightAboveGround(Real z);
virtual void setZoom(Real z);
virtual void setZoomToDefault(); ///< Set zoom to default value
virtual void setZoomToMax();
virtual void setZoomToDefault(); ///< Set zoom to default value - TheSuperHackers @info This function resets the camera so will cause scripted cameras to halt

virtual void setFieldOfView( Real angle ); ///< Set the horizontal field of view angle

Expand Down
38 changes: 35 additions & 3 deletions Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1895,6 +1895,31 @@ void W3DView::setPitchToDefault()
m_recalcCamera = true;
}

//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void W3DView::setCameraHeightAboveGroundLimitsToDefault(Real heightScale)
{
// TheSuperHackers @fix Mauller Adjust the camera height to compensate for the screen aspect ratio
Real baseAspectRatio = (Real)DEFAULT_DISPLAY_WIDTH / (Real)DEFAULT_DISPLAY_HEIGHT;
Real currentAspectRatio = (Real)TheTacticalView->getWidth() / (Real)TheTacticalView->getHeight();

Copilot AI Mar 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setCameraHeightAboveGroundLimitsToDefault() computes the current aspect ratio via TheTacticalView->getWidth()/getHeight(). Since this is already a W3DView instance method, using getWidth()/getHeight() (or m_width/m_height) would avoid dependence on the global singleton and reduce the risk of a null/0-height divide if this is ever called before TheTacticalView is fully initialized.

Suggested change
Real currentAspectRatio = (Real)TheTacticalView->getWidth() / (Real)TheTacticalView->getHeight();
// GeneralsX @bugfix copilot 24/03/2026 Use this view's dimensions and guard against zero height.
Real currentAspectRatio;
if (getHeight() > 0) {
currentAspectRatio = (Real)getWidth() / (Real)getHeight();
} else {
currentAspectRatio = baseAspectRatio;
}

Copilot uses AI. Check for mistakes.
Real aspectRatioScale = 0.0f;

if (currentAspectRatio > baseAspectRatio)
{
aspectRatioScale = fabs(( 1 + ( currentAspectRatio - baseAspectRatio) ));
}
else
{
aspectRatioScale = fabs(( 1 - ( baseAspectRatio - currentAspectRatio) ));
}

m_maxHeightAboveGround = TheGlobalData->m_maxCameraHeight * aspectRatioScale * heightScale;
m_minHeightAboveGround = TheGlobalData->m_minCameraHeight * aspectRatioScale;

if (m_minHeightAboveGround > m_maxHeightAboveGround)
m_maxHeightAboveGround = m_minHeightAboveGround;
}

//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void W3DView::setDefaultView(Real pitch, Real angle, Real maxHeight)
Expand Down Expand Up @@ -1938,10 +1963,8 @@ void W3DView::setZoom(Real z)

//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void W3DView::setZoomToDefault()
void W3DView::setZoomToMax()
{
// default zoom has to be max, otherwise players will just zoom to max always

// terrain height + desired height offset == cameraOffset * actual zoom
// find best approximation of max terrain height we can see
Real terrainHeightMax = getHeightAroundPos(m_pos.x, m_pos.y);
Expand All @@ -1954,6 +1977,15 @@ void W3DView::setZoomToDefault()
m_zoom = desiredZoom;
m_heightAboveGround = m_maxHeightAboveGround;

m_cameraAreaConstraintsValid = false; // recalc it.
m_recalcCamera = true;
}

//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void W3DView::setZoomToDefault()
{
// default zoom has to be max, otherwise players will just zoom to max always
stopDoingScriptedCamera();
m_CameraArrivedAtWaypointOnPathFlag = false;
m_cameraAreaConstraintsValid = false;
Expand Down
3 changes: 3 additions & 0 deletions Generals/Code/GameEngine/Include/Common/GlobalData.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,11 @@ class GlobalData : public SubsystemInterface
Real m_cameraPitch;
Real m_cameraYaw;
Real m_cameraHeight;

// GeneralsX @tweak Copilot 23/03/2026 Mirror ZH note: these are 4:3 camera limits, scaled for other aspect ratios.
Real m_maxCameraHeight;
Real m_minCameraHeight;

Real m_terrainHeightAtEdgeOfMap;
Real m_unitDamagedThresh;
Real m_unitReallyDamagedThresh;
Expand Down
2 changes: 1 addition & 1 deletion Generals/Code/GameEngine/Include/GameLogic/ScriptActions.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class ScriptActions : public ScriptActionsInterface

void doCameraTetherNamed(const AsciiString& unit, Bool snapToUnit, Real play);
void doCameraStopTetherNamed();
void doCameraSetDefault(Real pitch, Real angle, Real maxHeight);
void doCameraSetDefault(Real pitch, Real angle, Real heighScale);

Copilot AI Mar 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in parameter name: heighScale should be heightScale to keep the scripting API readable and consistent with W3DView::setCameraHeightAboveGroundLimitsToDefault(Real heightScale).

Suggested change
void doCameraSetDefault(Real pitch, Real angle, Real heighScale);
// GeneralsX @bugfix assistant 24/03/2026 Fix typo in parameter name to use heightScale for consistency with W3DView API.
void doCameraSetDefault(Real pitch, Real angle, Real heightScale);

Copilot uses AI. Check for mistakes.

void doOversizeTheTerrain(Int amount);
void doMoveCameraAlongWaypointPath(const AsciiString& waypoint, Real sec, Real cameraStutterSec);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,10 @@ static void saveOptions()

TheInGameUI->recreateControlBar();
TheInGameUI->refreshCustomUiResources();

// GeneralsX @tweak Copilot 23/03/2026 Update shell camera limits and zoom after display mode changes.
TheTacticalView->setCameraHeightAboveGroundLimitsToDefault();
TheTacticalView->setZoomToMax();
}
}
}
Expand Down
6 changes: 4 additions & 2 deletions Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1346,8 +1346,9 @@ void InGameUI::init()
// make the tactical display the full screen width and height
TheTacticalView->setWidth( TheDisplay->getWidth() );
TheTacticalView->setHeight( TheDisplay->getHeight() );
// GeneralsX @tweak Copilot 23/03/2026 Mirror ZH camera defaults for aspect-ratio-aware limits.
TheTacticalView->setCameraHeightAboveGroundLimitsToDefault();
}
TheTacticalView->setDefaultView(0.0f, 0.0f, 1.0f);

/** @todo this may be the wrong place to create the sidebar, but for now
this is where it lives */
Expand Down Expand Up @@ -2091,7 +2092,8 @@ void InGameUI::reset()
// reset the command bar
TheControlBar->reset();

TheTacticalView->setDefaultView(0.0f, 0.0f, 1.0f);
// GeneralsX @tweak Copilot 23/03/2026 Keep reset aligned with aspect-ratio-aware camera defaults.
TheTacticalView->setCameraHeightAboveGroundLimitsToDefault();

ResetInGameChat();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4270,9 +4270,12 @@ void ScriptActions::doCameraStopTetherNamed()
//-------------------------------------------------------------------------------------------------
/** doCameraSetDefault */
//-------------------------------------------------------------------------------------------------
void ScriptActions::doCameraSetDefault(Real pitch, Real angle, Real maxHeight)
void ScriptActions::doCameraSetDefault(Real pitch, Real angle, Real heighScale)
{
TheTacticalView->setDefaultView(pitch, angle, maxHeight);
// GeneralsX @tweak Copilot 23/03/2026 Mirror ZH scripted camera defaults for aspect-ratio-aware limits.
TheTacticalView->setCameraHeightAboveGroundLimitsToDefault(heighScale);
TheTacticalView->setPitch(pitch);
TheTacticalView->setAngle(angle);
Comment on lines +4273 to +4278

Copilot AI Mar 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in parameter name: heighScale should be heightScale (and consistently renamed in declaration/definition and uses) to avoid propagating a misspelled identifier into the public scripting API.

Copilot uses AI. Check for mistakes.
}

//-------------------------------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1815,9 +1815,12 @@ void GameLogic::startNewGame( Bool loadingSaveGame )
// update the loadscreen
updateLoadProgress(LOAD_PROGRESS_POST_PRELOAD_ASSETS);

// GeneralsX @tweak Copilot 23/03/2026 Keep camera defaults aligned after resolution/aspect changes.
TheTacticalView->setCameraHeightAboveGroundLimitsToDefault();
TheTacticalView->setAngleToDefault();
TheTacticalView->setPitchToDefault();
TheTacticalView->setZoomToDefault();
TheTacticalView->setZoomToMax();

if( TheRecorder )
TheRecorder->initControls();
Expand Down
3 changes: 3 additions & 0 deletions GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,11 @@ class GlobalData : public SubsystemInterface
Real m_cameraPitch;
Real m_cameraYaw;
Real m_cameraHeight;

// TheSuperHackers @info Max and Min camera height for the original 4:3 view, these are then scaled for other aspect ratios.
Real m_maxCameraHeight;
Real m_minCameraHeight;

Real m_terrainHeightAtEdgeOfMap;
Real m_unitDamagedThresh;
Real m_unitReallyDamagedThresh;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class ScriptActions : public ScriptActionsInterface

void doCameraTetherNamed(const AsciiString& unit, Bool snapToUnit, Real play);
void doCameraStopTetherNamed();
void doCameraSetDefault(Real pitch, Real angle, Real maxHeight);
void doCameraSetDefault(Real pitch, Real angle, Real heighScale);

Copilot AI Mar 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in parameter name: heighScale should be heightScale to keep the scripting API readable and consistent with W3DView::setCameraHeightAboveGroundLimitsToDefault(Real heightScale).

Suggested change
void doCameraSetDefault(Real pitch, Real angle, Real heighScale);
// GeneralsX @bugfix Copilot 24/03/2026 Fix typo in camera default height scale parameter name for scripting API clarity
void doCameraSetDefault(Real pitch, Real angle, Real heightScale);

Copilot uses AI. Check for mistakes.

void doOversizeTheTerrain(Int amount);
void doMoveCameraAlongWaypointPath(const AsciiString& waypoint, Real sec, Real cameraStutterSec, Real easeIn, Real easeOut);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,11 @@ static void saveOptions()

TheInGameUI->recreateControlBar();
TheInGameUI->refreshCustomUiResources();

// TheSuperHackers @info Only update the camera limits and set the zoom to max to not interfere with the scripted camera on the shellmap
// The tactical view gets reset at game start, this is here so the shell map looks correct once the resolution is adjusted
TheTacticalView->setCameraHeightAboveGroundLimitsToDefault();
TheTacticalView->setZoomToMax();
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1376,8 +1376,8 @@ void InGameUI::init()
// make the tactical display the full screen width and height
TheTacticalView->setWidth( TheDisplay->getWidth() );
TheTacticalView->setHeight( TheDisplay->getHeight() );
TheTacticalView->setCameraHeightAboveGroundLimitsToDefault();
}
TheTacticalView->setDefaultView(0.0f, 0.0f, 1.0f);

/** @todo this may be the wrong place to create the sidebar, but for now
this is where it lives */
Expand Down Expand Up @@ -2147,7 +2147,7 @@ void InGameUI::reset()
// reset the command bar
TheControlBar->reset();

TheTacticalView->setDefaultView(0.0f, 0.0f, 1.0f);
TheTacticalView->setCameraHeightAboveGroundLimitsToDefault();

ResetInGameChat();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4601,9 +4601,11 @@ void ScriptActions::doCameraStopTetherNamed()
//-------------------------------------------------------------------------------------------------
/** doCameraSetDefault */
//-------------------------------------------------------------------------------------------------
void ScriptActions::doCameraSetDefault(Real pitch, Real angle, Real maxHeight)
void ScriptActions::doCameraSetDefault(Real pitch, Real angle, Real heighScale)
{
TheTacticalView->setDefaultView(pitch, angle, maxHeight);
TheTacticalView->setCameraHeightAboveGroundLimitsToDefault(heighScale);
TheTacticalView->setPitch(pitch);
TheTacticalView->setAngle(angle);
Comment on lines +4604 to +4608

Copilot AI Mar 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in parameter name: heighScale should be heightScale (and consistently renamed in declaration/definition and uses) to avoid propagating a misspelled identifier into the public scripting API.

Copilot uses AI. Check for mistakes.
}

//-------------------------------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2079,9 +2079,12 @@ void GameLogic::startNewGame( Bool loadingSaveGame )
// update the loadscreen
updateLoadProgress(LOAD_PROGRESS_POST_PRELOAD_ASSETS);

// TheSuperHackers @info Initialize the camera height limits to default if the resolution was changed
TheTacticalView->setCameraHeightAboveGroundLimitsToDefault();
TheTacticalView->setAngleToDefault();
TheTacticalView->setPitchToDefault();
TheTacticalView->setZoomToDefault();
TheTacticalView->setZoomToMax();

if( TheRecorder )
TheRecorder->initControls();
Expand Down
16 changes: 16 additions & 0 deletions docs/DEV_BLOG/2026-03-DIARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@

---

## 2026-03-23 (SESSION 91): Backport Camera Aspect-Ratio Default Fixes to Generals Base

Backported the camera default-height integration from ZH to Generals base game paths after validating file-by-file equivalence.

What was changed in Generals:
- Replaced direct `setDefaultView(0.0f, 0.0f, 1.0f)` usage in `InGameUI::init()` and `InGameUI::reset()` with `setCameraHeightAboveGroundLimitsToDefault()`.
- Updated scripted camera default action to use height-scale-aware flow (`setCameraHeightAboveGroundLimitsToDefault`, `setPitch`, `setAngle`) and synced header signature.
- Updated `GameLogic::startNewGame()` to initialize camera height limits before default angle/pitch/zoom and force `setZoomToMax()`.
- Updated `OptionsMenu::saveOptions()` to refresh shell-map camera limits and zoom after runtime resolution changes.
- Added contextual note in `GlobalData.h` documenting that max/min camera height are treated as 4:3 baseline values and scaled for other aspect ratios.

Validation:
- Confirmed pending patch scope is limited to 6 Generals files.
- Checked for accidental literal `\\n` artifacts in edited files; none found.
- Language service reports no syntax errors on changed files.

## 2026-03-23 (SESSION 90): Issue #16 Skirmish Instant-End + Neutral/White Enemy on Linux

**Problem observed**:
Expand Down
Loading