Skip to content

Commit 832f3d8

Browse files
committed
feat(intro): Add short Intro Logo for The Super Hackers team (#2267)
1 parent 33336d1 commit 832f3d8

5 files changed

Lines changed: 221 additions & 1 deletion

File tree

Core/GameEngine/Include/GameClient/Intro.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,48 @@
1818

1919
#pragma once
2020

21+
#include <vector>
22+
23+
class DisplayString;
24+
class Image;
25+
2126
class Intro
2227
{
2328
enum IntroState
2429
{
2530
IntroState_Start,
2631
IntroState_EALogoMovie,
32+
IntroState_TheSuperHackersWait,
33+
IntroState_TheSuperHackers,
2734
IntroState_SizzleMovieWait,
2835
IntroState_SizzleMovie,
2936
IntroState_Done,
3037
};
3138

39+
struct DisplayEntity
40+
{
41+
DisplayEntity()
42+
: displayString(nullptr)
43+
, image(nullptr)
44+
, sizeX(10)
45+
, sizeY(10)
46+
, screenHeightFactor(0.5f)
47+
{}
48+
~DisplayEntity();
49+
50+
DisplayString* displayString;
51+
const Image* image;
52+
Int sizeX;
53+
Int sizeY;
54+
Real screenHeightFactor; // 0..1
55+
};
56+
3257
public:
3358

3459
Intro();
3560

3661
void update();
62+
void draw();
3763

3864
void enterNextState();
3965

@@ -42,11 +68,19 @@ class Intro
4268
private:
4369

4470
void doEALogoMovie();
71+
void doTheSuperHackers();
4572
void doSizzleMovie();
4673
void doPostIntro();
4774
void doAsyncWait(UnsignedInt milliseconds);
4875

76+
void drawDisplayEntities();
77+
78+
private:
79+
4980
IntroState m_currentState;
5081
UnsignedInt m_allowedStateFlags;
5182
UnsignedInt m_waitUntilMs;
83+
UnicodeString m_unicodeStrings[1];
84+
std::vector<DisplayEntity> m_displayEntities;
85+
Real m_fadeValue;
5286
};

Core/GameEngine/Source/GameClient/Intro.cpp

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,35 @@
1919
#include "PreRTS.h"
2020
#include "GameClient/Intro.h"
2121

22+
#include "Common/FramePacer.h"
2223
#include "Common/GameLOD.h"
2324

2425
#include "GameClient/Display.h"
26+
#include "GameClient/DisplayStringManager.h"
27+
#include "GameClient/GameText.h"
2528
#include "GameClient/GameWindowManager.h"
29+
#include "GameClient/GlobalLanguage.h"
30+
#include "GameClient/Image.h"
2631

2732

33+
Intro::DisplayEntity::~DisplayEntity()
34+
{
35+
TheDisplayStringManager->freeDisplayString(displayString);
36+
}
37+
2838
Intro::Intro()
2939
: m_currentState(IntroState_Start)
3040
, m_allowedStateFlags(0)
3141
, m_waitUntilMs(0)
42+
, m_fadeValue(0.0f)
3243
{
3344
if (TheGlobalData->m_playIntro)
3445
{
46+
// Please be kind and do not remove the EA logo movie. This game was built by EA. It lasts just 3 seconds.
3547
m_allowedStateFlags |= 1u << IntroState_EALogoMovie;
48+
// Please be kind and do not remove the custom logo screen when building on top of the work of The Super Hackers.
49+
m_allowedStateFlags |= 1u << IntroState_TheSuperHackersWait;
50+
m_allowedStateFlags |= 1u << IntroState_TheSuperHackers;
3651
}
3752

3853
if (TheGlobalData->m_playSizzle)
@@ -64,13 +79,23 @@ void Intro::update()
6479
switch (m_currentState)
6580
{
6681
case IntroState_EALogoMovie: doEALogoMovie(); break;
82+
case IntroState_TheSuperHackersWait: doAsyncWait(800); break;
83+
case IntroState_TheSuperHackers: doTheSuperHackers(); break;
6784
case IntroState_SizzleMovieWait: doAsyncWait(1000); break;
6885
case IntroState_SizzleMovie: doSizzleMovie(); break;
6986
case IntroState_Done: doPostIntro(); break;
7087
}
7188
}
7289
}
7390

