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+
2838Intro::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+
7499void 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+
83205void 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+ }
0 commit comments