diff --git a/d2app/app.go b/d2app/app.go index 2048501d..b1713bd2 100644 --- a/d2app/app.go +++ b/d2app/app.go @@ -961,3 +961,8 @@ func (a *App) ToMapEngineTest(region, level int) { func (a *App) ToCredits() { a.screen.SetNextScreen(d2gamescreen.CreateCredits(a, a.asset, a.renderer, a.ui)) } + +// ToCinematics forces the game to transition to the cinematics menu +func (a *App) ToCinematics() { + a.screen.SetNextScreen(d2gamescreen.CreateCinematics(a, a.asset, a.renderer, a.audio, a.ui)) +} diff --git a/d2common/d2interface/navigate.go b/d2common/d2interface/navigate.go index d30d4c39..15892076 100644 --- a/d2common/d2interface/navigate.go +++ b/d2common/d2interface/navigate.go @@ -12,4 +12,5 @@ type Navigator interface { ToCharacterSelect(connType d2clientconnectiontype.ClientConnectionType, connHost string) ToMapEngineTest(region int, level int) ToCredits() + ToCinematics() } diff --git a/d2common/d2resource/resource_paths.go b/d2common/d2resource/resource_paths.go index 19011df5..6159c938 100644 --- a/d2common/d2resource/resource_paths.go +++ b/d2common/d2resource/resource_paths.go @@ -6,6 +6,16 @@ const ( LoadingScreen = "/data/global/ui/Loading/loadingscreen.dc6" + // --- Video Paths --- + + Act1Intro = "/data/local/video/eng/d2intro640x292.bik" + Act2Intro = "/data/local/video/eng/act02start640x292.bik" + Act3Intro = "/data/local/video/eng/act03start640x292.bik" + Act4Intro = "/data/local/video/eng/act04start640x292.bik" + Act4Outro = "/data/local/video/eng/act04end640x292.bik" + Act5Intro = "/data/local/video/eng/d2x_intro_640x292.bik" + Act5Outro = "/data/local/video/eng/d2x_out_640x292.bik" + // --- Main Menu --- TrademarkScreen = "/data/global/ui/FrontEnd/trademarkscreenEXP.dc6" @@ -21,6 +31,10 @@ const ( CreditsBackground = "/data/global/ui/CharSelect/creditsbckgexpand.dc6" CreditsText = "/data/local/ui/{LANG}/ExpansionCredits.txt" + // --- Cinematics --- + + CinematicsBackground = "/data/global/ui/FrontEnd/CinematicsSelectionEXP.dc6" + // --- Character Select Screen --- CharacterSelectBackground = "/data/global/ui/FrontEnd/charactercreationscreenEXP.dc6" diff --git a/d2game/d2gamescreen/cinematics.go b/d2game/d2gamescreen/cinematics.go new file mode 100644 index 00000000..3159dafd --- /dev/null +++ b/d2game/d2gamescreen/cinematics.go @@ -0,0 +1,203 @@ +package d2gamescreen + +import ( + "log" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2video" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" + "github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset" + "github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui" + "github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen" + "github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui" +) + +const ( + cinematicsX, cinematicsY = 240, 90 + cinematicsLabelX, cinematicsLabelY = 400, 110 + a1BtnX, a1BtnY = 264, 160 + a2BtnX, a2BtnY = 264, 205 + a3BtnX, a3BtnY = 264, 250 + a4BtnX, a4BtnY = 264, 295 + endCreditClassBtnX, endCreditClassBtnY = 264, 340 + a5BtnX, a5BtnY = 264, 385 + endCreditExpBtnX, endCreditExpBtnY = 264, 430 + cinematicsExitBtnX, cinematicsExitBtnY = 340, 470 +) + +// Cinematics represents the cinematics screen +type Cinematics struct { + cinematicsBackground *d2ui.Sprite + background *d2ui.Sprite + a1Btn *d2ui.Button + a2Btn *d2ui.Button + a3Btn *d2ui.Button + a4Btn *d2ui.Button + a5Btn *d2ui.Button + endCreditClassBtn *d2ui.Button + endCreditExpBtn *d2ui.Button + cinematicsExitBtn *d2ui.Button + cinematicsLabel *d2ui.Label + + asset *d2asset.AssetManager + renderer d2interface.Renderer + navigator d2interface.Navigator + uiManager *d2ui.UIManager + videoDecoder *d2video.BinkDecoder + audioProvider d2interface.AudioProvider +} + +// CreateCinematics creates an instance of the credits screen +func CreateCinematics( + navigator d2interface.Navigator, + asset *d2asset.AssetManager, + renderer d2interface.Renderer, + aup d2interface.AudioProvider, + ui *d2ui.UIManager) *Cinematics { + result := &Cinematics{ + asset: asset, + renderer: renderer, + navigator: navigator, + uiManager: ui, + audioProvider: aup, + } + + return result +} + +// OnLoad is called to load the resources for the credits screen +func (v *Cinematics) OnLoad(_ d2screen.LoadingState) { + var err error + + v.audioProvider.PlayBGM("") + + v.background, err = v.uiManager.NewSprite(d2resource.GameSelectScreen, d2resource.PaletteSky) + + if err != nil { + log.Print(err) + } + + v.background.SetPosition(backgroundX, backgroundY) + + v.cinematicsBackground, err = v.uiManager.NewSprite(d2resource.CinematicsBackground, d2resource.PaletteSky) + + if err != nil { + log.Print(err) + } + + v.cinematicsBackground.SetPosition(cinematicsX, cinematicsY) + + v.createButtons() + + v.cinematicsLabel = v.uiManager.NewLabel(d2resource.Font30, d2resource.PaletteStatic) + v.cinematicsLabel.Alignment = d2gui.HorizontalAlignCenter + v.cinematicsLabel.SetText("SELECT CINEMATIC") + v.cinematicsLabel.Color[0] = rgbaColor(lightBrown) + v.cinematicsLabel.SetPosition(cinematicsLabelX, cinematicsLabelY) +} + +func (v *Cinematics) createButtons() { + /*CINEMATICS NAMES: + Act 1: The Sister's Lament + Act 2: Dessert Journay + Act 3: Mephisto's Jungle + Act 4: Enter Hell + Act 5: Search For Ball + end Credit Classic: Terror's End + end Credit Expansion: Destruction's End + */ + v.cinematicsExitBtn = v.uiManager.NewButton(d2ui.ButtonTypeMedium, "CANCEL") + v.cinematicsExitBtn.SetPosition(cinematicsExitBtnX, cinematicsExitBtnY) + v.cinematicsExitBtn.OnActivated(func() { v.onCinematicsExitBtnClicked() }) + + v.a1Btn = v.uiManager.NewButton(d2ui.ButtonTypeWide, "THE SISTER'S LAMENT") + v.a1Btn.SetPosition(a1BtnX, a1BtnY) + v.a1Btn.OnActivated(func() { v.onA1BtnClicked() }) + + v.a2Btn = v.uiManager.NewButton(d2ui.ButtonTypeWide, "DESSERT JOURNAY") + v.a2Btn.SetPosition(a2BtnX, a2BtnY) + v.a2Btn.OnActivated(func() { v.onA2BtnClicked() }) + + v.a3Btn = v.uiManager.NewButton(d2ui.ButtonTypeWide, "MEPHISTO'S JUNGLE") + v.a3Btn.SetPosition(a3BtnX, a3BtnY) + v.a3Btn.OnActivated(func() { v.onA3BtnClicked() }) + + v.a4Btn = v.uiManager.NewButton(d2ui.ButtonTypeWide, "ENTER HELL") + v.a4Btn.SetPosition(a4BtnX, a4BtnY) + v.a4Btn.OnActivated(func() { v.onA4BtnClicked() }) + + v.endCreditClassBtn = v.uiManager.NewButton(d2ui.ButtonTypeWide, "TERROR'S END") + v.endCreditClassBtn.SetPosition(endCreditClassBtnX, endCreditClassBtnY) + v.endCreditClassBtn.OnActivated(func() { v.onEndCreditClassBtnClicked() }) + + v.a5Btn = v.uiManager.NewButton(d2ui.ButtonTypeWide, "SEARCH FOR BAAL") + v.a5Btn.SetPosition(a5BtnX, a5BtnY) + v.a5Btn.OnActivated(func() { v.onA5BtnClicked() }) + + v.endCreditExpBtn = v.uiManager.NewButton(d2ui.ButtonTypeWide, "DESTRUCTION'S END") + v.endCreditExpBtn.SetPosition(endCreditExpBtnX, endCreditExpBtnY) + v.endCreditExpBtn.OnActivated(func() { v.onEndCreditExpBtnClicked() }) +} + +func (v *Cinematics) onCinematicsExitBtnClicked() { + v.navigator.ToMainMenu() +} + +func (v *Cinematics) onA1BtnClicked() { + v.playVideo(d2resource.Act1Intro) +} + +func (v *Cinematics) onA2BtnClicked() { + v.playVideo(d2resource.Act2Intro) +} + +func (v *Cinematics) onA3BtnClicked() { + v.playVideo(d2resource.Act3Intro) +} + +func (v *Cinematics) onA4BtnClicked() { + v.playVideo(d2resource.Act4Intro) +} + +func (v *Cinematics) onEndCreditClassBtnClicked() { + v.playVideo(d2resource.Act4Outro) +} + +func (v *Cinematics) onA5BtnClicked() { + v.playVideo(d2resource.Act5Intro) +} + +func (v *Cinematics) onEndCreditExpBtnClicked() { + v.playVideo(d2resource.Act5Outro) +} + +func (v *Cinematics) playVideo(path string) { + videoBytes, err := v.asset.LoadFile(path) + if err != nil { + log.Print(err) + return + } + + v.videoDecoder = d2video.CreateBinkDecoder(videoBytes) +} + +// Render renders the credits screen +func (v *Cinematics) Render(screen d2interface.Surface) { + err := v.background.RenderSegmented(screen, 4, 3, 0) + + if err != nil { + return + } + + err = v.cinematicsBackground.RenderSegmented(screen, 2, 2, 0) + + if err != nil { + return + } + + err = v.cinematicsLabel.Render(screen) + + if err != nil { + return + } +} diff --git a/d2game/d2gamescreen/main_menu.go b/d2game/d2gamescreen/main_menu.go index 1e424b2d..43466698 100644 --- a/d2game/d2gamescreen/main_menu.go +++ b/d2game/d2gamescreen/main_menu.go @@ -323,6 +323,7 @@ func (v *MainMenu) createButtons(loading d2screen.LoadingState) { v.cinematicsButton = v.uiManager.NewButton(d2ui.ButtonTypeShort, "CINEMATICS") v.cinematicsButton.SetPosition(cineBtnX, cineBtnY) + v.cinematicsButton.OnActivated(func() { v.onCinematicsButtonClicked() }) loading.Progress(seventyPercent) v.singlePlayerButton = v.uiManager.NewButton(d2ui.ButtonTypeWide, "SINGLE PLAYER") @@ -421,6 +422,10 @@ func (v *MainMenu) onCreditsButtonClicked() { v.navigator.ToCredits() } +func (v *MainMenu) onCinematicsButtonClicked() { + v.navigator.ToCinematics() +} + // Render renders the main menu func (v *MainMenu) Render(screen d2interface.Surface) { v.renderBackgrounds(screen) @@ -435,6 +440,10 @@ func (v *MainMenu) renderBackgrounds(screen d2interface.Surface) { return } case ScreenModeServerIP: + if err := v.tcpIPBackground.RenderSegmented(screen, 4, 3, 0); err != nil { + return + } + if err := v.serverIPBackground.RenderSegmented(screen, 2, 1, 0); err != nil { return }