From e3e8c9c49dc9946ca5cdca2e2659d5ab8faa8882 Mon Sep 17 00:00:00 2001
From: xezon <4720891+xezon@users.noreply.github.com>
Date: Sat, 7 Feb 2026 13:59:34 +0100
Subject: [PATCH 01/10] refactor(intro): Move intro related code to new file
and class (#2267)
---
Core/GameEngine/CMakeLists.txt | 2 +
Core/GameEngine/Include/GameClient/Intro.h | 35 +++++++
Core/GameEngine/Source/GameClient/Intro.cpp | 95 +++++++++++++++++++
.../Include/GameClient/GameClient.h | 2 +
.../Source/GameClient/GameClient.cpp | 77 +++------------
5 files changed, 148 insertions(+), 63 deletions(-)
create mode 100644 Core/GameEngine/Include/GameClient/Intro.h
create mode 100644 Core/GameEngine/Source/GameClient/Intro.cpp
diff --git a/Core/GameEngine/CMakeLists.txt b/Core/GameEngine/CMakeLists.txt
index d3d17ced516..7ab565a16f0 100644
--- a/Core/GameEngine/CMakeLists.txt
+++ b/Core/GameEngine/CMakeLists.txt
@@ -197,6 +197,7 @@ set(GAMEENGINE_SRC
Include/GameClient/Image.h
Include/GameClient/IMEManager.h
# Include/GameClient/InGameUI.h
+ Include/GameClient/Intro.h
Include/GameClient/Keyboard.h
# Include/GameClient/KeyDefs.h
Include/GameClient/LanguageFilter.h
@@ -806,6 +807,7 @@ set(GAMEENGINE_SRC
# Source/GameClient/InGameUI.cpp
Source/GameClient/Input/Keyboard.cpp
Source/GameClient/Input/Mouse.cpp
+ Source/GameClient/Intro.cpp
Source/GameClient/LanguageFilter.cpp
Source/GameClient/Line2D.cpp
Source/GameClient/MapUtil.cpp
diff --git a/Core/GameEngine/Include/GameClient/Intro.h b/Core/GameEngine/Include/GameClient/Intro.h
new file mode 100644
index 00000000000..4b866796bad
--- /dev/null
+++ b/Core/GameEngine/Include/GameClient/Intro.h
@@ -0,0 +1,35 @@
+/*
+** Command & Conquer Generals Zero Hour(tm)
+** Copyright 2026 TheSuperHackers
+**
+** This program is free software: you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation, either version 3 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program. If not, see .
+*/
+
+#pragma once
+
+class Intro
+{
+public:
+
+ Intro();
+
+ void update();
+
+ Bool isDone() const { return m_done; }
+
+private:
+
+ Bool m_playSizzle;
+ Bool m_done;
+};
diff --git a/Core/GameEngine/Source/GameClient/Intro.cpp b/Core/GameEngine/Source/GameClient/Intro.cpp
new file mode 100644
index 00000000000..ab1d75dacaf
--- /dev/null
+++ b/Core/GameEngine/Source/GameClient/Intro.cpp
@@ -0,0 +1,95 @@
+/*
+** Command & Conquer Generals Zero Hour(tm)
+** Copyright 2026 TheSuperHackers
+**
+** This program is free software: you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation, either version 3 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program. If not, see .
+*/
+
+#include "PreRTS.h"
+#include "GameClient/Intro.h"
+
+#include "Common/GameLOD.h"
+
+#include "GameClient/Display.h"
+#include "GameClient/GameWindowManager.h"
+
+#include "GameLogic/FPUControl.h"
+
+
+Intro::Intro()
+ : m_playSizzle(false)
+ , m_done(false)
+{
+}
+
+void Intro::update()
+{
+ // We need to show the movie first.
+ if(TheGlobalData->m_playIntro && !TheDisplay->isMoviePlaying())
+ {
+ if(TheGameLODManager && TheGameLODManager->didMemPass())
+ TheDisplay->playLogoMovie("EALogoMovie", 5000, 3000);
+ else
+ TheDisplay->playLogoMovie("EALogoMovie640", 5000, 3000);
+ TheWritableGlobalData->m_playIntro = FALSE;
+ TheWritableGlobalData->m_afterIntro = TRUE;
+ m_playSizzle = TRUE;
+ }
+
+ // We must show the movie first and then we can display the shell.
+ if(TheGlobalData->m_afterIntro && !TheDisplay->isMoviePlaying())
+ {
+ if( m_playSizzle && TheGlobalData->m_playSizzle )
+ {
+ TheWritableGlobalData->m_allowExitOutOfMovies = TRUE;
+ if(TheGameLODManager && TheGameLODManager->didMemPass())
+ TheDisplay->playMovie("Sizzle");
+ else
+ TheDisplay->playMovie("Sizzle640");
+ m_playSizzle = FALSE;
+ }
+ else
+ {
+ TheWritableGlobalData->m_breakTheMovie = TRUE;
+ TheWritableGlobalData->m_allowExitOutOfMovies = TRUE;
+
+ if(TheGameLODManager && !TheGameLODManager->didMemPass())
+ {
+ TheWritableGlobalData->m_breakTheMovie = FALSE;
+
+ WindowLayout *legal = TheWindowManager->winCreateLayout("Menus/LegalPage.wnd");
+ if(legal)
+ {
+ legal->hide(FALSE);
+ legal->bringForward();
+ Int beginTime = timeGetTime();
+ while(beginTime + 4000 > timeGetTime() )
+ {
+ TheWindowManager->update();
+ // redraw all views, update the GUI
+ TheDisplay->draw();
+ Sleep(100);
+ }
+ setFPMode();
+ legal->destroyWindows();
+ deleteInstance(legal);
+ }
+ TheWritableGlobalData->m_breakTheMovie = TRUE;
+ }
+
+ TheWritableGlobalData->m_afterIntro = FALSE;
+ m_done = TRUE;
+ }
+ }
+}
diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h b/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h
index 3650be5ee24..0100dcb05ee 100644
--- a/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h
+++ b/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h
@@ -44,6 +44,7 @@ class Drawable;
class FontLibrary;
class GameWindowManager;
class InGameUI;
+class Intro;
class Keyboard;
class Mouse;
class ParticleSystemManager;
@@ -179,6 +180,7 @@ class GameClient : public SubsystemInterface,
private:
+ Intro* m_intro;
UnsignedInt m_renderedObjectCount; ///< Keeps track of the number of rendered objects -- resets each frame.
//---------------------------------------------------------------------------
diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp
index d1c956e533a..07e6ff59758 100644
--- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp
+++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp
@@ -43,7 +43,6 @@
#include "Common/ThingFactory.h"
#include "Common/ThingTemplate.h"
#include "Common/Xfer.h"
-#include "Common/GameLOD.h"
#include "GameClient/Anim2D.h"
#include "GameClient/CampaignManager.h"
#include "GameClient/ChallengeGenerals.h"
@@ -64,6 +63,7 @@
#include "GameClient/HotKey.h"
#include "GameClient/IMEManager.h"
#include "GameClient/InGameUI.h"
+#include "GameClient/Intro.h"
#include "GameClient/Keyboard.h"
#include "GameClient/LanguageFilter.h"
#include "GameClient/LookAtXlat.h"
@@ -79,7 +79,6 @@
#include "GameClient/View.h"
#include "GameClient/VideoPlayer.h"
#include "GameClient/WindowXlat.h"
-#include "GameLogic/FPUControl.h"
#include "GameLogic/GameLogic.h"
#include "GameLogic/GhostObject.h"
#include "GameLogic/Object.h"
@@ -109,6 +108,8 @@ GameClient::GameClient()
m_nextDrawableID = (DrawableID)1;
TheDrawGroupInfo = new DrawGroupInfo;
+
+ m_intro = nullptr;
}
//std::vector preloadTextureNamesGlobalHack;
@@ -232,6 +233,8 @@ GameClient::~GameClient()
delete TheSnowManager;
TheSnowManager = nullptr;
+ delete m_intro;
+
}
//-------------------------------------------------------------------------------------------------
@@ -434,6 +437,8 @@ void GameClient::init()
TheSnowManager->setName("TheSnowManager");
}
+ m_intro = NEW Intro;
+
#ifdef PERF_TIMERS
TheGraphDraw = new GraphDraw;
#endif
@@ -516,73 +521,19 @@ void GameClient::update()
// create the FRAME_TICK message
GameMessage *frameMsg = TheMessageStream->appendMessage( GameMessage::MSG_FRAME_TICK );
frameMsg->appendTimestampArgument( getFrame() );
- static Bool playSizzle = FALSE;
- // We need to show the movie first.
- if(TheGlobalData->m_playIntro && !TheDisplay->isMoviePlaying())
- {
- if(TheGameLODManager && TheGameLODManager->didMemPass())
- TheDisplay->playLogoMovie("EALogoMovie", 5000, 3000);
- else
- TheDisplay->playLogoMovie("EALogoMovie640", 5000, 3000);
- TheWritableGlobalData->m_playIntro = FALSE;
- TheWritableGlobalData->m_afterIntro = TRUE;
- playSizzle = TRUE;
- }
- //Initial Game Condition. We must show the movie first and then we can display the shell
- if(TheGlobalData->m_afterIntro && !TheDisplay->isMoviePlaying())
+ // Update intro
+ if (m_intro != nullptr)
{
- if( playSizzle && TheGlobalData->m_playSizzle )
- {
- TheWritableGlobalData->m_allowExitOutOfMovies = TRUE;
- if(TheGameLODManager && TheGameLODManager->didMemPass())
- TheDisplay->playMovie("Sizzle");
- else
- TheDisplay->playMovie("Sizzle640");
- playSizzle = FALSE;
- }
- else
- {
- TheWritableGlobalData->m_breakTheMovie = TRUE;
- TheWritableGlobalData->m_allowExitOutOfMovies = TRUE;
+ m_intro->update();
- if(TheGameLODManager && !TheGameLODManager->didMemPass())
- {
- TheWritableGlobalData->m_breakTheMovie = FALSE;
-
- WindowLayout *legal = TheWindowManager->winCreateLayout("Menus/LegalPage.wnd");
- if(legal)
- {
- legal->hide(FALSE);
- legal->bringForward();
- Int beginTime = timeGetTime();
- while(beginTime + 4000 > timeGetTime() )
- {
- if (GameClient::isMovieAbortRequested())
- {
- break;
- }
-
- TheWindowManager->update();
- // redraw all views, update the GUI
- TheDisplay->draw();
- Sleep(100);
- }
- setFPMode();
-
-
- legal->destroyWindows();
- deleteInstance(legal);
-
- }
- TheWritableGlobalData->m_breakTheMovie = TRUE;
-
-
- }
+ if (m_intro->isDone())
+ {
+ delete m_intro;
+ m_intro = nullptr;
TheShell->showShellMap(TRUE);
TheShell->showShell();
- TheWritableGlobalData->m_afterIntro = FALSE;
}
}
From 27cdb47e51654666671797b326e616000f5f950a Mon Sep 17 00:00:00 2001
From: xezon <4720891+xezon@users.noreply.github.com>
Date: Thu, 5 Feb 2026 20:56:28 +0100
Subject: [PATCH 02/10] refactor(intro): Simplify the intro state machine in
Intro class (#2267)
---
Core/GameEngine/Include/GameClient/Intro.h | 22 ++-
Core/GameEngine/Source/GameClient/Intro.cpp | 131 +++++++++++-------
.../GameEngine/Include/Common/GlobalData.h | 1 -
.../GameEngine/Source/Common/CommandLine.cpp | 3 -
.../GameEngine/Source/Common/GameEngine.cpp | 6 -
.../GameEngine/Source/Common/GlobalData.cpp | 1 -
.../Source/GameClient/GameClient.cpp | 2 +-
7 files changed, 100 insertions(+), 66 deletions(-)
diff --git a/Core/GameEngine/Include/GameClient/Intro.h b/Core/GameEngine/Include/GameClient/Intro.h
index 4b866796bad..665d670acb9 100644
--- a/Core/GameEngine/Include/GameClient/Intro.h
+++ b/Core/GameEngine/Include/GameClient/Intro.h
@@ -20,16 +20,32 @@
class Intro
{
+ enum IntroState
+ {
+ IntroState_Start,
+ IntroState_EALogoMovie,
+ IntroState_SizzleMovie,
+ IntroState_LegalPage,
+ IntroState_Done,
+ };
+
public:
Intro();
void update();
- Bool isDone() const { return m_done; }
+ Bool isDone() const { return m_currentState == IntroState_Done; }
private:
- Bool m_playSizzle;
- Bool m_done;
+ void enterNextState();
+
+ void doEALogoMovie();
+ void doSizzleMovie();
+ void doLegalPage();
+ void doPostIntro();
+
+ IntroState m_currentState;
+ UnsignedInt m_allowedStateFlags;
};
diff --git a/Core/GameEngine/Source/GameClient/Intro.cpp b/Core/GameEngine/Source/GameClient/Intro.cpp
index ab1d75dacaf..6e5d8da1c5c 100644
--- a/Core/GameEngine/Source/GameClient/Intro.cpp
+++ b/Core/GameEngine/Source/GameClient/Intro.cpp
@@ -28,68 +28,97 @@
Intro::Intro()
- : m_playSizzle(false)
- , m_done(false)
+ : m_currentState(IntroState_Start)
+ , m_allowedStateFlags(0)
{
+ if (TheGlobalData->m_playIntro)
+ {
+ m_allowedStateFlags |= 1u << IntroState_EALogoMovie;
+ }
+
+ if (TheGlobalData->m_playSizzle)
+ {
+ m_allowedStateFlags |= 1u << IntroState_SizzleMovie;
+ }
+
+ if (TheGameLODManager && !TheGameLODManager->didMemPass())
+ {
+ m_allowedStateFlags |= 1u << IntroState_LegalPage;
+ }
}
-void Intro::update()
+void Intro::enterNextState()
{
- // We need to show the movie first.
- if(TheGlobalData->m_playIntro && !TheDisplay->isMoviePlaying())
+ Int currentState = m_currentState;
+ while (currentState < IntroState_Done)
{
- if(TheGameLODManager && TheGameLODManager->didMemPass())
- TheDisplay->playLogoMovie("EALogoMovie", 5000, 3000);
- else
- TheDisplay->playLogoMovie("EALogoMovie640", 5000, 3000);
- TheWritableGlobalData->m_playIntro = FALSE;
- TheWritableGlobalData->m_afterIntro = TRUE;
- m_playSizzle = TRUE;
+ ++currentState;
+ if (m_allowedStateFlags & (1u << currentState))
+ break;
}
+ m_currentState = static_cast(currentState);
+}
- // We must show the movie first and then we can display the shell.
- if(TheGlobalData->m_afterIntro && !TheDisplay->isMoviePlaying())
+void Intro::update()
+{
+ if (!TheDisplay->isMoviePlaying())
{
- if( m_playSizzle && TheGlobalData->m_playSizzle )
+ enterNextState();
+
+ switch (m_currentState)
{
- TheWritableGlobalData->m_allowExitOutOfMovies = TRUE;
- if(TheGameLODManager && TheGameLODManager->didMemPass())
- TheDisplay->playMovie("Sizzle");
- else
- TheDisplay->playMovie("Sizzle640");
- m_playSizzle = FALSE;
+ case IntroState_EALogoMovie: doEALogoMovie(); break;
+ case IntroState_SizzleMovie: doSizzleMovie(); break;
+ case IntroState_LegalPage: doLegalPage(); break;
+ case IntroState_Done: doPostIntro(); break;
}
- else
+ }
+}
+
+void Intro::doEALogoMovie()
+{
+ TheWritableGlobalData->m_allowExitOutOfMovies = FALSE;
+ if (TheGameLODManager && TheGameLODManager->didMemPass())
+ TheDisplay->playLogoMovie("EALogoMovie", 5000, 3000);
+ else
+ TheDisplay->playLogoMovie("EALogoMovie640", 5000, 3000);
+}
+
+void Intro::doSizzleMovie()
+{
+ TheWritableGlobalData->m_allowExitOutOfMovies = TRUE;
+ if (TheGameLODManager && TheGameLODManager->didMemPass())
+ TheDisplay->playMovie("Sizzle");
+ else
+ TheDisplay->playMovie("Sizzle640");
+}
+
+
+void Intro::doLegalPage()
+{
+ TheWritableGlobalData->m_breakTheMovie = FALSE;
+ WindowLayout *legal = TheWindowManager->winCreateLayout("Menus/LegalPage.wnd");
+ if (legal)
+ {
+ legal->hide(FALSE);
+ legal->bringForward();
+ Int beginTime = timeGetTime();
+ while (beginTime + 4000 > timeGetTime() )
{
- TheWritableGlobalData->m_breakTheMovie = TRUE;
- TheWritableGlobalData->m_allowExitOutOfMovies = TRUE;
-
- if(TheGameLODManager && !TheGameLODManager->didMemPass())
- {
- TheWritableGlobalData->m_breakTheMovie = FALSE;
-
- WindowLayout *legal = TheWindowManager->winCreateLayout("Menus/LegalPage.wnd");
- if(legal)
- {
- legal->hide(FALSE);
- legal->bringForward();
- Int beginTime = timeGetTime();
- while(beginTime + 4000 > timeGetTime() )
- {
- TheWindowManager->update();
- // redraw all views, update the GUI
- TheDisplay->draw();
- Sleep(100);
- }
- setFPMode();
- legal->destroyWindows();
- deleteInstance(legal);
- }
- TheWritableGlobalData->m_breakTheMovie = TRUE;
- }
-
- TheWritableGlobalData->m_afterIntro = FALSE;
- m_done = TRUE;
+ TheWindowManager->update();
+ // redraw all views, update the GUI
+ TheDisplay->draw();
+ Sleep(100);
}
+ setFPMode();
+ legal->destroyWindows();
+ deleteInstance(legal);
}
+ TheWritableGlobalData->m_breakTheMovie = TRUE;
+}
+
+void Intro::doPostIntro()
+{
+ TheWritableGlobalData->m_breakTheMovie = TRUE;
+ TheWritableGlobalData->m_allowExitOutOfMovies = TRUE;
}
diff --git a/GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h b/GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h
index 4c5130e1c05..8a3447ef8ff 100644
--- a/GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h
+++ b/GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h
@@ -365,7 +365,6 @@ class GlobalData : public SubsystemInterface
Bool m_shellMapOn; ///< User can set the shell map not to load
Bool m_playIntro; ///< Flag to say if we're to play the intro or not
Bool m_playSizzle; ///< Flag to say whether we play the sizzle movie after the logo movie.
- Bool m_afterIntro; ///< we need to tell the game our intro is done
Bool m_allowExitOutOfMovies; ///< flag to allow exit out of movies only after the Intro has played
Bool m_loadScreenRender; ///< flag to disallow rendering of almost everything during a loadscreen
diff --git a/GeneralsMD/Code/GameEngine/Source/Common/CommandLine.cpp b/GeneralsMD/Code/GameEngine/Source/Common/CommandLine.cpp
index 8289418703a..1162b34cc24 100644
--- a/GeneralsMD/Code/GameEngine/Source/Common/CommandLine.cpp
+++ b/GeneralsMD/Code/GameEngine/Source/Common/CommandLine.cpp
@@ -412,7 +412,6 @@ Int parseHeadless(char *args[], int num)
{
TheWritableGlobalData->m_headless = TRUE;
TheWritableGlobalData->m_playIntro = FALSE;
- TheWritableGlobalData->m_afterIntro = TRUE;
TheWritableGlobalData->m_playSizzle = FALSE;
// TheSuperHackers @fix bobtista 03/02/2026 Set DX8Wrapper_IsWindowed to false in headless
@@ -437,7 +436,6 @@ Int parseReplay(char *args[], int num)
TheWritableGlobalData->m_simulateReplays.push_back(filename);
TheWritableGlobalData->m_playIntro = FALSE;
- TheWritableGlobalData->m_afterIntro = TRUE;
TheWritableGlobalData->m_playSizzle = FALSE;
TheWritableGlobalData->m_shellMapOn = FALSE;
@@ -790,7 +788,6 @@ Int parseNoShaders(char *args[], int)
Int parseNoLogo(char *args[], int)
{
TheWritableGlobalData->m_playIntro = FALSE;
- TheWritableGlobalData->m_afterIntro = TRUE;
TheWritableGlobalData->m_playSizzle = FALSE;
return 1;
diff --git a/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp b/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp
index 74781f946a5..6cefe6cb122 100644
--- a/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp
+++ b/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp
@@ -745,9 +745,6 @@ void GameEngine::init()
}
}
- if(!TheGlobalData->m_playIntro)
- TheWritableGlobalData->m_afterIntro = TRUE;
-
}
catch (ErrorCode ec)
{
@@ -769,9 +766,6 @@ void GameEngine::init()
RELEASE_CRASH(("Uncaught Exception during initialization."));
}
- if(!TheGlobalData->m_playIntro)
- TheWritableGlobalData->m_afterIntro = TRUE;
-
resetSubsystems();
HideControlBar();
diff --git a/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp b/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp
index 9900029d48d..4b42531fe08 100644
--- a/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp
+++ b/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp
@@ -1012,7 +1012,6 @@ GlobalData::GlobalData()
m_shellMapOn =TRUE;
m_playIntro = TRUE;
m_playSizzle = TRUE;
- m_afterIntro = FALSE;
m_allowExitOutOfMovies = FALSE;
m_loadScreenRender = FALSE;
diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp
index 07e6ff59758..92b9df49402 100644
--- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp
+++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp
@@ -575,7 +575,7 @@ void GameClient::update()
TheInGameUI->setCameraTrackingDrawable( FALSE );
}
- if(TheGlobalData->m_playIntro || TheGlobalData->m_afterIntro)
+ if (m_intro != nullptr)
{
// redraw all views, update the GUI
TheDisplay->UPDATE();
From 0e71109ecf4c7a587e6f202d964c517954c8fe2e Mon Sep 17 00:00:00 2001
From: xezon <4720891+xezon@users.noreply.github.com>
Date: Thu, 5 Feb 2026 22:50:29 +0100
Subject: [PATCH 03/10] fix(intro): Remove non functional copyright string and
simplify logo movie code (#2267)
---
Core/GameEngine/Include/GameClient/Display.h | 6 --
Core/GameEngine/Include/GameClient/Intro.h | 3 +
Core/GameEngine/Source/GameClient/Display.cpp | 75 +------------------
Core/GameEngine/Source/GameClient/Intro.cpp | 15 +++-
.../W3DDevice/GameClient/W3DDisplay.cpp | 9 +--
5 files changed, 17 insertions(+), 91 deletions(-)
diff --git a/Core/GameEngine/Include/GameClient/Display.h b/Core/GameEngine/Include/GameClient/Display.h
index 8c022244206..3dd7e78efc1 100644
--- a/Core/GameEngine/Include/GameClient/Display.h
+++ b/Core/GameEngine/Include/GameClient/Display.h
@@ -153,7 +153,6 @@ class Display : public SubsystemInterface
Int endX, Int endY ) = 0;
/// FullScreen video playback
- virtual void playLogoMovie( AsciiString movieName, Int minMovieLength, Int minCopyrightLength );
virtual void playMovie( AsciiString movieName );
virtual void stopMovie();
virtual Bool isMoviePlaying();
@@ -216,11 +215,6 @@ class Display : public SubsystemInterface
Real m_letterBoxFadeLevel; ///open( movieName );
-
- if ( m_videoStream == nullptr )
- {
- return;
- }
-
- m_currentlyPlayingMovie = movieName;
- m_movieHoldTime = minMovieLength;
- m_copyrightHoldTime = minCopyrightLength;
- m_elapsedMovieTime = timeGetTime(); // we're using time get time because legal wants actual "Seconds"
-
- m_videoBuffer = createVideoBuffer();
- if ( m_videoBuffer == nullptr ||
- !m_videoBuffer->allocate( m_videoStream->width(),
- m_videoStream->height())
- )
- {
- stopMovie();
- return;
- }
-
-}
-
//============================================================================
// Display::playMovie
//============================================================================
@@ -286,13 +246,6 @@ void Display::stopMovie()
//TheScriptEngine->notifyOfCompletedVideo(m_currentlyPlayingMovie); // Removing this sync-error cause MDC
m_currentlyPlayingMovie = AsciiString::TheEmptyString;
}
- if(m_copyrightDisplayString)
- {
- TheDisplayStringManager->freeDisplayString(m_copyrightDisplayString);
- m_copyrightDisplayString = nullptr;
- }
- m_copyrightHoldTime = -1;
- m_movieHoldTime = -1;
}
//============================================================================
@@ -308,34 +261,8 @@ void Display::update()
m_videoStream->frameDecompress();
m_videoStream->frameRender( m_videoBuffer );
if( m_videoStream->frameIndex() != m_videoStream->frameCount() - 1)
- m_videoStream->frameNext();
- else if( m_copyrightHoldTime >= 0 ||m_movieHoldTime >= 0 )
{
- if( m_elapsedCopywriteTime == 0 && m_elapsedCopywriteTime >= 0)
- {
- //display the copyrighttext;
- deleteInstance(m_copyrightDisplayString);
- m_copyrightDisplayString = TheDisplayStringManager->newDisplayString();
- m_copyrightDisplayString->setText(TheGameText->fetch("GUI:EACopyright"));
- if (TheGlobalLanguageData && TheGlobalLanguageData->m_copyrightFont.name.isNotEmpty())
- { FontDesc *fontdesc=&TheGlobalLanguageData->m_copyrightFont;
- m_copyrightDisplayString->setFont(TheFontLibrary->getFont(fontdesc->name,
- TheGlobalLanguageData->adjustFontSize(fontdesc->size),
- fontdesc->bold));
- }
- else
- m_copyrightDisplayString->setFont(TheFontLibrary->getFont("Courier",
- TheGlobalLanguageData->adjustFontSize(12), TRUE));
- m_elapsedCopywriteTime = timeGetTime();
- }
- if(m_movieHoldTime + m_elapsedMovieTime < timeGetTime() &&
- m_copyrightHoldTime + m_elapsedCopywriteTime < timeGetTime())
- {
- m_movieHoldTime = -1;
- m_elapsedMovieTime = 0;
- m_elapsedCopywriteTime = 0;
- m_copyrightHoldTime = -1;
- }
+ m_videoStream->frameNext();
}
else
{
diff --git a/Core/GameEngine/Source/GameClient/Intro.cpp b/Core/GameEngine/Source/GameClient/Intro.cpp
index 6e5d8da1c5c..b821e34422a 100644
--- a/Core/GameEngine/Source/GameClient/Intro.cpp
+++ b/Core/GameEngine/Source/GameClient/Intro.cpp
@@ -30,6 +30,7 @@
Intro::Intro()
: m_currentState(IntroState_Start)
, m_allowedStateFlags(0)
+ , m_waitUntilMs(0)
{
if (TheGlobalData->m_playIntro)
{
@@ -38,6 +39,8 @@ Intro::Intro()
if (TheGlobalData->m_playSizzle)
{
+ if (TheGlobalData->m_playIntro)
+ m_allowedStateFlags |= 1u << IntroState_SizzleMovieWait;
m_allowedStateFlags |= 1u << IntroState_SizzleMovie;
}
@@ -61,13 +64,14 @@ void Intro::enterNextState()
void Intro::update()
{
- if (!TheDisplay->isMoviePlaying())
+ if (!TheDisplay->isMoviePlaying() && m_waitUntilMs < timeGetTime())
{
enterNextState();
switch (m_currentState)
{
case IntroState_EALogoMovie: doEALogoMovie(); break;
+ case IntroState_SizzleMovieWait: doAsyncWait(1000); break;
case IntroState_SizzleMovie: doSizzleMovie(); break;
case IntroState_LegalPage: doLegalPage(); break;
case IntroState_Done: doPostIntro(); break;
@@ -79,9 +83,9 @@ void Intro::doEALogoMovie()
{
TheWritableGlobalData->m_allowExitOutOfMovies = FALSE;
if (TheGameLODManager && TheGameLODManager->didMemPass())
- TheDisplay->playLogoMovie("EALogoMovie", 5000, 3000);
+ TheDisplay->playMovie("EALogoMovie");
else
- TheDisplay->playLogoMovie("EALogoMovie640", 5000, 3000);
+ TheDisplay->playMovie("EALogoMovie640");
}
void Intro::doSizzleMovie()
@@ -122,3 +126,8 @@ void Intro::doPostIntro()
TheWritableGlobalData->m_breakTheMovie = TRUE;
TheWritableGlobalData->m_allowExitOutOfMovies = TRUE;
}
+
+void Intro::doAsyncWait(UnsignedInt milliseconds)
+{
+ m_waitUntilMs = timeGetTime() + milliseconds;
+}
diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp
index 91541e588d0..a84011de270 100644
--- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp
+++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp
@@ -2008,14 +2008,7 @@ void W3DDisplay::draw()
// TheSuperHackers @bugfix Mauller 20/07/2025 scale videos based on screen size so they are shown in their original aspect
drawScaledVideoBuffer( m_videoBuffer, m_videoStream );
}
- if( m_copyrightDisplayString )
- {
- Int x, y, dX, dY;
- m_copyrightDisplayString->getSize(&dX, &dY);
- x = (getWidth() / 2) - (dX /2);
- y = getHeight() - dY - 20 ;
- m_copyrightDisplayString->draw(x, y, GameMakeColor(0,0,0,255), GameMakeColor(0,0,0,0),0,0);
- }
+
// render letter box before debug display so debug info isn't hidden
renderLetterBox(now);
From 33f47d40a6198d4f2bed13acc257e32b6e0afc3a Mon Sep 17 00:00:00 2001
From: xezon <4720891+xezon@users.noreply.github.com>
Date: Thu, 5 Feb 2026 22:56:10 +0100
Subject: [PATCH 04/10] tweak(intro): Remove superfluous legal page window from
intro sequence (#2267)
---
Core/GameEngine/Include/GameClient/Intro.h | 2 --
Core/GameEngine/Source/GameClient/Intro.cpp | 32 ---------------------
2 files changed, 34 deletions(-)
diff --git a/Core/GameEngine/Include/GameClient/Intro.h b/Core/GameEngine/Include/GameClient/Intro.h
index e298463af03..01fb8250da0 100644
--- a/Core/GameEngine/Include/GameClient/Intro.h
+++ b/Core/GameEngine/Include/GameClient/Intro.h
@@ -26,7 +26,6 @@ class Intro
IntroState_EALogoMovie,
IntroState_SizzleMovieWait,
IntroState_SizzleMovie,
- IntroState_LegalPage,
IntroState_Done,
};
@@ -44,7 +43,6 @@ class Intro
void doEALogoMovie();
void doSizzleMovie();
- void doLegalPage();
void doPostIntro();
void doAsyncWait(UnsignedInt milliseconds);
diff --git a/Core/GameEngine/Source/GameClient/Intro.cpp b/Core/GameEngine/Source/GameClient/Intro.cpp
index b821e34422a..d4299acd3bb 100644
--- a/Core/GameEngine/Source/GameClient/Intro.cpp
+++ b/Core/GameEngine/Source/GameClient/Intro.cpp
@@ -24,8 +24,6 @@
#include "GameClient/Display.h"
#include "GameClient/GameWindowManager.h"
-#include "GameLogic/FPUControl.h"
-
Intro::Intro()
: m_currentState(IntroState_Start)
@@ -43,11 +41,6 @@ Intro::Intro()
m_allowedStateFlags |= 1u << IntroState_SizzleMovieWait;
m_allowedStateFlags |= 1u << IntroState_SizzleMovie;
}
-
- if (TheGameLODManager && !TheGameLODManager->didMemPass())
- {
- m_allowedStateFlags |= 1u << IntroState_LegalPage;
- }
}
void Intro::enterNextState()
@@ -73,7 +66,6 @@ void Intro::update()
case IntroState_EALogoMovie: doEALogoMovie(); break;
case IntroState_SizzleMovieWait: doAsyncWait(1000); break;
case IntroState_SizzleMovie: doSizzleMovie(); break;
- case IntroState_LegalPage: doLegalPage(); break;
case IntroState_Done: doPostIntro(); break;
}
}
@@ -97,30 +89,6 @@ void Intro::doSizzleMovie()
TheDisplay->playMovie("Sizzle640");
}
-
-void Intro::doLegalPage()
-{
- TheWritableGlobalData->m_breakTheMovie = FALSE;
- WindowLayout *legal = TheWindowManager->winCreateLayout("Menus/LegalPage.wnd");
- if (legal)
- {
- legal->hide(FALSE);
- legal->bringForward();
- Int beginTime = timeGetTime();
- while (beginTime + 4000 > timeGetTime() )
- {
- TheWindowManager->update();
- // redraw all views, update the GUI
- TheDisplay->draw();
- Sleep(100);
- }
- setFPMode();
- legal->destroyWindows();
- deleteInstance(legal);
- }
- TheWritableGlobalData->m_breakTheMovie = TRUE;
-}
-
void Intro::doPostIntro()
{
TheWritableGlobalData->m_breakTheMovie = TRUE;
From 89c8906a32b01dc24d811e78bc17417012a2529d Mon Sep 17 00:00:00 2001
From: xezon <4720891+xezon@users.noreply.github.com>
Date: Sat, 7 Feb 2026 00:01:08 +0100
Subject: [PATCH 05/10] feat(intro): Add short Intro Logo for The Super Hackers
team (#2267)
---
Core/GameEngine/Include/GameClient/Intro.h | 34 ++++
Core/GameEngine/Source/GameClient/Intro.cpp | 177 ++++++++++++++++++
.../Include/GameClient/GameClient.h | 1 +
.../Source/GameClient/GameClient.cpp | 8 +
.../W3DDevice/GameClient/W3DDisplay.cpp | 2 +-
5 files changed, 221 insertions(+), 1 deletion(-)
diff --git a/Core/GameEngine/Include/GameClient/Intro.h b/Core/GameEngine/Include/GameClient/Intro.h
index 01fb8250da0..8429cc2933d 100644
--- a/Core/GameEngine/Include/GameClient/Intro.h
+++ b/Core/GameEngine/Include/GameClient/Intro.h
@@ -18,22 +18,48 @@
#pragma once
+#include
+
+class DisplayString;
+class Image;
+
class Intro
{
enum IntroState
{
IntroState_Start,
IntroState_EALogoMovie,
+ IntroState_TheSuperHackersWait,
+ IntroState_TheSuperHackers,
IntroState_SizzleMovieWait,
IntroState_SizzleMovie,
IntroState_Done,
};
+ struct DisplayEntity
+ {
+ DisplayEntity()
+ : displayString(nullptr)
+ , image(nullptr)
+ , sizeX(10)
+ , sizeY(10)
+ , screenHeightFactor(0.5f)
+ {}
+ ~DisplayEntity();
+
+ DisplayString* displayString;
+ const Image* image;
+ Int sizeX;
+ Int sizeY;
+ Real screenHeightFactor; // 0..1
+ };
+
public:
Intro();
void update();
+ void draw();
Bool isDone() const { return m_currentState == IntroState_Done; }
@@ -42,11 +68,19 @@ class Intro
void enterNextState();
void doEALogoMovie();
+ void doTheSuperHackers();
void doSizzleMovie();
void doPostIntro();
void doAsyncWait(UnsignedInt milliseconds);
+ void drawDisplayEntities();
+
+private:
+
IntroState m_currentState;
UnsignedInt m_allowedStateFlags;
UnsignedInt m_waitUntilMs;
+ UnicodeString m_unicodeStrings[1];
+ std::vector m_displayEntities;
+ Real m_fadeValue;
};
diff --git a/Core/GameEngine/Source/GameClient/Intro.cpp b/Core/GameEngine/Source/GameClient/Intro.cpp
index d4299acd3bb..fd8858f2fae 100644
--- a/Core/GameEngine/Source/GameClient/Intro.cpp
+++ b/Core/GameEngine/Source/GameClient/Intro.cpp
@@ -19,20 +19,35 @@
#include "PreRTS.h"
#include "GameClient/Intro.h"
+#include "Common/FramePacer.h"
#include "Common/GameLOD.h"
#include "GameClient/Display.h"
+#include "GameClient/DisplayStringManager.h"
+#include "GameClient/GameText.h"
#include "GameClient/GameWindowManager.h"
+#include "GameClient/GlobalLanguage.h"
+#include "GameClient/Image.h"
+Intro::DisplayEntity::~DisplayEntity()
+{
+ TheDisplayStringManager->freeDisplayString(displayString);
+}
+
Intro::Intro()
: m_currentState(IntroState_Start)
, m_allowedStateFlags(0)
, m_waitUntilMs(0)
+ , m_fadeValue(0.0f)
{
if (TheGlobalData->m_playIntro)
{
+ // Please be kind and do not remove the EA logo movie. This game was built by EA. It lasts just 3 seconds.
m_allowedStateFlags |= 1u << IntroState_EALogoMovie;
+ // Please be kind and do not remove the custom logo screen when building on top of the work of The Super Hackers.
+ m_allowedStateFlags |= 1u << IntroState_TheSuperHackersWait;
+ m_allowedStateFlags |= 1u << IntroState_TheSuperHackers;
}
if (TheGlobalData->m_playSizzle)
@@ -64,6 +79,8 @@ void Intro::update()
switch (m_currentState)
{
case IntroState_EALogoMovie: doEALogoMovie(); break;
+ case IntroState_TheSuperHackersWait: doAsyncWait(800); break;
+ case IntroState_TheSuperHackers: doTheSuperHackers(); break;
case IntroState_SizzleMovieWait: doAsyncWait(1000); break;
case IntroState_SizzleMovie: doSizzleMovie(); break;
case IntroState_Done: doPostIntro(); break;
@@ -71,6 +88,14 @@ void Intro::update()
}
}
+void Intro::draw()
+{
+ switch (m_currentState)
+ {
+ case IntroState_TheSuperHackers: drawDisplayEntities(); break;
+ }
+}
+
void Intro::doEALogoMovie()
{
TheWritableGlobalData->m_allowExitOutOfMovies = FALSE;
@@ -80,6 +105,103 @@ void Intro::doEALogoMovie()
TheDisplay->playMovie("EALogoMovie640");
}
+struct DisplaySetting
+{
+ DisplaySetting()
+ : imageName(nullptr)
+ , text(nullptr)
+ , screenHeightFactor(0.5f)
+ , sizeX(10)
+ , sizeY(10)
+ , bold(false)
+ , centered(false)
+ {}
+
+ const Char* imageName;
+ const WideChar* text;
+ Real screenHeightFactor;
+ Int sizeX;
+ Int sizeY;
+ Bool bold;
+ Bool centered;
+};
+
+void Intro::doTheSuperHackers()
+{
+ std::vector settings;
+
+ constexpr const Real startY = 0.35f;
+
+ {
+ // Pretext
+ m_unicodeStrings[0] = TheGameText->FETCH_OR_SUBSTITUTE("CREDITS:CustomIntroPretext", L"Game improved by");
+ DisplaySetting setting;
+ setting.text = m_unicodeStrings[0].str();
+ setting.screenHeightFactor = startY;
+ setting.sizeY = 16;
+ setting.bold = false;
+ setting.centered = true;
+ settings.push_back(setting);
+ }
+ {
+ // Team name
+ DisplaySetting setting;
+ setting.text = L"The Super Hackers";
+ setting.screenHeightFactor = startY + 0.05f;
+ setting.sizeY = 32;
+ setting.bold = true;
+ setting.centered = true;
+ settings.push_back(setting);
+ }
+ {
+ // Website
+ DisplaySetting setting;
+ setting.text = L"www.thesuperhackers.org";
+ setting.screenHeightFactor = startY + 0.20f;
+ setting.sizeY = 16;
+ setting.bold = false;
+ setting.centered = true;
+ settings.push_back(setting);
+ }
+ {
+ // China Hacker image
+ DisplaySetting setting;
+ setting.imageName = "SNHacker2_L";
+ setting.screenHeightFactor = startY + 0.27f;
+ setting.sizeX = (Int)(122 * 0.50f);
+ setting.sizeY = (Int)(98 * 0.50f);
+ settings.push_back(setting);
+ }
+
+ const Real fontScale = GlobalLanguage::getResolutionFontSizeScale(GlobalLanguage::ResolutionFontSizeMethod_Strict);
+
+ m_displayEntities.resize(settings.size());
+
+ for (size_t i = 0; i < m_displayEntities.size(); ++i)
+ {
+ const DisplaySetting& s = settings[i];
+ DisplayEntity& e = m_displayEntities[i];
+ e.sizeX = Int(s.sizeX * fontScale);
+ e.sizeY = Int(s.sizeY * fontScale);
+ if (s.text != nullptr)
+ {
+ e.displayString = TheDisplayStringManager->newDisplayString();
+ e.displayString->setText(s.text);
+ // Consolas is Windows Vista native, can be installed in 2000, XP
+ e.displayString->setFont(TheFontLibrary->getFont("Consolas", e.sizeY, s.bold));
+ e.displayString->setWordWrapCentered(s.centered);
+ }
+ if (s.imageName != nullptr)
+ {
+ e.image = TheMappedImageCollection->findImageByName(s.imageName);
+ }
+ e.screenHeightFactor = s.screenHeightFactor;
+ }
+
+ doAsyncWait(3000);
+ m_fadeValue = 0.0f;
+}
+
void Intro::doSizzleMovie()
{
TheWritableGlobalData->m_allowExitOutOfMovies = TRUE;
@@ -99,3 +221,58 @@ void Intro::doAsyncWait(UnsignedInt milliseconds)
{
m_waitUntilMs = timeGetTime() + milliseconds;
}
+
+void Intro::drawDisplayEntities()
+{
+ const Real alpha = 255.0f * clamp(0.0f, m_fadeValue, 1.0f);
+ const Color color = GameMakeColor(255, 255, 255, (Int)alpha);
+ const Color dropColor = GameMakeColor(255, 255, 255, 0);
+ const Int screenWidth = TheDisplay->getWidth();
+ const Int screenHeight = TheDisplay->getHeight();
+
+ for (size_t i = 0; i < m_displayEntities.size(); ++i)
+ {
+ DisplayEntity& e = m_displayEntities[i];
+ if (e.displayString != nullptr)
+ {
+ ICoord2D pos;
+ e.displayString->getSize(&pos.x, &pos.y);
+ pos.x = (screenWidth / 2) - (pos.x / 2);
+ pos.y = (Int)(e.screenHeightFactor * screenHeight);
+ e.displayString->setWordWrap(screenWidth);
+ e.displayString->draw(pos.x, pos.y, color, dropColor);
+ }
+ if (e.image != nullptr)
+ {
+ IRegion2D region;
+ region.lo.x = (screenWidth / 2) - (e.sizeX / 2);
+ region.hi.x = (screenWidth / 2) + (e.sizeX / 2);
+ region.lo.y = (Int)(e.screenHeightFactor * screenHeight);
+ region.hi.y = region.lo.y + e.sizeY;
+ TheDisplay->drawImage(e.image, region.lo.x, region.lo.y, region.hi.x, region.hi.y, color);
+ }
+ }
+
+ // Note: Applies fade after drawing the text once because originally the text takes one draw update to 'settle in' first.
+
+ constexpr const Real fadeInMs = 500.f;
+ constexpr const Real fadeOutMs = 125.f;
+
+ if (timeGetTime() + fadeOutMs > m_waitUntilMs)
+ {
+ if (m_fadeValue > 0.0f)
+ {
+ // Fade out
+ m_fadeValue -= TheFramePacer->getUpdateTime() * (1000.f / fadeOutMs);
+ if (m_fadeValue < 0.0f)
+ m_fadeValue = 0.0f;
+ }
+ }
+ else if (m_fadeValue < 1.0f)
+ {
+ // Fade in
+ m_fadeValue += TheFramePacer->getUpdateTime() * (1000.f / fadeInMs);
+ if (m_fadeValue > 1.0f)
+ m_fadeValue = 1.0f;
+ }
+}
diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h b/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h
index 0100dcb05ee..91d809c7f02 100644
--- a/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h
+++ b/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h
@@ -92,6 +92,7 @@ class GameClient : public SubsystemInterface,
// subsystem methods
virtual void init() override; ///< Initialize resources
virtual void update() override; ///< Updates the GUI, display, audio, etc
+ virtual void draw() override;
virtual void reset() override; ///< reset system
virtual void setFrame( UnsignedInt frame ) { m_frame = frame; } ///< Set the GameClient's internal frame number
diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp
index 92b9df49402..8245dd655a6 100644
--- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp
+++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp
@@ -733,6 +733,14 @@ void GameClient::update()
}
}
+void GameClient::draw()
+{
+ if (m_intro != nullptr)
+ {
+ m_intro->draw();
+ }
+}
+
void GameClient::step()
{
TheDisplay->step();
diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp
index a84011de270..eec3d78c68b 100644
--- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp
+++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp
@@ -1997,7 +1997,7 @@ void W3DDisplay::draw()
// draw the user interface
TheInGameUI->DRAW();
- // end of video example code
+ TheGameClient->DRAW();
// draw the mouse
if( TheMouse )
From 6d31c63d6982728b6fae8a075c32f95a02af2807 Mon Sep 17 00:00:00 2001
From: xezon <4720891+xezon@users.noreply.github.com>
Date: Sat, 18 Apr 2026 19:42:07 +0200
Subject: [PATCH 06/10] fixup! feat(intro): Add short Intro Logo for The Super
Hackers team (#2267)
---
Core/GameEngine/Source/GameClient/Intro.cpp | 29 ++++++++++++++-------
1 file changed, 20 insertions(+), 9 deletions(-)
diff --git a/Core/GameEngine/Source/GameClient/Intro.cpp b/Core/GameEngine/Source/GameClient/Intro.cpp
index fd8858f2fae..1f53dbdea4d 100644
--- a/Core/GameEngine/Source/GameClient/Intro.cpp
+++ b/Core/GameEngine/Source/GameClient/Intro.cpp
@@ -109,6 +109,7 @@ struct DisplaySetting
{
DisplaySetting()
: imageName(nullptr)
+ , font("Arial")
, text(nullptr)
, screenHeightFactor(0.5f)
, sizeX(10)
@@ -118,6 +119,7 @@ struct DisplaySetting
{}
const Char* imageName;
+ const Char* font;
const WideChar* text;
Real screenHeightFactor;
Int sizeX;
@@ -132,10 +134,16 @@ void Intro::doTheSuperHackers()
constexpr const Real startY = 0.35f;
+ const Real fontScale = GlobalLanguage::getResolutionFontSizeScale(GlobalLanguage::ResolutionFontSizeMethod_Strict);
+
+ // "Lucida Console" is Windows XP native.
+ // "Consolas" is Windows Vista native, can be installed in 2000, XP
+
{
// Pretext
m_unicodeStrings[0] = TheGameText->FETCH_OR_SUBSTITUTE("CREDITS:CustomIntroPretext", L"Game improved by");
DisplaySetting setting;
+ setting.font = "Lucida Console";
setting.text = m_unicodeStrings[0].str();
setting.screenHeightFactor = startY;
setting.sizeY = 16;
@@ -146,16 +154,23 @@ void Intro::doTheSuperHackers()
{
// Team name
DisplaySetting setting;
- setting.text = L"The Super Hackers";
- setting.screenHeightFactor = startY + 0.05f;
- setting.sizeY = 32;
- setting.bold = true;
+ setting.font = "Lucida Console";
+ setting.text =
+ L"\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u000a"
+ L"\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u2588\u2588\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u000a"
+ L"\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u000a"
+ L"\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u2588\u2588\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u000a"
+ L"\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020";
+ setting.screenHeightFactor = startY + 0.07f;
+ setting.sizeY = 6;
+ setting.bold = false;
setting.centered = true;
settings.push_back(setting);
}
{
// Website
DisplaySetting setting;
+ setting.font = "Lucida Console";
setting.text = L"www.thesuperhackers.org";
setting.screenHeightFactor = startY + 0.20f;
setting.sizeY = 16;
@@ -173,8 +188,6 @@ void Intro::doTheSuperHackers()
settings.push_back(setting);
}
- const Real fontScale = GlobalLanguage::getResolutionFontSizeScale(GlobalLanguage::ResolutionFontSizeMethod_Strict);
-
m_displayEntities.resize(settings.size());
for (size_t i = 0; i < m_displayEntities.size(); ++i)
@@ -187,9 +200,7 @@ void Intro::doTheSuperHackers()
{
e.displayString = TheDisplayStringManager->newDisplayString();
e.displayString->setText(s.text);
- // Consolas is Windows Vista native, can be installed in 2000, XP
- e.displayString->setFont(TheFontLibrary->getFont("Consolas", e.sizeY, s.bold));
- e.displayString->setWordWrapCentered(s.centered);
+ e.displayString->setFont(TheFontLibrary->getFont(s.font, e.sizeY, s.bold));
}
if (s.imageName != nullptr)
{
From 60208cc6c422ac06eb5dcedbb97cbc0217132309 Mon Sep 17 00:00:00 2001
From: xezon <4720891+xezon@users.noreply.github.com>
Date: Sun, 31 May 2026 12:29:33 +0200
Subject: [PATCH 07/10] fixup! feat(intro): Add short Intro Logo for The Super
Hackers team (#2267)
---
Core/GameEngine/Include/GameClient/Intro.h | 4 +--
Core/GameEngine/Source/GameClient/Intro.cpp | 39 ++++++++++++---------
2 files changed, 24 insertions(+), 19 deletions(-)
diff --git a/Core/GameEngine/Include/GameClient/Intro.h b/Core/GameEngine/Include/GameClient/Intro.h
index 8429cc2933d..85cf393b49e 100644
--- a/Core/GameEngine/Include/GameClient/Intro.h
+++ b/Core/GameEngine/Include/GameClient/Intro.h
@@ -43,7 +43,7 @@ class Intro
, image(nullptr)
, sizeX(10)
, sizeY(10)
- , screenHeightFactor(0.5f)
+ , centerOffsetY(0)
{}
~DisplayEntity();
@@ -51,7 +51,7 @@ class Intro
const Image* image;
Int sizeX;
Int sizeY;
- Real screenHeightFactor; // 0..1
+ Int centerOffsetY;
};
public:
diff --git a/Core/GameEngine/Source/GameClient/Intro.cpp b/Core/GameEngine/Source/GameClient/Intro.cpp
index 1f53dbdea4d..0c9219e2e01 100644
--- a/Core/GameEngine/Source/GameClient/Intro.cpp
+++ b/Core/GameEngine/Source/GameClient/Intro.cpp
@@ -111,7 +111,7 @@ struct DisplaySetting
: imageName(nullptr)
, font("Arial")
, text(nullptr)
- , screenHeightFactor(0.5f)
+ , centerOffsetY(0)
, sizeX(10)
, sizeY(10)
, bold(false)
@@ -121,7 +121,7 @@ struct DisplaySetting
const Char* imageName;
const Char* font;
const WideChar* text;
- Real screenHeightFactor;
+ Int centerOffsetY;
Int sizeX;
Int sizeY;
Bool bold;
@@ -132,9 +132,10 @@ void Intro::doTheSuperHackers()
{
std::vector settings;
- constexpr const Real startY = 0.35f;
-
- const Real fontScale = GlobalLanguage::getResolutionFontSizeScale(GlobalLanguage::ResolutionFontSizeMethod_Strict);
+ const Real resolutionScale = GlobalLanguage::getResolutionFontSizeScale(GlobalLanguage::ResolutionFontSizeMethod_Strict);
+ const Int screenWidth = TheDisplay->getWidth();
+ const Int screenHeight = TheDisplay->getHeight();
+ Int centerOffsetY = -(screenHeight * 0.05f);
// "Lucida Console" is Windows XP native.
// "Consolas" is Windows Vista native, can be installed in 2000, XP
@@ -145,8 +146,10 @@ void Intro::doTheSuperHackers()
DisplaySetting setting;
setting.font = "Lucida Console";
setting.text = m_unicodeStrings[0].str();
- setting.screenHeightFactor = startY;
setting.sizeY = 16;
+ centerOffsetY -= setting.sizeY * resolutionScale * 2;
+ setting.centerOffsetY = centerOffsetY;
+ centerOffsetY += setting.sizeY * resolutionScale * 2;
setting.bold = false;
setting.centered = true;
settings.push_back(setting);
@@ -154,15 +157,16 @@ void Intro::doTheSuperHackers()
{
// Team name
DisplaySetting setting;
- setting.font = "Lucida Console";
+ setting.font = "Courier New";
setting.text =
L"\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u000a"
L"\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u2588\u2588\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u000a"
L"\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u000a"
L"\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u2588\u2588\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u000a"
L"\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020";
- setting.screenHeightFactor = startY + 0.07f;
setting.sizeY = 6;
+ setting.centerOffsetY = centerOffsetY;
+ centerOffsetY += setting.sizeY * 5 * resolutionScale * 2.5f;
setting.bold = false;
setting.centered = true;
settings.push_back(setting);
@@ -171,9 +175,10 @@ void Intro::doTheSuperHackers()
// Website
DisplaySetting setting;
setting.font = "Lucida Console";
- setting.text = L"www.thesuperhackers.org";
- setting.screenHeightFactor = startY + 0.20f;
+ setting.text = L"thesuperhackers.org";
setting.sizeY = 16;
+ setting.centerOffsetY = centerOffsetY;
+ centerOffsetY += setting.sizeY * resolutionScale * 2;
setting.bold = false;
setting.centered = true;
settings.push_back(setting);
@@ -182,7 +187,7 @@ void Intro::doTheSuperHackers()
// China Hacker image
DisplaySetting setting;
setting.imageName = "SNHacker2_L";
- setting.screenHeightFactor = startY + 0.27f;
+ setting.centerOffsetY = centerOffsetY;
setting.sizeX = (Int)(122 * 0.50f);
setting.sizeY = (Int)(98 * 0.50f);
settings.push_back(setting);
@@ -194,19 +199,20 @@ void Intro::doTheSuperHackers()
{
const DisplaySetting& s = settings[i];
DisplayEntity& e = m_displayEntities[i];
- e.sizeX = Int(s.sizeX * fontScale);
- e.sizeY = Int(s.sizeY * fontScale);
+ e.sizeX = Int(s.sizeX * resolutionScale);
+ e.sizeY = Int(s.sizeY * resolutionScale);
if (s.text != nullptr)
{
e.displayString = TheDisplayStringManager->newDisplayString();
e.displayString->setText(s.text);
e.displayString->setFont(TheFontLibrary->getFont(s.font, e.sizeY, s.bold));
+ e.displayString->setWordWrap(screenWidth);
}
if (s.imageName != nullptr)
{
e.image = TheMappedImageCollection->findImageByName(s.imageName);
}
- e.screenHeightFactor = s.screenHeightFactor;
+ e.centerOffsetY = s.centerOffsetY;
}
doAsyncWait(3000);
@@ -249,8 +255,7 @@ void Intro::drawDisplayEntities()
ICoord2D pos;
e.displayString->getSize(&pos.x, &pos.y);
pos.x = (screenWidth / 2) - (pos.x / 2);
- pos.y = (Int)(e.screenHeightFactor * screenHeight);
- e.displayString->setWordWrap(screenWidth);
+ pos.y = (screenHeight / 2) + e.centerOffsetY;
e.displayString->draw(pos.x, pos.y, color, dropColor);
}
if (e.image != nullptr)
@@ -258,7 +263,7 @@ void Intro::drawDisplayEntities()
IRegion2D region;
region.lo.x = (screenWidth / 2) - (e.sizeX / 2);
region.hi.x = (screenWidth / 2) + (e.sizeX / 2);
- region.lo.y = (Int)(e.screenHeightFactor * screenHeight);
+ region.lo.y = (screenHeight / 2) + e.centerOffsetY;
region.hi.y = region.lo.y + e.sizeY;
TheDisplay->drawImage(e.image, region.lo.x, region.lo.y, region.hi.x, region.hi.y, color);
}
From 5e10a092780fbe9371736f3ee27079c69c4c3bb8 Mon Sep 17 00:00:00 2001
From: xezon <4720891+xezon@users.noreply.github.com>
Date: Fri, 10 Jul 2026 22:46:59 +0200
Subject: [PATCH 08/10] fixup! feat(intro): Add short Intro Logo for The Super
Hackers team (#2267)
---
Core/GameEngine/Source/GameClient/Intro.cpp | 21 ++++++++-------------
1 file changed, 8 insertions(+), 13 deletions(-)
diff --git a/Core/GameEngine/Source/GameClient/Intro.cpp b/Core/GameEngine/Source/GameClient/Intro.cpp
index 0c9219e2e01..0479d43805a 100644
--- a/Core/GameEngine/Source/GameClient/Intro.cpp
+++ b/Core/GameEngine/Source/GameClient/Intro.cpp
@@ -137,14 +137,13 @@ void Intro::doTheSuperHackers()
const Int screenHeight = TheDisplay->getHeight();
Int centerOffsetY = -(screenHeight * 0.05f);
- // "Lucida Console" is Windows XP native.
// "Consolas" is Windows Vista native, can be installed in 2000, XP
{
// Pretext
m_unicodeStrings[0] = TheGameText->FETCH_OR_SUBSTITUTE("CREDITS:CustomIntroPretext", L"Game improved by");
DisplaySetting setting;
- setting.font = "Lucida Console";
+ setting.font = "Consolas";
setting.text = m_unicodeStrings[0].str();
setting.sizeY = 16;
centerOffsetY -= setting.sizeY * resolutionScale * 2;
@@ -157,24 +156,20 @@ void Intro::doTheSuperHackers()
{
// Team name
DisplaySetting setting;
- setting.font = "Courier New";
- setting.text =
- L"\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u000a"
- L"\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u2588\u2588\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u000a"
- L"\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u000a"
- L"\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u2588\u2588\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u000a"
- L"\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020\u2588\u2588\u0020\u0020\u0020\u2588\u2588\u0020\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u0020";
- setting.sizeY = 6;
+ setting.font = "Consolas";
+ setting.text = L"THE SUPER HACKERS";
+ setting.sizeY = 32;
setting.centerOffsetY = centerOffsetY;
- centerOffsetY += setting.sizeY * 5 * resolutionScale * 2.5f;
- setting.bold = false;
+ centerOffsetY += setting.sizeY * resolutionScale * 2;
+ setting.bold = true;
setting.centered = true;
settings.push_back(setting);
}
+ if constexpr (false)
{
// Website
DisplaySetting setting;
- setting.font = "Lucida Console";
+ setting.font = "Consolas";
setting.text = L"thesuperhackers.org";
setting.sizeY = 16;
setting.centerOffsetY = centerOffsetY;
From eade69376127738ce7e5838075083cfa891f6254 Mon Sep 17 00:00:00 2001
From: xezon <4720891+xezon@users.noreply.github.com>
Date: Sun, 12 Jul 2026 16:59:35 +0200
Subject: [PATCH 09/10] fixup! feat(intro): Add short Intro Logo for The Super
Hackers team (#2267)
---
Core/GameEngine/Include/GameClient/Intro.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Core/GameEngine/Include/GameClient/Intro.h b/Core/GameEngine/Include/GameClient/Intro.h
index 85cf393b49e..383ce8db12b 100644
--- a/Core/GameEngine/Include/GameClient/Intro.h
+++ b/Core/GameEngine/Include/GameClient/Intro.h
@@ -47,7 +47,7 @@ class Intro
{}
~DisplayEntity();
- DisplayString* displayString;
+ DisplayString* displayString; // is owner
const Image* image;
Int sizeX;
Int sizeY;
From ceb12df708980370675ae9121437be4ccbeacaae Mon Sep 17 00:00:00 2001
From: xezon <4720891+xezon@users.noreply.github.com>
Date: Sun, 12 Jul 2026 17:07:07 +0200
Subject: [PATCH 10/10] fixup! refactor(intro): Move intro related code to new
file and class (#2267)
---
GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp
index 8245dd655a6..006c3ed9376 100644
--- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp
+++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp
@@ -153,6 +153,10 @@ GameClient::~GameClient()
}
m_drawableList = nullptr;
+ // Should be destroyed before the Display String Manager
+ delete m_intro;
+ m_intro = nullptr;
+
// delete the ray effects
delete TheRayEffects;
TheRayEffects = nullptr;
@@ -233,8 +237,6 @@ GameClient::~GameClient()
delete TheSnowManager;
TheSnowManager = nullptr;
- delete m_intro;
-
}
//-------------------------------------------------------------------------------------------------