3 using Microsoft.Xna.Framework;
4 using Microsoft.Xna.Framework.Graphics;
5 using Microsoft.Xna.Framework.Input;
7 using System.Collections.Concurrent;
8 using System.Collections.Generic;
15 private readonly
Sprite defaultBackgroundTexture, overlay;
16 private readonly
SpriteSheet decorativeGraph, decorativeMap;
17 private Sprite currentBackgroundTexture;
18 private readonly
Sprite noiseSprite;
20 private string randText =
"";
22 private Sprite languageSelectionCursor;
23 private ScalableFont languageSelectionFont, languageSelectionFontCJK;
25 private Video currSplashScreen;
26 private DateTime videoStartTime;
28 private bool mirrorBackground;
44 public readonly ConcurrentQueue<PendingSplashScreen>
PendingSplashScreens =
new ConcurrentQueue<PendingSplashScreen>();
72 defaultBackgroundTexture =
new Sprite(
"Content/Map/LocationPortraits/MainMenu1.png", Vector2.Zero);
74 decorativeMap =
new SpriteSheet(
"Content/Map/MapHUD.png", 6, 5, Vector2.Zero, sourceRect:
new Rectangle(0, 0, 2048, 640));
75 decorativeGraph =
new SpriteSheet(
"Content/Map/MapHUD.png", 4, 10, Vector2.Zero, sourceRect:
new Rectangle(1025, 1259, 1024, 732));
77 overlay =
new Sprite(
"Content/UI/MainMenuVignette.png", Vector2.Zero);
78 noiseSprite =
new Sprite(
"Content/UI/noise.png", Vector2.Zero);
80 SetSelectedTip(TextManager.Get(
"LoadingScreenTip"));
83 public void Draw(SpriteBatch spriteBatch, GraphicsDevice graphics,
float deltaTime)
85 if (GameSettings.CurrentConfig.EnableSplashScreen)
89 DrawSplashScreen(spriteBatch, graphics);
94 DebugConsole.ThrowError(
"Playing splash screen video failed", e);
95 DisableSplashScreen();
101 currentBackgroundTexture ??= defaultBackgroundTexture;
106 (
int)(overlay.size.X * overlayScale / 2), 0,
109 spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, samplerState: GUI.SamplerState);
111 GUI.DrawBackgroundSprite(spriteBatch, currentBackgroundTexture, Color.White, drawArea,
112 spriteEffects: mirrorBackground ? SpriteEffects.FlipHorizontally : SpriteEffects.None);
113 overlay.Draw(spriteBatch, Vector2.Zero, scale: overlayScale);
115 double noiseT = Timing.TotalTime * 0.02f;
116 float noiseStrength = (float)PerlinNoise.CalculatePerlin(noiseT, noiseT, 0);
117 float noiseScale = (float)PerlinNoise.CalculatePerlin(noiseT * 5.0f, noiseT * 2.0f, 0) * 4.0f;
119 startOffset:
new Vector2(Rand.Range(0.0f, noiseSprite.SourceRect.Width), Rand.Range(0.0f, noiseSprite.SourceRect.Height)),
120 color: Color.White * noiseStrength * 0.1f,
121 textureScale: Vector2.One * noiseScale);
126 DrawLanguageSelectionPrompt(spriteBatch, graphics);
132 if (loadState >= 100.0f)
135 if (GameSettings.CurrentConfig.AutomaticQuickStartEnabled || GameSettings.CurrentConfig.AutomaticCampaignLoadEnabled || (GameSettings.CurrentConfig.TestScreenEnabled &&
GameMain.FirstLoad))
137 loadText =
"QUICKSTARTING ...";
142 loadText = TextManager.Get(
"PressAnyKey");
149 loadText = TextManager.Get(
"Loading");
152 loadText += $
" {loadState:N0} %";
158 loadText +=
" (Quickstart aborted)";
163 if (GUIStyle.LargeFont.HasValue)
165 GUIStyle.LargeFont.DrawString(spriteBatch, loadText.
ToUpper(),
168 textPos.Y += GUIStyle.LargeFont.MeasureString(loadText.
ToUpper()).Y * 1.2f;
171 if (GUIStyle.Font.HasValue && selectedTip !=
null)
174 string[] lines = wrappedTip.
Split(
'\n');
175 float lineHeight = GUIStyle.Font.MeasureString(selectedTip).Y;
180 for (
int i = 0; i < lines.Length; i++)
182 GUIStyle.Font.DrawStringWithColors(spriteBatch, lines[i],
183 new Vector2(textPos.X, (
int)(textPos.Y + i * lineHeight)),
185 0f, Vector2.Zero, 1f, SpriteEffects.None, 0f, selectedTip.
RichTextData.Value, rtdOffset);
186 rtdOffset += lines[i].Length;
191 for (
int i = 0; i < lines.Length; i++)
193 GUIStyle.Font.DrawString(spriteBatch, lines[i],
194 new Vector2(textPos.X, (
int)(textPos.Y + i * lineHeight)),
195 new Color(228, 217, 167, 255));
200 GUI.DrawMessageBoxesOnly(spriteBatch);
203 spriteBatch.Begin(blendState: BlendState.Additive);
207 float noiseVal = (float)PerlinNoise.CalculatePerlin(Timing.TotalTime * 0.25f, Timing.TotalTime * 0.5f, 0);
210 decorativeGraph.Draw(spriteBatch, (
int)(decorativeGraph.FrameCount * noiseVal),
212 Color.White,
new Vector2(0, decorativeMap.FrameSize.Y), 0.0f, decorativeScale, SpriteEffects.FlipVertically);
215 decorativeMap.Draw(spriteBatch, (
int)(decorativeMap.FrameCount * noiseVal),
217 Color.White,
new Vector2(decorativeMap.FrameSize.X, 0), 0.0f, decorativeScale, SpriteEffects.FlipHorizontally | SpriteEffects.FlipVertically);
222 randText = (
new string[] {
"NIL",
"black white gray",
"Sometimes we would have had time to scream",
"e8m106]af",
"NO" }).GetRandomUnsynced();
224 else if (noiseVal < 0.3f)
226 randText = ToolBox.RandomSeed(9);
228 else if (noiseVal < 0.5f)
231 Rand.Int(100).ToString().PadLeft(2,
'0') +
" " +
232 Rand.Int(100).ToString().PadLeft(2,
'0') +
" " +
233 Rand.Int(100).ToString().PadLeft(2,
'0') +
" " +
234 Rand.Int(100).ToString().PadLeft(2,
'0');
237 if (GUIStyle.LargeFont.HasValue)
239 Vector2 textSize = GUIStyle.LargeFont.MeasureString(randText);
240 GUIStyle.LargeFont.DrawString(spriteBatch, randText,
242 Color.White * (1.0f - noiseVal));
248 private void DrawLanguageSelectionPrompt(SpriteBatch spriteBatch, GraphicsDevice graphicsDevice)
252 if (languageSelectionFont ==
null)
254 languageSelectionFont =
new ScalableFont(
"Content/Fonts/NotoSans/NotoSans-Bold.ttf",
255 (uint)(30 * (GameMain.GraphicsHeight / 1080.0f)), graphicsDevice);
257 if (languageSelectionFontCJK ==
null)
259 languageSelectionFontCJK =
new ScalableFont(
"Content/Fonts/NotoSans/NotoSansCJKsc-Bold.otf",
260 (uint)(30 * (GameMain.GraphicsHeight / 1080.0f)), graphicsDevice, dynamicLoading:
true);
262 if (languageSelectionCursor ==
null)
264 languageSelectionCursor =
new Sprite(
"Content/UI/cursor.png", Vector2.Zero);
267 Vector2 textPos =
new Vector2((
int)(GameMain.GraphicsWidth * 0.05f), (
int)(GameMain.GraphicsHeight * 0.3f));
268 Vector2 textSpacing =
new Vector2(0.0f, GameMain.GraphicsHeight * 0.5f /
AvailableLanguages.Length);
271 string localizedLanguageName = TextManager.GetTranslatedLanguageName(language);
272 var font = TextManager.IsCJK(localizedLanguageName) ? languageSelectionFontCJK : languageSelectionFont;
274 Vector2 textSize = font.
MeasureString(localizedLanguageName);
276 PlayerInput.MousePosition.X > textPos.X && PlayerInput.MousePosition.X < textPos.X + textSize.X &&
277 PlayerInput.MousePosition.Y > textPos.Y && PlayerInput.MousePosition.Y < textPos.Y + textSize.Y;
279 font.DrawString(spriteBatch, localizedLanguageName, textPos,
280 hover ? Color.White : Color.White * 0.6f);
281 if (hover && PlayerInput.PrimaryMouseButtonClicked())
283 var config = GameSettings.CurrentConfig;
284 config.Language = language;
285 GameSettings.SetCurrentConfig(config);
287 SetSelectedTip(TextManager.Get(
"LoadingScreenTip"));
289 languageSelectionFont?.
Dispose(); languageSelectionFont =
null;
290 languageSelectionFontCJK?.
Dispose(); languageSelectionFontCJK =
null;
294 textPos += textSpacing;
297 languageSelectionCursor.
Draw(spriteBatch, PlayerInput.LatestMousePosition, scale: 0.5f);
300 private void DrawSplashScreen(SpriteBatch spriteBatch, GraphicsDevice graphics)
302 if (currSplashScreen ==
null)
305 string fileName = newSplashScreen.Filename;
308 currSplashScreen =
Video.
Load(graphics, GameMain.SoundManager, fileName);
309 currSplashScreen.
AudioGain = newSplashScreen.Gain;
310 videoStartTime = DateTime.Now;
314 DisableSplashScreen();
315 DebugConsole.ThrowError(
"Playing the splash screen \"" + fileName +
"\" failed.", e);
317 currSplashScreen =
null;
321 if (currSplashScreen ==
null) {
return; }
325 graphics.Clear(Color.Black);
326 float videoAspectRatio = (float)currSplashScreen.
Width / (
float)currSplashScreen.
Height;
327 int width;
int height;
328 if (GameMain.GraphicsHeight * videoAspectRatio > GameMain.GraphicsWidth)
330 width = GameMain.GraphicsWidth;
331 height = (int)(GameMain.GraphicsWidth / videoAspectRatio);
335 width = (int)(GameMain.GraphicsHeight * videoAspectRatio);
336 height = GameMain.GraphicsHeight;
343 GameMain.GraphicsWidth / 2 - width / 2,
344 GameMain.GraphicsHeight / 2 - height / 2,
350 origin: Vector2.Zero,
355 if (DateTime.Now > videoStartTime +
new TimeSpan(0, 0, 0, 0, milliseconds: 500)
356 && GameMain.WindowActive
357 && (PlayerInput.KeyHit(Keys.Escape)
358 || PlayerInput.KeyHit(Keys.Space)
359 || PlayerInput.KeyHit(Keys.Enter)
360 || PlayerInput.PrimaryMouseButtonDown()))
362 currSplashScreen.
Dispose(); currSplashScreen =
null;
365 else if (DateTime.Now > videoStartTime +
new TimeSpan(0, 0, 0, 0, milliseconds: 1500))
367 currSplashScreen.
Dispose(); currSplashScreen =
null;
371 private void DisableSplashScreen()
373 var config = GameSettings.CurrentConfig;
374 config.EnableSplashScreen =
false;
375 GameSettings.SetCurrentConfig(config);
379 public IEnumerable<CoroutineStatus>
DoLoading(IEnumerable<CoroutineStatus> loader)
383 SetSelectedTip(TextManager.Get(
"LoadingScreenTip"));
384 currentBackgroundTexture =
LocationType.
Prefabs.Where(p => p.UsePortraitInRandomLoadingScreens).GetRandomUnsynced()?.GetPortrait(Rand.Int(
int.MaxValue));
387 currentBackgroundTexture = missions.Where(m => m.Prefab.HasPortraits).First().Prefab.GetPortrait(Rand.Int(
int.MaxValue));
389 mirrorBackground = Rand.Range(0.0f, 1.0f) < 0.5f;
396 CoroutineManager.StartCoroutine(loader);
400 while (CoroutineManager.IsCoroutineRunning(loader.ToString()))
static CoroutineStatus Running
static CoroutineStatus Success
static GameSession?? GameSession
static int GraphicsHeight
virtual IEnumerable< Mission > Missions
LoadingScreen(GraphicsDevice graphics)
bool WaitForLanguageSelection
void Draw(SpriteBatch spriteBatch, GraphicsDevice graphics, float deltaTime)
readonly ConcurrentQueue< PendingSplashScreen > PendingSplashScreens
Triplet.first = filepath, Triplet.second = resolution, Triplet.third = audio gain
LanguageIdentifier[] AvailableLanguages
IEnumerable< CoroutineStatus > DoLoading(IEnumerable< CoroutineStatus > loader)
IReadOnlyList< LocalizedString > Split(params char[] separators)
virtual LocalizedString ToUpper()
static readonly PrefabCollection< LocationType > Prefabs
ImmutableArray< RichTextData >? RichTextData
static RichString Rich(LocalizedString str, Func< string, string >? postProcess=null)
Vector2 MeasureString(LocalizedString str, bool removeExtraSpacing=false)
void Draw(ISpriteBatch spriteBatch, Vector2 pos, float rotate=0.0f, float scale=1.0f, SpriteEffects spriteEffect=SpriteEffects.None)
PendingSplashScreen(string filename, float gain)