From 842153c241ad9fbe8a464a5f70fb320633a8811d Mon Sep 17 00:00:00 2001 From: Tim Sarbin Date: Wed, 12 Dec 2018 23:13:16 -0500 Subject: [PATCH] Added credits screen. --- OpenDiablo2.Common/Enums/eButtonType.cs | 1 + OpenDiablo2.Common/Enums/eSceneType.cs | 1 + OpenDiablo2.Common/Models/ButtonLayout.cs | 2 + OpenDiablo2.Common/ResourcePaths.cs | 4 + OpenDiablo2.Core/UI/Button.cs | 2 +- OpenDiablo2.SDL2/SDL2Label.cs | 2 +- OpenDiablo2.Scenes/Credits.cs | 185 +++++++++++++++++++ OpenDiablo2.Scenes/MainMenu.cs | 19 +- OpenDiablo2.Scenes/OpenDiablo2.Scenes.csproj | 1 + OpenDiablo2/OpenDiablo2.csproj | 5 + OpenDiablo2/credits.txt | 16 ++ 11 files changed, 231 insertions(+), 7 deletions(-) create mode 100644 OpenDiablo2.Scenes/Credits.cs create mode 100644 OpenDiablo2/credits.txt diff --git a/OpenDiablo2.Common/Enums/eButtonType.cs b/OpenDiablo2.Common/Enums/eButtonType.cs index 810a9c06..beb8d7fa 100644 --- a/OpenDiablo2.Common/Enums/eButtonType.cs +++ b/OpenDiablo2.Common/Enums/eButtonType.cs @@ -7,6 +7,7 @@ Narrow, Cancel, Tall, + Short, // Game UI Skill, Run, diff --git a/OpenDiablo2.Common/Enums/eSceneType.cs b/OpenDiablo2.Common/Enums/eSceneType.cs index eea856c7..78791b5a 100644 --- a/OpenDiablo2.Common/Enums/eSceneType.cs +++ b/OpenDiablo2.Common/Enums/eSceneType.cs @@ -22,6 +22,7 @@ namespace OpenDiablo2.Common.Enums public enum eSceneType { MainMenu, + Credits, SelectHeroClass, SelectCharacter, Game diff --git a/OpenDiablo2.Common/Models/ButtonLayout.cs b/OpenDiablo2.Common/Models/ButtonLayout.cs index 45a99b9c..f9cfbba0 100644 --- a/OpenDiablo2.Common/Models/ButtonLayout.cs +++ b/OpenDiablo2.Common/Models/ButtonLayout.cs @@ -13,6 +13,7 @@ namespace OpenDiablo2.Common.Models public bool Toggleable { get; internal set; } = false; public int BaseFrame { get; internal set; } = 0; public int DisabledFrame { get; internal set; } = -1; + public string FontPath { get; internal set; } = ResourcePaths.FontExocet10; public bool IsDarkenedWhenDisabled => DisabledFrame == -1; @@ -22,6 +23,7 @@ namespace OpenDiablo2.Common.Models {eButtonType.Medium, new ButtonLayout{ XSegments = 1, ResourceName=ResourcePaths.MediumButtonBlank, PaletteName = Palettes.Units } }, {eButtonType.Narrow, new ButtonLayout {XSegments = 1, ResourceName = ResourcePaths.NarrowButtonBlank,PaletteName = Palettes.Units } }, {eButtonType.Tall, new ButtonLayout {XSegments = 1, ResourceName = ResourcePaths.TallButtonBlank, PaletteName = Palettes.Units } }, + {eButtonType.Short, new ButtonLayout {XSegments = 1, ResourceName = ResourcePaths.ShortButtonBlank, PaletteName = Palettes.Units, FontPath = ResourcePaths.FontExocet10 } }, {eButtonType.Cancel, new ButtonLayout {XSegments = 1, ResourceName = ResourcePaths.CancelButton,PaletteName = Palettes.Units } }, // Minipanel {eButtonType.MinipanelCharacter, new ButtonLayout {XSegments = 1, ResourceName = ResourcePaths.MinipanelButton,PaletteName = Palettes.Units, BaseFrame = 0 } }, diff --git a/OpenDiablo2.Common/ResourcePaths.cs b/OpenDiablo2.Common/ResourcePaths.cs index cba6fdd5..c22b5895 100644 --- a/OpenDiablo2.Common/ResourcePaths.cs +++ b/OpenDiablo2.Common/ResourcePaths.cs @@ -30,6 +30,9 @@ namespace OpenDiablo2.Common public const string Diablo2LogoBlackLeft = @"data\global\ui\FrontEnd\D2logoBlackLeft.DC6"; public const string Diablo2LogoBlackRight = @"data\global\ui\FrontEnd\D2logoBlackRight.DC6"; + // --- Credits --- + public const string CreditsBackground = @"data\global\ui\CharSelect\creditsbckgexpand.dc6"; + public const string CreditsText = @"data\local\ui\eng\ExpansionCredits.txt"; // --- Character Select Screen --- public const string CharacterSelectBackground = @"data\global\ui\FrontEnd\charactercreationscreenEXP.dc6"; public const string CharacterSelectCampfire = @"data\global\ui\FrontEnd\fire.DC6"; @@ -117,6 +120,7 @@ namespace OpenDiablo2.Common public const string MediumButtonBlank = @"data\global\ui\FrontEnd\MediumButtonBlank.dc6"; public const string CancelButton = @"data\global\ui\FrontEnd\CancelButtonBlank.dc6"; public const string NarrowButtonBlank = @"data\global\ui\FrontEnd\NarrowButtonBlank.dc6"; + public const string ShortButtonBlank = @"data\global\ui\CharSelect\ShortButtonBlank.dc6"; public const string TextBox2 = @"data\global\ui\FrontEnd\textbox2.dc6"; public const string TallButtonBlank = @"data\global\ui\CharSelect\TallButtonBlank.dc6"; diff --git a/OpenDiablo2.Core/UI/Button.cs b/OpenDiablo2.Core/UI/Button.cs index b24d7df1..323c708d 100644 --- a/OpenDiablo2.Core/UI/Button.cs +++ b/OpenDiablo2.Core/UI/Button.cs @@ -83,7 +83,7 @@ namespace OpenDiablo2.Core.UI this.mouseInfoProvider = mouseInfoProvider; this.musicProvider = soundProvider; - font = renderWindow.LoadFont(ResourcePaths.FontExocet10, Palettes.Units); + font = renderWindow.LoadFont(buttonLayout.FontPath, Palettes.Units); label = renderWindow.CreateLabel(font); sprite = renderWindow.LoadSprite(buttonLayout.ResourceName, buttonLayout.PaletteName, true); diff --git a/OpenDiablo2.SDL2/SDL2Label.cs b/OpenDiablo2.SDL2/SDL2Label.cs index af5f8fd3..4390951d 100644 --- a/OpenDiablo2.SDL2/SDL2Label.cs +++ b/OpenDiablo2.SDL2/SDL2Label.cs @@ -45,7 +45,7 @@ namespace OpenDiablo2.SDL2_ } } - private string text; + private string text = string.Empty; public string Text { get => text; diff --git a/OpenDiablo2.Scenes/Credits.cs b/OpenDiablo2.Scenes/Credits.cs new file mode 100644 index 00000000..40156efd --- /dev/null +++ b/OpenDiablo2.Scenes/Credits.cs @@ -0,0 +1,185 @@ +using OpenDiablo2.Common; +using OpenDiablo2.Common.Attributes; +using OpenDiablo2.Common.Enums; +using OpenDiablo2.Common.Interfaces; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OpenDiablo2.Scenes +{ + [Scene(eSceneType.Credits)] + public sealed class Credits : IScene + { + private class LabelItem + { + public ILabel Label { get; set; } + public bool IsHeading { get; set; } + public bool Avaiable { get; set; } + } + + private const float secondsPerCycle = (40f / 1000f); + + private readonly IRenderWindow renderWindow; + private readonly ISceneManager sceneManager; + private readonly IMPQProvider mpqProvider; + + private bool doneWithCredits = false; + private int cyclesTillNextLine = 0; + private float cycleTime = 0f; + private IFont textFont; + private ISprite backgroundSprite; + private IButton btnExit; + private Stack creditsText; + private List fontLabels = new List(); + + public Credits( + IRenderWindow renderWindow, + ISceneManager sceneManager, + IMPQProvider mpqProvider, + Func createButton + ) + { + this.renderWindow = renderWindow; + this.sceneManager = sceneManager; + this.mpqProvider = mpqProvider; + + backgroundSprite = renderWindow.LoadSprite(ResourcePaths.CreditsBackground, Palettes.Sky); + + btnExit = createButton(eButtonType.Medium); + btnExit.Text = "Exit".ToUpper(); + btnExit.Location = new Point(20, 550); + btnExit.OnActivate = OnActivateClicked; + + textFont = renderWindow.LoadFont(ResourcePaths.FontFormal10, Palettes.Static); + + creditsText = new Stack(( + File.ReadAllLines(Path.Combine(Path.GetDirectoryName(Environment.GetCommandLineArgs().First()), "credits.txt")) + .Concat(mpqProvider.GetTextFile(ResourcePaths.CreditsText)) + ).Reverse()); + } + + private void OnActivateClicked() + => sceneManager.ChangeScene(eSceneType.MainMenu); + + private void AddNextItem() + { + if (!creditsText.Any()) + { + doneWithCredits = true; + return; + } + + var text = creditsText.Pop().Trim(); + if (text.Trim().Length == 0) + { + cyclesTillNextLine = 18; + return; + } + var isHeading = text.StartsWith("*"); + var isNextHeading = creditsText.Any() && creditsText.Peek().StartsWith("*"); + var isNextSpace = creditsText.Any() && creditsText.Peek().Trim().Length == 0; + var label = GetNewFontLabel(isHeading); + label.Text = isHeading ? text.Substring(1) : text; + var isDoubled = false; + if (!isHeading && !isNextHeading && !isNextSpace) + { + isDoubled = true; + + // Gotta go side by side + label.Location = new Point(390 - label.TextArea.Width, 605); + + var text2 = creditsText.Pop().Trim(); + isNextHeading = creditsText.Any() && creditsText.Peek().StartsWith("*"); + var label2 = GetNewFontLabel(isHeading); + label2.Text = text2; + + label2.Location = new Point(410, 605); + } + else + { + label.Location = new Point(400 - (label.TextArea.Width / 2), 605); + } + + if (isHeading && isNextHeading) + cyclesTillNextLine = 40; + else if (isNextHeading) + cyclesTillNextLine = isDoubled ? 40 : 70; + else if (isHeading) + cyclesTillNextLine = 40; + else + cyclesTillNextLine = 18; + } + + public void Render() + { + renderWindow.Draw(backgroundSprite, 4, 3, 0); + btnExit.Render(); + foreach (var label in fontLabels.Where(x => !x.Avaiable).Select(x => x.Label)) + renderWindow.Draw(label); + } + + public void Update(long ms) + { + + cycleTime += (ms / 1000f); + while (cycleTime >= secondsPerCycle) + { + cycleTime -= secondsPerCycle; + if (!doneWithCredits && (--cyclesTillNextLine <= 0)) + AddNextItem(); + + foreach (var fontLabel in fontLabels.Where(x => !x.Avaiable)) + { + if (fontLabel.Label.Location.Y - 1 <= -15) + { + fontLabel.Avaiable = true; + continue; + } + fontLabel.Label.Location = new Point(fontLabel.Label.Location.X, fontLabel.Label.Location.Y - 1); + } + } + + btnExit.Update(); + } + + private ILabel GetNewFontLabel(bool isHeading) + { + var labelItem = fontLabels.FirstOrDefault(x => x.Avaiable && x.IsHeading == isHeading); + if (labelItem != null) + { + labelItem.Avaiable = false; + return labelItem.Label; + } + + var newLabelItem = new LabelItem + { + Avaiable = false, + IsHeading = isHeading, + Label = renderWindow.CreateLabel(textFont) + }; + + newLabelItem.Label.TextColor = isHeading + ? Color.FromArgb(255, 88, 82) + : Color.FromArgb(198, 178, 150); + + fontLabels.Add(newLabelItem); + return newLabelItem.Label; + } + + + public void Dispose() + { + backgroundSprite?.Dispose(); + + foreach (var labelItem in fontLabels) + labelItem.Label.Dispose(); + + textFont.Dispose(); + } + } +} diff --git a/OpenDiablo2.Scenes/MainMenu.cs b/OpenDiablo2.Scenes/MainMenu.cs index 49dc0d09..f7a38a2d 100644 --- a/OpenDiablo2.Scenes/MainMenu.cs +++ b/OpenDiablo2.Scenes/MainMenu.cs @@ -34,7 +34,7 @@ namespace OpenDiablo2.Scenes private readonly ISprite backgroundSprite, diabloLogoLeft, diabloLogoRight, diabloLogoLeftBlack, diabloLogoRightBlack; private readonly IFont labelFont; private readonly ILabel versionLabel, urlLabel; - private readonly IButton btnSinglePlayer, btnExit, btnWebsite; + private readonly IButton btnSinglePlayer, btnExit, btnWebsite, btnCredits; public MainMenu( IRenderWindow renderWindow, @@ -42,8 +42,7 @@ namespace OpenDiablo2.Scenes IResourceManager resourceManager, ISoundProvider soundProvider, IMPQProvider mpqProvider, - Func createButton, - Func getScene // Temporary until SDL load functions are sped up + Func createButton ) { this.renderWindow = renderWindow; @@ -64,7 +63,7 @@ namespace OpenDiablo2.Scenes btnWebsite = createButton(eButtonType.Wide); btnWebsite.Text = "Visit Github".ToUpper(); - btnWebsite.Location = new Point(264, 460); + btnWebsite.Location = new Point(264, 330); btnWebsite.OnActivate = OnVisitWebsiteClicked; btnExit = createButton(eButtonType.Wide); @@ -72,8 +71,13 @@ namespace OpenDiablo2.Scenes btnExit.Location = new Point(264, 500); btnExit.OnActivate = OnExitClicked; + btnCredits = createButton(eButtonType.Short); + btnCredits.Text = "Credits".ToUpper(); /* TODO: We apparently need a 'half font' option... */ + btnCredits.Location = new Point(264, 470); + btnCredits.OnActivate = OnCreditsClicked; + labelFont = renderWindow.LoadFont(ResourcePaths.Font16, Palettes.Static); - versionLabel = renderWindow.CreateLabel(labelFont, new Point(50, 555), "v0.01 Pre-Alpha"); + versionLabel = renderWindow.CreateLabel(labelFont, new Point(50, 555), "v0.02 Pre-Alpha"); urlLabel = renderWindow.CreateLabel(labelFont, new Point(50, 569), "https://github.com/essial/OpenDiablo2/"); urlLabel.TextColor = Color.Magenta; @@ -81,6 +85,9 @@ namespace OpenDiablo2.Scenes soundProvider.PlaySong(); } + private void OnCreditsClicked() + => sceneManager.ChangeScene(eSceneType.Credits); + private void OnVisitWebsiteClicked() => System.Diagnostics.Process.Start("https://github.com/essial/OpenDiablo2/"); @@ -103,6 +110,7 @@ namespace OpenDiablo2.Scenes btnSinglePlayer.Render(); btnWebsite.Render(); btnExit.Render(); + btnCredits.Render(); //wideButton.Location = new Point(264, 290); //renderWindow.Draw(wideButton, 2, 1, 0); @@ -118,6 +126,7 @@ namespace OpenDiablo2.Scenes btnSinglePlayer.Update(); btnWebsite.Update(); btnExit.Update(); + btnCredits.Update(); } diff --git a/OpenDiablo2.Scenes/OpenDiablo2.Scenes.csproj b/OpenDiablo2.Scenes/OpenDiablo2.Scenes.csproj index 8d38eb2d..595d6d46 100644 --- a/OpenDiablo2.Scenes/OpenDiablo2.Scenes.csproj +++ b/OpenDiablo2.Scenes/OpenDiablo2.Scenes.csproj @@ -54,6 +54,7 @@ + diff --git a/OpenDiablo2/OpenDiablo2.csproj b/OpenDiablo2/OpenDiablo2.csproj index a8fdcf74..a454b39f 100644 --- a/OpenDiablo2/OpenDiablo2.csproj +++ b/OpenDiablo2/OpenDiablo2.csproj @@ -135,5 +135,10 @@ false + + + PreserveNewest + + \ No newline at end of file diff --git a/OpenDiablo2/credits.txt b/OpenDiablo2/credits.txt new file mode 100644 index 00000000..6353063c --- /dev/null +++ b/OpenDiablo2/credits.txt @@ -0,0 +1,16 @@ +*OpenDiablo2 +An open source re-implementation of Diablo 2 in C# + +THIS GAME IS NEITHER DEVELOPED BY, NOR ENDORSED + +BY BLIZZARD OR ITS PARENT COMPANY ACTIVISION. + +*Developers: +erexo +essial +grazz +Mirey +nicholasdechiara +wtfblub + +*----- Original Diablo2 Credits ----- \ No newline at end of file