91+
void Intro::draw()
92+
{
93+
switch (m_currentState)
94+
{
95+
case IntroState_TheSuperHackers: drawDisplayEntities(); break;
96+
}
97+
}
98+
7499
void Intro::doEALogoMovie()
75100
{
76101
TheWritableGlobalData->m_allowExitOutOfMovies = FALSE;
@@ -80,6 +105,103 @@ void Intro::doEALogoMovie()
80105
TheDisplay->playMovie("EALogoMovie640");
81106
}
82107

108+
struct DisplaySetting
109+
{
110+
DisplaySetting()
111+
: imageName(nullptr)
112+
, text(nullptr)
113+
, screenHeightFactor(0.5f)
114+
, sizeX(10)
115+
, sizeY(10)
116+
, bold(false)
117+
, centered(false)
118+
{}
119+
120+
const Char* imageName;
121+
const WideChar* text;
122+
Real screenHeightFactor;
123+
Int sizeX;
124+
Int sizeY;
125+
Bool bold;
126+
Bool centered;
127+
};
128+
129+
void Intro::doTheSuperHackers()
130+
{
131+
std::vector<DisplaySetting> settings;
132+
133+
constexpr const Real startY = 0.35f;
134+
135+
{
136+
// Pretext
137+
m_unicodeStrings[0] = TheGameText->FETCH_OR_SUBSTITUTE("CREDITS:CustomIntroPretext", L"Game improved by");
138+
DisplaySetting setting;
139+
setting.text = m_unicodeStrings[0].str();
140+
setting.screenHeightFactor = startY;
141+
setting.sizeY = 16;
142+
setting.bold = false;
143+
setting.centered = true;
144+
settings.push_back(setting);
145+
}
146+
{
147+
// Team name
148+
DisplaySetting setting;
149+
setting.text = L"The Super Hackers";
150+
setting.screenHeightFactor = startY + 0.05f;
151+
setting.sizeY = 32;
152+
setting.bold = true;
153+
setting.centered = true;
154+
settings.push_back(setting);
155+
}
156+
{
157+
// Website
158+
DisplaySetting setting;
159+
setting.text = L"www.thesuperhackers.org";
160+
setting.screenHeightFactor = startY + 0.20f;
161+
setting.sizeY = 16;
162+
setting.bold = false;
163+
setting.centered = true;
164+
settings.push_back(setting);
165+
}
166+
{
167+
// China Hacker image
168+
DisplaySetting setting;
169+
setting.imageName = "SNHacker2_L";
170+
setting.screenHeightFactor = startY + 0.27f;
171+
setting.sizeX = (Int)(122 * 0.50f);
172+
setting.sizeY = (Int)(98 * 0.50f);
173+
settings.push_back(setting);
174+
}
175+
176+
const Real fontScale = GlobalLanguage::getResolutionFontSizeScale(GlobalLanguage::ResolutionFontSizeMethod_Strict);
177+
178+
m_displayEntities.resize(settings.size());
179+
180+
for (size_t i = 0; i < m_displayEntities.size(); ++i)
181+
{
182+
const DisplaySetting& s = settings[i];
183+
DisplayEntity& e = m_displayEntities[i];
184+
e.sizeX = Int(s.sizeX * fontScale);
185+
e.sizeY = Int(s.sizeY * fontScale);
186+
if (s.text != nullptr)
187+
{
188+
e.displayString = TheDisplayStringManager->newDisplayString();
189+
e.displayString->setText(s.text);
190+
// Consolas is Windows Vista native, can be installed in 2000, XP
191+
e.displayString->setFont(TheFontLibrary->getFont("Consolas", e.sizeY, s.bold));
192+
e.displayString->setWordWrapCentered(s.centered);
193+
}
194+
if (s.imageName != nullptr)
195+
{
196+
e.image = TheMappedImageCollection->findImageByName(s.imageName);
197+
}
198+
e.screenHeightFactor = s.screenHeightFactor;
199+
}
200+
201+
doAsyncWait(3000);
202+
m_fadeValue = 0.0f;
203+
}
204+
83205
void Intro::doSizzleMovie()
84206
{
85207
TheWritableGlobalData->m_allowExitOutOfMovies = TRUE;
@@ -99,3 +221,58 @@ void Intro::doAsyncWait(UnsignedInt milliseconds)
99221
{
100222
m_waitUntilMs = timeGetTime() + milliseconds;
101223
}
224+
225+
void Intro::drawDisplayEntities()
226+
{
227+
const Real alpha = 255.0f * clamp(0.0f, m_fadeValue, 1.0f);
228+
const Color color = GameMakeColor(255, 255, 255, (Int)alpha);
229+
const Color dropColor = GameMakeColor(255, 255, 255, 0);
230+
const Int screenWidth = TheDisplay->getWidth();
231+
const Int screenHeight = TheDisplay->getHeight();
232+
233+
for (size_t i = 0; i < m_displayEntities.size(); ++i)
234+
{
235+
DisplayEntity& e = m_displayEntities[i];
236+
if (e.displayString != nullptr)
237+
{
238+
ICoord2D pos;
239+
e.displayString->getSize(&pos.x, &pos.y);
240+
pos.x = (screenWidth / 2) - (pos.x / 2);
241+
pos.y = (Int)(e.screenHeightFactor * screenHeight);
242+
e.displayString->setWordWrap(screenWidth);
243+
e.displayString->draw(pos.x, pos.y, color, dropColor);
244+
}
245+
if (e.image != nullptr)
246+
{
247+
IRegion2D region;
248+
region.lo.x = (screenWidth / 2) - (e.sizeX / 2);
249+
region.hi.x = (screenWidth / 2) + (e.sizeX / 2);
250+
region.lo.y = (Int)(e.screenHeightFactor * screenHeight);
251+
region.hi.y = region.lo.y + e.sizeY;
252+
TheDisplay->drawImage(e.image, region.lo.x, region.lo.y, region.hi.x, region.hi.y, color);
253+
}
254+
}
255+
256+
// Note: Applies fade after drawing the text once because originally the text takes one draw update to 'settle in' first.
257+
258+
constexpr const Real fadeInMs = 500.f;
259+
constexpr const Real fadeOutMs = 125.f;
260+
261+
if (timeGetTime() + fadeOutMs > m_waitUntilMs)
262+
{
263+
if (m_fadeValue > 0.0f)
264+
{
265+
// Fade out
266+
m_fadeValue -= TheFramePacer->getUpdateTime() * (1000.f / fadeOutMs);
267+
if (m_fadeValue < 0.0f)
268+
m_fadeValue = 0.0f;
269+
}
270+
}
271+
else if (m_fadeValue < 1.0f)
272+
{
273+
// Fade in
274+
m_fadeValue += TheFramePacer->getUpdateTime() * (1000.f / fadeInMs);
275+
if (m_fadeValue > 1.0f)
276+
m_fadeValue = 1.0f;
277+
}
278+
}

GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ class GameClient : public SubsystemInterface,
9292
// subsystem methods
9393
virtual void init(); ///< Initialize resources
9494
virtual void update(); ///< Updates the GUI, display, audio, etc
95+
virtual void draw();
9596
virtual void reset(); ///< reset system
9697

9798
virtual void setFrame( UnsignedInt frame ) { m_frame = frame; } ///< Set the GameClient's internal frame number

GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,14 @@ void GameClient::update()
731731
}
732732
}
733733

734+
void GameClient::draw()
735+
{
736+
if (m_intro != nullptr)
737+
{
738+
m_intro->draw();
739+
}
740+
}
741+
734742
void GameClient::step()
735743
{
736744
TheDisplay->step();

GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1859,7 +1859,7 @@ void W3DDisplay::draw()
18591859
// draw the user interface
18601860
TheInGameUI->DRAW();
18611861

1862-
// end of video example code
1862+
TheGameClient->DRAW();
18631863

18641864
// draw the mouse
18651865
if( TheMouse )

0 commit comments

Comments
 (0)