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/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; ///. +*/ + +#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) + , centerOffsetY(0) + {} + ~DisplayEntity(); + + DisplayString* displayString; // is owner + const Image* image; + Int sizeX; + Int sizeY; + Int centerOffsetY; + }; + +public: + + Intro(); + + void update(); + void draw(); + + Bool isDone() const { return m_currentState == IntroState_Done; } + +private: + + 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/Display.cpp b/Core/GameEngine/Source/GameClient/Display.cpp index 41acb4d0003..eef868d4dbc 100644 --- a/Core/GameEngine/Source/GameClient/Display.cpp +++ b/Core/GameEngine/Source/GameClient/Display.cpp @@ -58,11 +58,6 @@ Display::Display() m_cinematicText = AsciiString::TheEmptyString; m_cinematicFont = nullptr; m_cinematicTextFrames = 0; - m_movieHoldTime = -1; - m_copyrightHoldTime = -1; - m_elapsedMovieTime = 0; - m_elapsedCopywriteTime = 0; - m_copyrightDisplayString = nullptr; m_currentlyPlayingMovie.clear(); m_letterBoxFadeStartTime = 0; @@ -200,41 +195,6 @@ void Display::setHeight( UnsignedInt height ) } -//============================================================================ -// Display::playLogoMovie -// minMovieLength is in milliseconds -// minCopyrightLength -//============================================================================ - -void Display::playLogoMovie( AsciiString movieName, Int minMovieLength, Int minCopyrightLength ) -{ - - stopMovie(); - - m_videoStream = TheVideoPlayer->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 new file mode 100644 index 00000000000..0479d43805a --- /dev/null +++ b/Core/GameEngine/Source/GameClient/Intro.cpp @@ -0,0 +1,289 @@ +/* +** 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/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) + { + if (TheGlobalData->m_playIntro) + m_allowedStateFlags |= 1u << IntroState_SizzleMovieWait; + m_allowedStateFlags |= 1u << IntroState_SizzleMovie; + } +} + +void Intro::enterNextState() +{ + Int currentState = m_currentState; + while (currentState < IntroState_Done) + { + ++currentState; + if (m_allowedStateFlags & (1u << currentState)) + break; + } + m_currentState = static_cast(currentState); +} + +void Intro::update() +{ + if (!TheDisplay->isMoviePlaying() && m_waitUntilMs < timeGetTime()) + { + enterNextState(); + + 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; + } + } +} + +void Intro::draw() +{ + switch (m_currentState) + { + case IntroState_TheSuperHackers: drawDisplayEntities(); break; + } +} + +void Intro::doEALogoMovie() +{ + TheWritableGlobalData->m_allowExitOutOfMovies = FALSE; + if (TheGameLODManager && TheGameLODManager->didMemPass()) + TheDisplay->playMovie("EALogoMovie"); + else + TheDisplay->playMovie("EALogoMovie640"); +} + +struct DisplaySetting +{ + DisplaySetting() + : imageName(nullptr) + , font("Arial") + , text(nullptr) + , centerOffsetY(0) + , sizeX(10) + , sizeY(10) + , bold(false) + , centered(false) + {} + + const Char* imageName; + const Char* font; + const WideChar* text; + Int centerOffsetY; + Int sizeX; + Int sizeY; + Bool bold; + Bool centered; +}; + +void Intro::doTheSuperHackers() +{ + std::vector settings; + + const Real resolutionScale = GlobalLanguage::getResolutionFontSizeScale(GlobalLanguage::ResolutionFontSizeMethod_Strict); + const Int screenWidth = TheDisplay->getWidth(); + const Int screenHeight = TheDisplay->getHeight(); + Int centerOffsetY = -(screenHeight * 0.05f); + + // "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 = "Consolas"; + setting.text = m_unicodeStrings[0].str(); + 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); + } + { + // Team name + DisplaySetting setting; + setting.font = "Consolas"; + setting.text = L"THE SUPER HACKERS"; + setting.sizeY = 32; + setting.centerOffsetY = centerOffsetY; + centerOffsetY += setting.sizeY * resolutionScale * 2; + setting.bold = true; + setting.centered = true; + settings.push_back(setting); + } + if constexpr (false) + { + // Website + DisplaySetting setting; + setting.font = "Consolas"; + 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); + } + { + // China Hacker image + DisplaySetting setting; + setting.imageName = "SNHacker2_L"; + setting.centerOffsetY = centerOffsetY; + setting.sizeX = (Int)(122 * 0.50f); + setting.sizeY = (Int)(98 * 0.50f); + settings.push_back(setting); + } + + 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 * 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.centerOffsetY = s.centerOffsetY; + } + + doAsyncWait(3000); + m_fadeValue = 0.0f; +} + +void Intro::doSizzleMovie() +{ + TheWritableGlobalData->m_allowExitOutOfMovies = TRUE; + if (TheGameLODManager && TheGameLODManager->didMemPass()) + TheDisplay->playMovie("Sizzle"); + else + TheDisplay->playMovie("Sizzle640"); +} + +void Intro::doPostIntro() +{ + TheWritableGlobalData->m_breakTheMovie = TRUE; + TheWritableGlobalData->m_allowExitOutOfMovies = TRUE; +} + +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 = (screenHeight / 2) + e.centerOffsetY; + 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 = (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); + } + } + + // 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/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/Include/GameClient/GameClient.h b/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h index 3650be5ee24..91d809c7f02 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; @@ -91,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 @@ -179,6 +181,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/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 d1c956e533a..006c3ed9376 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; @@ -152,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; @@ -434,6 +439,8 @@ void GameClient::init() TheSnowManager->setName("TheSnowManager"); } + m_intro = NEW Intro; + #ifdef PERF_TIMERS TheGraphDraw = new GraphDraw; #endif @@ -516,73 +523,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; - - 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; + m_intro->update(); - - } + if (m_intro->isDone()) + { + delete m_intro; + m_intro = nullptr; TheShell->showShellMap(TRUE); TheShell->showShell(); - TheWritableGlobalData->m_afterIntro = FALSE; } } @@ -624,7 +577,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(); @@ -782,6 +735,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 91541e588d0..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 ) @@ -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);