From 9c5f3f3673712c8a52877ea37ef8e4fa375a6b4f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 15 Apr 2021 23:04:14 +0200 Subject: [PATCH 01/34] - Exhumed: Skip the map when changing levels from the console. The current screen job implementation does not coexist well with UI elements. More like a hotfix, the screen job framework needs to be redone for properly handling input. --- source/games/exhumed/src/gameloop.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/games/exhumed/src/gameloop.cpp b/source/games/exhumed/src/gameloop.cpp index 154c7b69b..cb05c6774 100644 --- a/source/games/exhumed/src/gameloop.cpp +++ b/source/games/exhumed/src/gameloop.cpp @@ -225,7 +225,8 @@ void GameInterface::LevelCompleted(MapRecord *map, int skill) { Mus_Stop(); if (currentLevel->levelNumber == 0) gameaction = ga_mainmenu; - else Intermission(currentLevel, map); + else if (ConsoleState == c_up) Intermission(currentLevel, map); + else gameaction = ga_nextlevel; } //--------------------------------------------------------------------------- From 6cb84dc554dc909fa06308edf9e1bf0ed057eb10 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 15 Apr 2021 23:55:29 +0200 Subject: [PATCH 02/34] - split out the movie player into its own file. --- source/CMakeLists.txt | 1 + source/core/movie/movieplayer.cpp | 717 ++++++++++++++++++++++++++++++ source/core/screenjob.cpp | 664 --------------------------- 3 files changed, 718 insertions(+), 664 deletions(-) create mode 100644 source/core/movie/movieplayer.cpp diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 11f382b2f..4bbd3c85a 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -1034,6 +1034,7 @@ set (PCH_SOURCES build/src/voxmodel.cpp core/movie/playmve.cpp + core/movie/movieplayer.cpp core/automap.cpp core/cheats.cpp core/cheathandler.cpp diff --git a/source/core/movie/movieplayer.cpp b/source/core/movie/movieplayer.cpp new file mode 100644 index 000000000..96137a03f --- /dev/null +++ b/source/core/movie/movieplayer.cpp @@ -0,0 +1,717 @@ +/* +** movieplayer.cpp +** +**--------------------------------------------------------------------------- +** Copyright 2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include "types.h" +#include "build.h" +#include "screenjob.h" +#include "i_time.h" +#include "v_2ddrawer.h" +#include "animlib.h" +#include "v_draw.h" +#include "s_soundinternal.h" +#include "animtexture.h" +#include "gamestate.h" +#include "razemenu.h" +#include "raze_sound.h" +#include "SmackerDecoder.h" +#include "movie/playmve.h" +#include "gamecontrol.h" +#include +#include +#include "raze_music.h" + + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +class DAnmPlayer : public DScreenJob +{ + // This doesn't need its own class type + anim_t anim; + TArray buffer; + int numframes = 0; + int curframe = 1; + int frametime = 0; + int nextframetime = 0; + AnimTextures animtex; + const AnimSound* animSnd; + const int* frameTicks; + bool nostopsound; + +public: + bool isvalid() { return numframes > 0; } + + DAnmPlayer(FileReader& fr, const AnimSound* ans, const int *frameticks, bool nosoundcutoff) + : animSnd(ans), frameTicks(frameticks), nostopsound(nosoundcutoff) + { + buffer = fr.ReadPadded(1); + fr.Close(); + + if (ANIM_LoadAnim(&anim, buffer.Data(), buffer.Size() - 1) < 0) + { + return; + } + numframes = ANIM_NumFrames(&anim); + animtex.SetSize(AnimTexture::Paletted, 320, 200); + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + int Frame(uint64_t clock, bool skiprequest) override + { + int currentclock = int(clock * 120 / 1'000'000'000); + + if (currentclock < nextframetime - 1) + { + twod->ClearScreen(); + DrawTexture(twod, animtex.GetFrame(), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_Masked, false, TAG_DONE); + if (skiprequest && !nostopsound) soundEngine->StopAllChannels(); + return skiprequest? -1 : 1; + } + + animtex.SetFrame(ANIM_GetPalette(&anim), ANIM_DrawFrame(&anim, curframe)); + frametime = currentclock; + + twod->ClearScreen(); + DrawTexture(twod, animtex.GetFrame(), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_Masked, false, TAG_DONE); + + int delay = 20; + if (frameTicks) + { + if (curframe == 1) delay = frameTicks[0]; + else if (curframe < numframes - 2) delay = frameTicks[1]; + else delay = frameTicks[2]; + } + nextframetime += delay; + + if (animSnd) for (int i = 0; animSnd[i].framenum >= 0; i++) + { + if (animSnd[i].framenum == curframe) + { + int sound = animSnd[i].soundnum; + if (sound == -1) + soundEngine->StopAllChannels(); + else if (SoundEnabled()) + soundEngine->StartSound(SOURCE_None, nullptr, nullptr, CHAN_AUTO, CHANF_UI, sound, 1.f, ATTN_NONE); + } + } + if (!skiprequest && !nostopsound && curframe == numframes && soundEngine->GetSoundPlayingInfo(SOURCE_None, nullptr, -1)) return 1; + curframe++; + if (skiprequest && !nostopsound) soundEngine->StopAllChannels(); + return skiprequest ? -1 : curframe < numframes? 1 : 0; + } + + void OnDestroy() override + { + buffer.Reset(); + animtex.Clean(); + } +}; + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +class DMvePlayer : public DScreenJob +{ + InterplayDecoder decoder; + bool failed = false; + +public: + bool isvalid() { return !failed; } + + DMvePlayer(FileReader& fr) : decoder(SoundEnabled()) + { + failed = !decoder.Open(fr); + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + int Frame(uint64_t clock, bool skiprequest) override + { + if (failed) return -1; + bool playon = decoder.RunFrame(clock); + twod->ClearScreen(); + DrawTexture(twod, decoder.animTex().GetFrame(), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, TAG_DONE); + + return skiprequest ? -1 : playon ? 1 : 0; + } + + void OnDestroy() override + { + decoder.Close(); + } +}; + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +class DVpxPlayer : public DScreenJob +{ + bool failed = false; + FileReader fr; + AnimTextures animtex; + const AnimSound* animSnd; + + unsigned width, height; + TArray Pic; + TArray readBuf; + vpx_codec_ctx_t codec{}; + vpx_codec_iter_t iter = nullptr; + + uint32_t convnumer; + uint32_t convdenom; + + uint64_t nsecsperframe; + uint64_t nextframetime; + + int decstate = 0; + int framenum = 0; + int numframes; + int lastsoundframe = -1; +public: + int soundtrack = -1; + + +public: + bool isvalid() { return !failed; } + + DVpxPlayer(FileReader& fr_, const AnimSound* animSnd_, int origframedelay) + { + fr = std::move(fr_); + animSnd = animSnd_; + + if (!ReadIVFHeader(origframedelay)) + { + // We should never get here, because any file failing this has been eliminated before this constructor got called. + Printf(PRINT_BOLD, "Failed reading IVF header\n"); + failed = true; + } + + Pic.Resize(width * height * 4); + + + // Todo: Support VP9 as well? + vpx_codec_dec_cfg_t cfg = { 1, width, height }; + if (vpx_codec_dec_init(&codec, &vpx_codec_vp8_dx_algo, &cfg, 0)) + { + Printf(PRINT_BOLD, "Error initializing VPX codec.\n"); + failed = true; + } + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + bool ReadIVFHeader(int origframedelay) + { + // IVF format: http://wiki.multimedia.cx/index.php?title=IVF + uint32_t magic; fr.Read(&magic, 4); // do not byte swap! + if (magic != MAKE_ID('D', 'K', 'I', 'F')) return false; + uint16_t version = fr.ReadUInt16(); + if (version != 0) return false; + uint16_t length = fr.ReadUInt16(); + if (length != 32) return false; + fr.Read(&magic, 4); + if (magic != MAKE_ID('V', 'P', '8', '0')) return false; + + width = fr.ReadUInt16(); + height = fr.ReadUInt16(); + uint32_t fpsdenominator = fr.ReadUInt32(); + uint32_t fpsnumerator = fr.ReadUInt32(); + numframes = fr.ReadUInt32(); + if (numframes == 0) return false; + fr.Seek(4, FileReader::SeekCur); + + if (fpsdenominator > 1000 || fpsnumerator == 0 || fpsdenominator == 0) + { + // default to 30 fps if the header does not provide useful info. + fpsdenominator = 30; + fpsnumerator = 1; + } + + convnumer = 120 * fpsnumerator; + convdenom = fpsdenominator * origframedelay; + + nsecsperframe = int64_t(fpsnumerator) * 1'000'000'000 / fpsdenominator; + nextframetime = 0; + + return true; + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + bool ReadFrame() + { + int corrupted = 0; + int framesize = fr.ReadInt32(); + fr.Seek(8, FileReader::SeekCur); + if (framesize == 0) return false; + + readBuf.Resize(framesize); + if (fr.Read(readBuf.Data(), framesize) != framesize) return false; + if (vpx_codec_decode(&codec, readBuf.Data(), readBuf.Size(), NULL, 0) != VPX_CODEC_OK) return false; + if (vpx_codec_control(&codec, VP8D_GET_FRAME_CORRUPTED, &corrupted) != VPX_CODEC_OK) return false; + return true; + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + vpx_image_t *GetFrameData() + { + vpx_image_t *img; + do + { + if (decstate == 0) // first time / begin + { + if (!ReadFrame()) return nullptr; + decstate = 1; + } + + img = vpx_codec_get_frame(&codec, &iter); + if (img == nullptr) + { + decstate = 0; + iter = nullptr; + } + } while (img == nullptr); + + return img->d_w == width && img->d_h == height? img : nullptr; + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + void SetPixel(uint8_t* dest, uint8_t y, uint8_t u, uint8_t v) + { + dest[0] = y; + dest[1] = u; + dest[2] = v; + } + + bool CreateNextFrame() + { + auto img = GetFrameData(); + if (!img) return false; + uint8_t const* const yplane = img->planes[VPX_PLANE_Y]; + uint8_t const* const uplane = img->planes[VPX_PLANE_U]; + uint8_t const* const vplane = img->planes[VPX_PLANE_V]; + + const int ystride = img->stride[VPX_PLANE_Y]; + const int ustride = img->stride[VPX_PLANE_U]; + const int vstride = img->stride[VPX_PLANE_V]; + + for (unsigned int y = 0; y < height; y += 2) + { + unsigned int y1 = y + 1; + unsigned int wy = width * y; + unsigned int wy1 = width * y1; + + for (unsigned int x = 0; x < width; x += 2) + { + uint8_t u = uplane[ustride * (y >> 1) + (x >> 1)]; + uint8_t v = vplane[vstride * (y >> 1) + (x >> 1)]; + + SetPixel(&Pic[(wy + x) << 2], yplane[ystride * y + x], u, v); + SetPixel(&Pic[(wy + x + 1) << 2], yplane[ystride * y + x + 1], u, v); + SetPixel(&Pic[(wy1 + x) << 2], yplane[ystride * y1 + x], u, v); + SetPixel(&Pic[(wy1 + x + 1) << 2], yplane[ystride * y1 + x + 1], u, v); + } + } + return true; + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + int Frame(uint64_t clock, bool skiprequest) override + { + if (clock == 0) + { + if (soundtrack > 0) + { + Mus_Play(nullptr, fileSystem.GetFileFullName(soundtrack, false), false); + } + animtex.SetSize(AnimTexture::YUV, width, height); + } + bool stop = false; + if (clock > nextframetime) + { + nextframetime += nsecsperframe; + + if (!CreateNextFrame()) + { + Printf(PRINT_BOLD, "Failed reading next frame\n"); + stop = true; + } + else + { + animtex.SetFrame(nullptr, Pic.Data()); + } + framenum++; + if (framenum >= numframes) stop = true; + + int soundframe = convdenom ? Scale(framenum, convnumer, convdenom) : framenum; + if (soundframe > lastsoundframe) + { + if (animSnd && soundtrack == -1) for (int i = 0; animSnd[i].framenum >= 0; i++) + { + if (animSnd[i].framenum == soundframe) + { + int sound = animSnd[i].soundnum; + if (sound == -1) + soundEngine->StopAllChannels(); + else if (SoundEnabled()) + soundEngine->StartSound(SOURCE_None, nullptr, nullptr, CHAN_AUTO, CHANF_UI, sound, 1.f, ATTN_NONE); + } + } + lastsoundframe = soundframe; + } + } + DrawTexture(twod, animtex.GetFrame(), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit, TAG_DONE); + if (stop || skiprequest) Mus_Stop(); + if (stop) return 0; + return skiprequest ? -1 : 1; + } + + void OnDestroy() override + { + vpx_codec_destroy(&codec); + } +}; + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +struct AudioData +{ + int hFx; + SmackerAudioInfo inf; + + int16_t samples[6000 * 20]; // must be a multiple of the stream buffer size and larger than the initial chunk of audio + + int nWrite; + int nRead; +}; + +class DSmkPlayer : public DScreenJob +{ + SmackerHandle hSMK{}; + int numAudioTracks; + AudioData adata; + uint32_t nWidth, nHeight; + uint8_t palette[768]; + AnimTextures animtex; + TArray pFrame; + TArray audioBuffer; + int nFrameRate; + int nFrames; + bool fullscreenScale; + uint64_t nFrameNs; + int nFrame = 0; + const AnimSound* animSnd; + FString filename; + SoundStream* stream = nullptr; + +public: + bool isvalid() { return hSMK.isValid; } + + static bool StreamCallbackFunc(SoundStream* stream, void* buff, int len, void* userdata) + { + DSmkPlayer* pId = (DSmkPlayer*)userdata; + memcpy(buff, &pId->adata.samples[pId->adata.nRead], len); + pId->adata.nRead += len / 2; + if (pId->adata.nRead >= countof(pId->adata.samples)) pId->adata.nRead = 0; + return true; + } + + void copy8bitSamples(unsigned count) + { + for (unsigned i = 0; i < count; i++) + { + adata.samples[adata.nWrite] = (audioBuffer[i] - 128) << 8; + if (++adata.nWrite >= countof(adata.samples)) adata.nWrite = 0; + } + } + + void copy16bitSamples(unsigned count) + { + auto ptr = (uint16_t*)audioBuffer.Data(); + for (unsigned i = 0; i < count/2; i++) + { + adata.samples[adata.nWrite] = *ptr++; + if (++adata.nWrite >= countof(adata.samples)) adata.nWrite = 0; + } + } + + + DSmkPlayer(const char *fn, const AnimSound* ans, bool fixedviewport) + { + hSMK = Smacker_Open(fn); + if (!hSMK.isValid) + { + return; + } + Smacker_GetFrameSize(hSMK, nWidth, nHeight); + pFrame.Resize(nWidth * nHeight + std::max(nWidth, nHeight)); + nFrameRate = Smacker_GetFrameRate(hSMK); + nFrameNs = 1'000'000'000 / nFrameRate; + nFrames = Smacker_GetNumFrames(hSMK); + Smacker_GetPalette(hSMK, palette); + fullscreenScale = (!fixedviewport || (nWidth <= 320 && nHeight <= 200) || nWidth >= 640 || nHeight >= 480); + + bool hassound = false; + numAudioTracks = Smacker_GetNumAudioTracks(hSMK); + if (numAudioTracks) + { + adata.nWrite = 0; + adata.nRead = 0; + adata.inf = Smacker_GetAudioTrackDetails(hSMK, 0); + if (adata.inf.idealBufferSize > 0) + { + audioBuffer.Resize(adata.inf.idealBufferSize); + auto read = Smacker_GetAudioData(hSMK, 0, (int16_t*)audioBuffer.Data()); + if (adata.inf.bitsPerSample == 8) copy8bitSamples(read); + else copy16bitSamples(read); + animSnd = nullptr; + hassound = true; + } + } + if (!hassound) + { + adata.inf = {}; + animSnd = ans; + } + + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + int Frame(uint64_t clock, bool skiprequest) override + { + int frame = clock / nFrameNs; + + if (clock == 0) + { + animtex.SetSize(AnimTexture::Paletted, nWidth, nHeight); + } + twod->ClearScreen(); + if (frame > nFrame) + { + Smacker_GetPalette(hSMK, palette); + Smacker_GetFrame(hSMK, pFrame.Data()); + animtex.SetFrame(palette, pFrame.Data()); + if (numAudioTracks) + { + auto read = Smacker_GetAudioData(hSMK, 0, (int16_t*)audioBuffer.Data()); + if (adata.inf.bitsPerSample == 8) copy8bitSamples(read); + else copy16bitSamples(read); + if (!stream && read) // the sound may not start in the first frame, but the stream cannot start without any sound data present. + stream = S_CreateCustomStream(6000, adata.inf.sampleRate, adata.inf.nChannels, StreamCallbackFunc, this); + + } + + } + if (fullscreenScale) + { + DrawTexture(twod, animtex.GetFrame(), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, TAG_DONE); + } + else + { + DrawTexture(twod, animtex.GetFrame(), 320, 240, DTA_VirtualWidth, 640, DTA_VirtualHeight, 480, DTA_CenterOffset, true, TAG_DONE); + } + if (frame > nFrame) + { + nFrame++; + Smacker_GetNextFrame(hSMK); + if (animSnd) for (int i = 0; animSnd[i].framenum >= 0; i++) + { + if (animSnd[i].framenum == nFrame) + { + int sound = animSnd[i].soundnum; + if (sound == -1) + soundEngine->StopAllChannels(); + else if (SoundEnabled()) + soundEngine->StartSound(SOURCE_None, nullptr, nullptr, CHAN_AUTO, CHANF_UI, sound, 1.f, ATTN_NONE); + } + } + } + + return skiprequest ? -1 : nFrame < nFrames ? 1 : 0; + } + + void OnDestroy() override + { + Smacker_Close(hSMK); + if (stream) S_StopCustomStream(stream); + soundEngine->StopAllChannels(); + animtex.Clean(); + } +}; + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* frameticks, bool nosoundcutoff) +{ + auto nothing = []()->DScreenJob* { return Create(); }; + if (!filename) + { + return nothing(); + } + FileReader fr; + // first try as .ivf - but only if sounds are provided - the decoder is video only. + if (ans) + { + auto fn = StripExtension(filename); + DefaultExtension(fn, ".ivf"); + fr = fileSystem.OpenFileReader(fn); + } + + if (!fr.isOpen()) fr = fileSystem.OpenFileReader(filename); + if (!fr.isOpen()) + { + int nLen = strlen(filename); + // Strip the drive letter and retry. + if (nLen >= 3 && isalpha(filename[0]) && filename[1] == ':' && filename[2] == '/') + { + filename += 3; + fr = fileSystem.OpenFileReader(filename); + } + if (!fr.isOpen()) + { + Printf(PRINT_BOLD, "%s: Unable to open video\n", filename); + return nothing(); + } + } + char id[20] = {}; + + fr.Read(&id, 20); + fr.Seek(-20, FileReader::SeekCur); + + if (!memcmp(id, "LPF ", 4)) + { + auto anm = Create(fr, ans, frameticks, nosoundcutoff); + if (!anm->isvalid()) + { + Printf(PRINT_BOLD, "%s: invalid ANM file.\n", filename); + anm->Destroy(); + return nothing(); + } + return anm; + } + else if (!memcmp(id, "SMK2", 4)) + { + fr.Close(); + auto anm = Create(filename, ans, true); // Fixme: Handle Blood's video scaling behavior more intelligently. + if (!anm->isvalid()) + { + Printf(PRINT_BOLD, "%s: invalid SMK file.\n", filename); + anm->Destroy(); + return nothing(); + } + return anm; + } + else if (!memcmp(id, "Interplay MVE File", 18)) + { + auto anm = Create(fr); + if (!anm->isvalid()) + { + anm->Destroy(); + return nothing(); + } + return anm; + } + else if (!memcmp(id, "DKIF\0\0 \0VP80", 12)) + { + auto anm = Create(fr, ans, frameticks? frameticks[1] : 0 ); + if (!anm->isvalid()) + { + anm->Destroy(); + return nothing(); + } + anm->soundtrack = LookupMusic(filename, true); + return anm; + } + // add more formats here. + else + { + Printf(PRINT_BOLD, "%s: Unknown video format\n", filename); + } + return nothing(); +} + + diff --git a/source/core/screenjob.cpp b/source/core/screenjob.cpp index 943178a68..f674f4792 100644 --- a/source/core/screenjob.cpp +++ b/source/core/screenjob.cpp @@ -88,670 +88,6 @@ int DImageScreen::Frame(uint64_t clock, bool skiprequest) return skiprequest ? -1 : span > waittime? 0 : 1; } -//--------------------------------------------------------------------------- -// -// -// -//--------------------------------------------------------------------------- - -class DAnmPlayer : public DScreenJob -{ - // This doesn't need its own class type - anim_t anim; - TArray buffer; - int numframes = 0; - int curframe = 1; - int frametime = 0; - int nextframetime = 0; - AnimTextures animtex; - const AnimSound* animSnd; - const int* frameTicks; - bool nostopsound; - -public: - bool isvalid() { return numframes > 0; } - - DAnmPlayer(FileReader& fr, const AnimSound* ans, const int *frameticks, bool nosoundcutoff) - : animSnd(ans), frameTicks(frameticks), nostopsound(nosoundcutoff) - { - buffer = fr.ReadPadded(1); - fr.Close(); - - if (ANIM_LoadAnim(&anim, buffer.Data(), buffer.Size() - 1) < 0) - { - return; - } - numframes = ANIM_NumFrames(&anim); - animtex.SetSize(AnimTexture::Paletted, 320, 200); - } - - //--------------------------------------------------------------------------- - // - // - // - //--------------------------------------------------------------------------- - - int Frame(uint64_t clock, bool skiprequest) override - { - int currentclock = int(clock * 120 / 1'000'000'000); - - if (currentclock < nextframetime - 1) - { - twod->ClearScreen(); - DrawTexture(twod, animtex.GetFrame(), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_Masked, false, TAG_DONE); - if (skiprequest && !nostopsound) soundEngine->StopAllChannels(); - return skiprequest? -1 : 1; - } - - animtex.SetFrame(ANIM_GetPalette(&anim), ANIM_DrawFrame(&anim, curframe)); - frametime = currentclock; - - twod->ClearScreen(); - DrawTexture(twod, animtex.GetFrame(), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_Masked, false, TAG_DONE); - - int delay = 20; - if (frameTicks) - { - if (curframe == 1) delay = frameTicks[0]; - else if (curframe < numframes - 2) delay = frameTicks[1]; - else delay = frameTicks[2]; - } - nextframetime += delay; - - if (animSnd) for (int i = 0; animSnd[i].framenum >= 0; i++) - { - if (animSnd[i].framenum == curframe) - { - int sound = animSnd[i].soundnum; - if (sound == -1) - soundEngine->StopAllChannels(); - else if (SoundEnabled()) - soundEngine->StartSound(SOURCE_None, nullptr, nullptr, CHAN_AUTO, CHANF_UI, sound, 1.f, ATTN_NONE); - } - } - if (!skiprequest && !nostopsound && curframe == numframes && soundEngine->GetSoundPlayingInfo(SOURCE_None, nullptr, -1)) return 1; - curframe++; - if (skiprequest && !nostopsound) soundEngine->StopAllChannels(); - return skiprequest ? -1 : curframe < numframes? 1 : 0; - } - - void OnDestroy() override - { - buffer.Reset(); - animtex.Clean(); - } -}; - -//--------------------------------------------------------------------------- -// -// -// -//--------------------------------------------------------------------------- - -class DMvePlayer : public DScreenJob -{ - InterplayDecoder decoder; - bool failed = false; - -public: - bool isvalid() { return !failed; } - - DMvePlayer(FileReader& fr) : decoder(SoundEnabled()) - { - failed = !decoder.Open(fr); - } - - //--------------------------------------------------------------------------- - // - // - // - //--------------------------------------------------------------------------- - - int Frame(uint64_t clock, bool skiprequest) override - { - if (failed) return -1; - bool playon = decoder.RunFrame(clock); - twod->ClearScreen(); - DrawTexture(twod, decoder.animTex().GetFrame(), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, TAG_DONE); - - return skiprequest ? -1 : playon ? 1 : 0; - } - - void OnDestroy() override - { - decoder.Close(); - } -}; - -//--------------------------------------------------------------------------- -// -// -// -//--------------------------------------------------------------------------- - -class DVpxPlayer : public DScreenJob -{ - bool failed = false; - FileReader fr; - AnimTextures animtex; - const AnimSound* animSnd; - - unsigned width, height; - TArray Pic; - TArray readBuf; - vpx_codec_ctx_t codec{}; - vpx_codec_iter_t iter = nullptr; - - uint32_t convnumer; - uint32_t convdenom; - - uint64_t nsecsperframe; - uint64_t nextframetime; - - int decstate = 0; - int framenum = 0; - int numframes; - int lastsoundframe = -1; -public: - int soundtrack = -1; - - -public: - bool isvalid() { return !failed; } - - DVpxPlayer(FileReader& fr_, const AnimSound* animSnd_, int origframedelay) - { - fr = std::move(fr_); - animSnd = animSnd_; - - if (!ReadIVFHeader(origframedelay)) - { - // We should never get here, because any file failing this has been eliminated before this constructor got called. - Printf(PRINT_BOLD, "Failed reading IVF header\n"); - failed = true; - } - - Pic.Resize(width * height * 4); - - - // Todo: Support VP9 as well? - vpx_codec_dec_cfg_t cfg = { 1, width, height }; - if (vpx_codec_dec_init(&codec, &vpx_codec_vp8_dx_algo, &cfg, 0)) - { - Printf(PRINT_BOLD, "Error initializing VPX codec.\n"); - failed = true; - } - } - - //--------------------------------------------------------------------------- - // - // - // - //--------------------------------------------------------------------------- - - bool ReadIVFHeader(int origframedelay) - { - // IVF format: http://wiki.multimedia.cx/index.php?title=IVF - uint32_t magic; fr.Read(&magic, 4); // do not byte swap! - if (magic != MAKE_ID('D', 'K', 'I', 'F')) return false; - uint16_t version = fr.ReadUInt16(); - if (version != 0) return false; - uint16_t length = fr.ReadUInt16(); - if (length != 32) return false; - fr.Read(&magic, 4); - if (magic != MAKE_ID('V', 'P', '8', '0')) return false; - - width = fr.ReadUInt16(); - height = fr.ReadUInt16(); - uint32_t fpsdenominator = fr.ReadUInt32(); - uint32_t fpsnumerator = fr.ReadUInt32(); - numframes = fr.ReadUInt32(); - if (numframes == 0) return false; - fr.Seek(4, FileReader::SeekCur); - - if (fpsdenominator > 1000 || fpsnumerator == 0 || fpsdenominator == 0) - { - // default to 30 fps if the header does not provide useful info. - fpsdenominator = 30; - fpsnumerator = 1; - } - - convnumer = 120 * fpsnumerator; - convdenom = fpsdenominator * origframedelay; - - nsecsperframe = int64_t(fpsnumerator) * 1'000'000'000 / fpsdenominator; - nextframetime = 0; - - return true; - } - - //--------------------------------------------------------------------------- - // - // - // - //--------------------------------------------------------------------------- - - bool ReadFrame() - { - int corrupted = 0; - int framesize = fr.ReadInt32(); - fr.Seek(8, FileReader::SeekCur); - if (framesize == 0) return false; - - readBuf.Resize(framesize); - if (fr.Read(readBuf.Data(), framesize) != framesize) return false; - if (vpx_codec_decode(&codec, readBuf.Data(), readBuf.Size(), NULL, 0) != VPX_CODEC_OK) return false; - if (vpx_codec_control(&codec, VP8D_GET_FRAME_CORRUPTED, &corrupted) != VPX_CODEC_OK) return false; - return true; - } - - //--------------------------------------------------------------------------- - // - // - // - //--------------------------------------------------------------------------- - - vpx_image_t *GetFrameData() - { - vpx_image_t *img; - do - { - if (decstate == 0) // first time / begin - { - if (!ReadFrame()) return nullptr; - decstate = 1; - } - - img = vpx_codec_get_frame(&codec, &iter); - if (img == nullptr) - { - decstate = 0; - iter = nullptr; - } - } while (img == nullptr); - - return img->d_w == width && img->d_h == height? img : nullptr; - } - - //--------------------------------------------------------------------------- - // - // - // - //--------------------------------------------------------------------------- - - void SetPixel(uint8_t* dest, uint8_t y, uint8_t u, uint8_t v) - { - dest[0] = y; - dest[1] = u; - dest[2] = v; - } - - bool CreateNextFrame() - { - auto img = GetFrameData(); - if (!img) return false; - uint8_t const* const yplane = img->planes[VPX_PLANE_Y]; - uint8_t const* const uplane = img->planes[VPX_PLANE_U]; - uint8_t const* const vplane = img->planes[VPX_PLANE_V]; - - const int ystride = img->stride[VPX_PLANE_Y]; - const int ustride = img->stride[VPX_PLANE_U]; - const int vstride = img->stride[VPX_PLANE_V]; - - for (unsigned int y = 0; y < height; y += 2) - { - unsigned int y1 = y + 1; - unsigned int wy = width * y; - unsigned int wy1 = width * y1; - - for (unsigned int x = 0; x < width; x += 2) - { - uint8_t u = uplane[ustride * (y >> 1) + (x >> 1)]; - uint8_t v = vplane[vstride * (y >> 1) + (x >> 1)]; - - SetPixel(&Pic[(wy + x) << 2], yplane[ystride * y + x], u, v); - SetPixel(&Pic[(wy + x + 1) << 2], yplane[ystride * y + x + 1], u, v); - SetPixel(&Pic[(wy1 + x) << 2], yplane[ystride * y1 + x], u, v); - SetPixel(&Pic[(wy1 + x + 1) << 2], yplane[ystride * y1 + x + 1], u, v); - } - } - return true; - } - - //--------------------------------------------------------------------------- - // - // - // - //--------------------------------------------------------------------------- - - int Frame(uint64_t clock, bool skiprequest) override - { - if (clock == 0) - { - if (soundtrack > 0) - { - Mus_Play(nullptr, fileSystem.GetFileFullName(soundtrack, false), false); - } - animtex.SetSize(AnimTexture::YUV, width, height); - } - bool stop = false; - if (clock > nextframetime) - { - nextframetime += nsecsperframe; - - if (!CreateNextFrame()) - { - Printf(PRINT_BOLD, "Failed reading next frame\n"); - stop = true; - } - else - { - animtex.SetFrame(nullptr, Pic.Data()); - } - framenum++; - if (framenum >= numframes) stop = true; - - int soundframe = convdenom ? Scale(framenum, convnumer, convdenom) : framenum; - if (soundframe > lastsoundframe) - { - if (animSnd && soundtrack == -1) for (int i = 0; animSnd[i].framenum >= 0; i++) - { - if (animSnd[i].framenum == soundframe) - { - int sound = animSnd[i].soundnum; - if (sound == -1) - soundEngine->StopAllChannels(); - else if (SoundEnabled()) - soundEngine->StartSound(SOURCE_None, nullptr, nullptr, CHAN_AUTO, CHANF_UI, sound, 1.f, ATTN_NONE); - } - } - lastsoundframe = soundframe; - } - } - DrawTexture(twod, animtex.GetFrame(), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit, TAG_DONE); - if (stop || skiprequest) Mus_Stop(); - if (stop) return 0; - return skiprequest ? -1 : 1; - } - - void OnDestroy() override - { - vpx_codec_destroy(&codec); - } -}; - -//--------------------------------------------------------------------------- -// -// -// -//--------------------------------------------------------------------------- - -struct AudioData -{ - int hFx; - SmackerAudioInfo inf; - - int16_t samples[6000 * 20]; // must be a multiple of the stream buffer size and larger than the initial chunk of audio - - int nWrite; - int nRead; -}; - -class DSmkPlayer : public DScreenJob -{ - SmackerHandle hSMK{}; - int numAudioTracks; - AudioData adata; - uint32_t nWidth, nHeight; - uint8_t palette[768]; - AnimTextures animtex; - TArray pFrame; - TArray audioBuffer; - int nFrameRate; - int nFrames; - bool fullscreenScale; - uint64_t nFrameNs; - int nFrame = 0; - const AnimSound* animSnd; - FString filename; - SoundStream* stream = nullptr; - -public: - bool isvalid() { return hSMK.isValid; } - - static bool StreamCallbackFunc(SoundStream* stream, void* buff, int len, void* userdata) - { - DSmkPlayer* pId = (DSmkPlayer*)userdata; - memcpy(buff, &pId->adata.samples[pId->adata.nRead], len); - pId->adata.nRead += len / 2; - if (pId->adata.nRead >= countof(pId->adata.samples)) pId->adata.nRead = 0; - return true; - } - - void copy8bitSamples(unsigned count) - { - for (unsigned i = 0; i < count; i++) - { - adata.samples[adata.nWrite] = (audioBuffer[i] - 128) << 8; - if (++adata.nWrite >= countof(adata.samples)) adata.nWrite = 0; - } - } - - void copy16bitSamples(unsigned count) - { - auto ptr = (uint16_t*)audioBuffer.Data(); - for (unsigned i = 0; i < count/2; i++) - { - adata.samples[adata.nWrite] = *ptr++; - if (++adata.nWrite >= countof(adata.samples)) adata.nWrite = 0; - } - } - - - DSmkPlayer(const char *fn, const AnimSound* ans, bool fixedviewport) - { - hSMK = Smacker_Open(fn); - if (!hSMK.isValid) - { - return; - } - Smacker_GetFrameSize(hSMK, nWidth, nHeight); - pFrame.Resize(nWidth * nHeight + std::max(nWidth, nHeight)); - nFrameRate = Smacker_GetFrameRate(hSMK); - nFrameNs = 1'000'000'000 / nFrameRate; - nFrames = Smacker_GetNumFrames(hSMK); - Smacker_GetPalette(hSMK, palette); - fullscreenScale = (!fixedviewport || (nWidth <= 320 && nHeight <= 200) || nWidth >= 640 || nHeight >= 480); - - bool hassound = false; - numAudioTracks = Smacker_GetNumAudioTracks(hSMK); - if (numAudioTracks) - { - adata.nWrite = 0; - adata.nRead = 0; - adata.inf = Smacker_GetAudioTrackDetails(hSMK, 0); - if (adata.inf.idealBufferSize > 0) - { - audioBuffer.Resize(adata.inf.idealBufferSize); - auto read = Smacker_GetAudioData(hSMK, 0, (int16_t*)audioBuffer.Data()); - if (adata.inf.bitsPerSample == 8) copy8bitSamples(read); - else copy16bitSamples(read); - animSnd = nullptr; - hassound = true; - } - } - if (!hassound) - { - adata.inf = {}; - animSnd = ans; - } - - } - - //--------------------------------------------------------------------------- - // - // - // - //--------------------------------------------------------------------------- - - int Frame(uint64_t clock, bool skiprequest) override - { - int frame = clock / nFrameNs; - - if (clock == 0) - { - animtex.SetSize(AnimTexture::Paletted, nWidth, nHeight); - } - twod->ClearScreen(); - if (frame > nFrame) - { - Smacker_GetPalette(hSMK, palette); - Smacker_GetFrame(hSMK, pFrame.Data()); - animtex.SetFrame(palette, pFrame.Data()); - if (numAudioTracks) - { - auto read = Smacker_GetAudioData(hSMK, 0, (int16_t*)audioBuffer.Data()); - if (adata.inf.bitsPerSample == 8) copy8bitSamples(read); - else copy16bitSamples(read); - if (!stream && read) // the sound may not start in the first frame, but the stream cannot start without any sound data present. - stream = S_CreateCustomStream(6000, adata.inf.sampleRate, adata.inf.nChannels, StreamCallbackFunc, this); - - } - - } - if (fullscreenScale) - { - DrawTexture(twod, animtex.GetFrame(), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, TAG_DONE); - } - else - { - DrawTexture(twod, animtex.GetFrame(), 320, 240, DTA_VirtualWidth, 640, DTA_VirtualHeight, 480, DTA_CenterOffset, true, TAG_DONE); - } - if (frame > nFrame) - { - nFrame++; - Smacker_GetNextFrame(hSMK); - if (animSnd) for (int i = 0; animSnd[i].framenum >= 0; i++) - { - if (animSnd[i].framenum == nFrame) - { - int sound = animSnd[i].soundnum; - if (sound == -1) - soundEngine->StopAllChannels(); - else if (SoundEnabled()) - soundEngine->StartSound(SOURCE_None, nullptr, nullptr, CHAN_AUTO, CHANF_UI, sound, 1.f, ATTN_NONE); - } - } - } - - return skiprequest ? -1 : nFrame < nFrames ? 1 : 0; - } - - void OnDestroy() override - { - Smacker_Close(hSMK); - if (stream) S_StopCustomStream(stream); - soundEngine->StopAllChannels(); - animtex.Clean(); - } -}; - -//--------------------------------------------------------------------------- -// -// -// -//--------------------------------------------------------------------------- - -DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* frameticks, bool nosoundcutoff) -{ - auto nothing = []()->DScreenJob* { return Create(); }; - if (!filename) - { - return nothing(); - } - FileReader fr; - // first try as .ivf - but only if sounds are provided - the decoder is video only. - if (ans) - { - auto fn = StripExtension(filename); - DefaultExtension(fn, ".ivf"); - fr = fileSystem.OpenFileReader(fn); - } - - if (!fr.isOpen()) fr = fileSystem.OpenFileReader(filename); - if (!fr.isOpen()) - { - int nLen = strlen(filename); - // Strip the drive letter and retry. - if (nLen >= 3 && isalpha(filename[0]) && filename[1] == ':' && filename[2] == '/') - { - filename += 3; - fr = fileSystem.OpenFileReader(filename); - } - if (!fr.isOpen()) - { - Printf(PRINT_BOLD, "%s: Unable to open video\n", filename); - return nothing(); - } - } - char id[20] = {}; - - fr.Read(&id, 20); - fr.Seek(-20, FileReader::SeekCur); - - if (!memcmp(id, "LPF ", 4)) - { - auto anm = Create(fr, ans, frameticks, nosoundcutoff); - if (!anm->isvalid()) - { - Printf(PRINT_BOLD, "%s: invalid ANM file.\n", filename); - anm->Destroy(); - return nothing(); - } - return anm; - } - else if (!memcmp(id, "SMK2", 4)) - { - fr.Close(); - auto anm = Create(filename, ans, true); // Fixme: Handle Blood's video scaling behavior more intelligently. - if (!anm->isvalid()) - { - Printf(PRINT_BOLD, "%s: invalid SMK file.\n", filename); - anm->Destroy(); - return nothing(); - } - return anm; - } - else if (!memcmp(id, "Interplay MVE File", 18)) - { - auto anm = Create(fr); - if (!anm->isvalid()) - { - anm->Destroy(); - return nothing(); - } - return anm; - } - else if (!memcmp(id, "DKIF\0\0 \0VP80", 12)) - { - auto anm = Create(fr, ans, frameticks? frameticks[1] : 0 ); - if (!anm->isvalid()) - { - anm->Destroy(); - return nothing(); - } - anm->soundtrack = LookupMusic(filename, true); - return anm; - } - // add more formats here. - else - { - Printf(PRINT_BOLD, "%s: Unknown video format\n", filename); - } - return nothing(); -} - - //--------------------------------------------------------------------------- // // From be4fbbf9ecbed82ba2680f38e57b0d822dc12443 Mon Sep 17 00:00:00 2001 From: Mitchell Richters Date: Fri, 16 Apr 2021 23:37:05 +1000 Subject: [PATCH 03/34] - Exhumed: Hide player panning code behind `cl_slopetilting`. * Fixes #303. again. --- source/games/exhumed/src/player.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/source/games/exhumed/src/player.cpp b/source/games/exhumed/src/player.cpp index 96df6d5b5..1578366b8 100644 --- a/source/games/exhumed/src/player.cpp +++ b/source/games/exhumed/src/player.cpp @@ -1032,14 +1032,13 @@ void FuncPlayer(int a, int nDamage, int nRun) StopLocalSound(); InitSpiritHead(); - PlayerList[nPlayer].nDestVertPan = q16horiz(0); if (currentLevel->levelNumber == 11) { - PlayerList[nPlayer].nDestVertPan = q16horiz(46); + PlayerList[nPlayer].horizon.settarget(46); } else { - PlayerList[nPlayer].nDestVertPan = q16horiz(11); + PlayerList[nPlayer].horizon.settarget(11); } } } @@ -1067,7 +1066,7 @@ void FuncPlayer(int a, int nDamage, int nRun) zVelB = -zVelB; } - if (zVelB > 512 && !PlayerList[nPlayer].horizon.horiz.asq16() && !(sPlayerInput[nPlayer].actions & SB_AIMMODE)) { + if (zVelB > 512 && !PlayerList[nPlayer].horizon.horiz.asq16() && cl_slopetilting) { sPlayerInput[nPlayer].actions |= SB_CENTERVIEW; } } @@ -2665,10 +2664,13 @@ loc_1BD2E: pPlayer->bPlayerPan = false; } - double nVertPan = (pPlayer->nDestVertPan - pPlayer->horizon.horiz).asq16() * (1. / (FRACUNIT << 2)); - if (nVertPan != 0) + if (cl_slopetilting) { - pPlayer->horizon.addadjustment(abs(nVertPan) >= 4 ? clamp(nVertPan, -4, 4) : nVertPan * 2.); + double nVertPan = (pPlayer->nDestVertPan - pPlayer->horizon.horiz).asq16() * (1. / (FRACUNIT << 2)); + if (nVertPan != 0) + { + pPlayer->horizon.addadjustment(abs(nVertPan) >= 4 ? clamp(nVertPan, -4, 4) : nVertPan * 2.); + } } } else // else, player's health is less than 0 From 7e9b8059cf848fda6495f510b6b09eda3dbe464f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 16 Apr 2021 16:55:07 +0200 Subject: [PATCH 04/34] - enable cl_slopetilting for Exhumed as well, now that it has a function there --- wadsrc/static/menudef.txt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 4ddf92bca..f19c4ccea 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1033,10 +1033,7 @@ OptionMenu "VideoOptions" protected StaticText "" Option "$DSPLYMNU_VOXELS", "r_voxels", "OnOff" Option "$DSPLYMNU_SHADOWS", "r_shadows", "OnOff" - ifnotgame(Exhumed) - { - Option "$DSPLYMNU_SLOPETILT", "cl_slopetilting", "OnOff" - } + Option "$DSPLYMNU_SLOPETILT", "cl_slopetilting", "OnOff" ifnotgame(Blood, Exhumed) { Option "$DSPLYMNU_VIEWBOB", "cl_viewbob", "OnOff" From dbd3e1de44e2daa3b05f14802908c0f5fa6abd27 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 16 Apr 2021 00:50:13 +0200 Subject: [PATCH 05/34] - Screen Job refactoring WIP. Framework to let them handle proper input events. Not used yet. --- source/common/engine/d_event.cpp | 15 +++++---- source/core/cheats.cpp | 12 ++++++++ source/core/cheats.h | 1 + source/core/console/d_event.cpp | 6 ++++ source/core/d_net.cpp | 1 + source/core/d_protocol.h | 1 + source/core/gamecontrol.cpp | 23 -------------- source/core/mainloop.cpp | 5 +-- source/core/screenjob.cpp | 52 ++++++++++++++++++++++++++++++-- source/core/screenjob.h | 31 +++++++++++++++++-- 10 files changed, 112 insertions(+), 35 deletions(-) diff --git a/source/common/engine/d_event.cpp b/source/common/engine/d_event.cpp index b42915c7b..3a779a5fc 100644 --- a/source/common/engine/d_event.cpp +++ b/source/common/engine/d_event.cpp @@ -76,12 +76,15 @@ void D_ProcessEvents (void) continue; if (ev->type == EV_DeviceChange) UpdateJoystickMenu(I_UpdateDeviceList()); - if (gamestate == GS_INTRO) - continue; - if (C_Responder (ev)) - continue; // console ate the event - if (M_Responder (ev)) - continue; // menu ate the event + + if (gamestate != GS_INTRO) // GS_INTRO blocks the UI. + { + if (C_Responder(ev)) + continue; // console ate the event + if (M_Responder(ev)) + continue; // menu ate the event + } + G_Responder (ev); } } diff --git a/source/core/cheats.cpp b/source/core/cheats.cpp index d8695173a..1a7086f8b 100644 --- a/source/core/cheats.cpp +++ b/source/core/cheats.cpp @@ -44,6 +44,7 @@ #include "mmulti.h" #include "gstrings.h" #include "gamecontrol.h" +#include "screenjob.h" #include "mapinfo.h" CVAR(Bool, sv_cheats, true, CVAR_ARCHIVE|CVAR_SERVERINFO) @@ -239,6 +240,17 @@ void changeMap(int player, uint8_t** stream, bool skip) // //--------------------------------------------------------------------------- +void endScreenJob(int player, uint8_t** stream, bool skip) +{ + if (!skip) EndScreenJob(); +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void ChangeLevel(MapRecord* map, int skill) { Net_WriteByte(DEM_CHANGEMAP); diff --git a/source/core/cheats.h b/source/core/cheats.h index bc4245ede..7398073ae 100644 --- a/source/core/cheats.h +++ b/source/core/cheats.h @@ -8,3 +8,4 @@ EXTERN_CVAR(Bool, sv_cheats) void genericCheat(int player, uint8_t** stream, bool skip); void changeMap(int player, uint8_t** stream, bool skip); +void endScreenJob(int player, uint8_t** stream, bool skip); diff --git a/source/core/console/d_event.cpp b/source/core/console/d_event.cpp index 2af44f0b8..007d0c46d 100644 --- a/source/core/console/d_event.cpp +++ b/source/core/console/d_event.cpp @@ -43,6 +43,7 @@ #include "gamecontrol.h" #include "uiinput.h" #include "automap.h" +#include "screenjob.h" //========================================================================== // @@ -53,6 +54,11 @@ bool G_Responder (event_t *ev) { + if (gamestate == GS_INTRO || gamestate == GS_INTERMISSION) + { + return ScreenJobResponder(ev); + } + if (CT_Responder(ev)) return true; // chat ate the event if (Cheat_Responder(ev)) diff --git a/source/core/d_net.cpp b/source/core/d_net.cpp index 32c7864e1..5650ea43f 100644 --- a/source/core/d_net.cpp +++ b/source/core/d_net.cpp @@ -1674,6 +1674,7 @@ bool D_CheckNetGame (void) Net_SetCommandHandler(DEM_GENERICCHEAT, genericCheat); Net_SetCommandHandler(DEM_CHANGEMAP, changeMap); + Net_SetCommandHandler(DEM_ENDSCREENJOB, endScreenJob); for (i = 0; i < MAXNETNODES; i++) { diff --git a/source/core/d_protocol.h b/source/core/d_protocol.h index 50cc29555..cac55b56e 100644 --- a/source/core/d_protocol.h +++ b/source/core/d_protocol.h @@ -89,6 +89,7 @@ enum EDemoCommand DEM_GENERICCHEAT, DEM_GIVE, DEM_CHANGEMAP, + DEM_ENDSCREENJOB, DEM_MAX }; diff --git a/source/core/gamecontrol.cpp b/source/core/gamecontrol.cpp index 96431b3e6..7963c384d 100644 --- a/source/core/gamecontrol.cpp +++ b/source/core/gamecontrol.cpp @@ -976,29 +976,6 @@ int RunGame() // //--------------------------------------------------------------------------- - -void TickSubsystems() -{ - // run these on an independent timer until we got something working for the games. - static const uint64_t tickInterval = 1'000'000'000 / 30; - static uint64_t nexttick = 0; - - auto nowtick = I_nsTime(); - if (nexttick == 0) nexttick = nowtick; - int cnt = 0; - while (nexttick <= nowtick && cnt < 5) - { - nexttick += tickInterval; - C_Ticker(); - M_Ticker(); - C_RunDelayedCommands(); - cnt++; - } - // If this took too long the engine was most likely suspended so recalibrate the timer. - // Perfect precision is not needed here. - if (cnt == 5) nexttick = nowtick + tickInterval; -} - void updatePauseStatus() { // This must go through the network in multiplayer games. diff --git a/source/core/mainloop.cpp b/source/core/mainloop.cpp index 8a7ed3e12..7a65c950d 100644 --- a/source/core/mainloop.cpp +++ b/source/core/mainloop.cpp @@ -328,9 +328,10 @@ static void GameTicker() case GS_MENUSCREEN: case GS_FULLCONSOLE: + break; case GS_INTERMISSION: case GS_INTRO: - // These elements do not tick at game rate. + ScreenJobTick(); break; } @@ -370,7 +371,7 @@ void Display() case GS_INTRO: case GS_INTERMISSION: // screen jobs are not bound by the game ticker so they need to be ticked in the display loop. - RunScreenJobFrame(); + ScreenJobDraw(); break; case GS_LEVEL: diff --git a/source/core/screenjob.cpp b/source/core/screenjob.cpp index f674f4792..d57f13c53 100644 --- a/source/core/screenjob.cpp +++ b/source/core/screenjob.cpp @@ -193,7 +193,7 @@ public: screenfade = 1.f; } job.job->SetClock(clock); - int state = job.job->Frame(clock, skiprequest); + int state = job.job->Frame(clock, skiprequest, 0); clock = job.job->GetClock(); if (clock == 0) clock = 1; return state; @@ -225,6 +225,36 @@ public: return 1; } + bool OnEvent(event_t* ev) + { + if (jobs[index].job->state == DScreenJob::stopping) return false; + return jobs[index].job->OnEvent(ev); + } + + void OnFinished() + { + if (completion) completion(false); + completion = nullptr; // only finish once. + } + + void OnTick() + { + if (index >= jobs.Size()) + { + //DeleteJobs(); + //twod->SetScreenFade(1); + //twod->ClearScreen(); // This must not leave the 2d buffer empty. + //if (gamestate == GS_INTRO) OnFinished(); + //else Net_WriteByte(DEM_ENDSCREENJOB); // intermissions must be terminated synchronously. + } + else + { + if (jobs[index].job->state == DScreenJob::stopping) return; + jobs[index].job->ticks++; + jobs[index].job->OnTick(); + } + } + bool RunFrame() { if (index >= jobs.Size()) @@ -300,7 +330,25 @@ void DeleteScreenJob() twod->SetScreenFade(1); } -void RunScreenJobFrame() +void EndScreenJob() +{ + if (runner) runner->OnFinished(); + DeleteScreenJob(); +} + + +bool ScreenJobResponder(event_t* ev) +{ + if (runner) return runner->OnEvent(ev); + return false; +} + +void ScreenJobTick() +{ + if (runner) runner->OnTick(); +} + +void ScreenJobDraw() { // we cannot recover from this because we have no completion callback to call. if (!runner) diff --git a/source/core/screenjob.h b/source/core/screenjob.h index 64467490e..f51ae4ba4 100644 --- a/source/core/screenjob.h +++ b/source/core/screenjob.h @@ -2,6 +2,7 @@ #include #include "dobject.h" #include "v_2ddrawer.h" +#include "d_eventbase.h" using CompletionFunc = std::function; struct JobDesc; @@ -16,8 +17,19 @@ class DScreenJob : public DObject int fadestate = fadein; friend class ScreenJobRunner; +protected: + int ticks = 0; + int state = running; public: + enum + { + running = 1, // normal operation + skipped = 2, // finished by user skipping + finished = 3, // finished by completing its sequence + stopping = 4, // running ending animations / fadeout, etc. Will not accept more input. + stopped = 5, // we're done here. + }; enum { visible = 0, @@ -42,7 +54,19 @@ public: return now; } - virtual int Frame(uint64_t clock, bool skiprequest) { return 0; } + virtual bool OnEvent(event_t* evt) { return false; } + virtual void OnTick() { } + virtual int Frame(uint64_t clock, bool skiprequest) { return 1; } + virtual void Draw(double smoothratio) {} + + int Frame(uint64_t clock, bool skiprequest, double smoothratio) + { + Draw(smoothratio); + if (state == skipped) return -1; + if (state == finished) return 0; + return Frame(clock, skiprequest); + } + int GetFadeState() const { return fadestate; } }; @@ -105,8 +129,11 @@ struct JobDesc void RunScreenJob(JobDesc *jobs, int count, CompletionFunc completion, bool clearbefore = true, bool blockingui = false); +void EndScreenJob(); void DeleteScreenJob(); -void RunScreenJobFrame(); +bool ScreenJobResponder(event_t* ev); +void ScreenJobTick(); +void ScreenJobDraw(); struct AnimSound { From aad6158288bc1be10c2d8faab038f17e7c82c0bf Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 16 Apr 2021 00:02:09 +0200 Subject: [PATCH 06/34] - cleanup of movie player code, migration to event interface. --- source/core/movie/movieplayer.cpp | 223 +++++++++++++++++++++--------- source/core/screenjob.cpp | 16 ++- source/core/screenjob.h | 15 ++ 3 files changed, 188 insertions(+), 66 deletions(-) diff --git a/source/core/movie/movieplayer.cpp b/source/core/movie/movieplayer.cpp index 96137a03f..b72f39f21 100644 --- a/source/core/movie/movieplayer.cpp +++ b/source/core/movie/movieplayer.cpp @@ -51,13 +51,22 @@ #include "raze_music.h" +class MoviePlayer +{ +public: + virtual void Start() {} + virtual bool Frame(uint64_t clock) = 0; + virtual void Stop() {} + virtual ~MoviePlayer() = default; +}; + //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- -class DAnmPlayer : public DScreenJob +class AnmPlayer : public MoviePlayer { // This doesn't need its own class type anim_t anim; @@ -74,7 +83,7 @@ class DAnmPlayer : public DScreenJob public: bool isvalid() { return numframes > 0; } - DAnmPlayer(FileReader& fr, const AnimSound* ans, const int *frameticks, bool nosoundcutoff) + AnmPlayer(FileReader& fr, const AnimSound* ans, const int *frameticks, bool nosoundcutoff) : animSnd(ans), frameTicks(frameticks), nostopsound(nosoundcutoff) { buffer = fr.ReadPadded(1); @@ -94,7 +103,7 @@ public: // //--------------------------------------------------------------------------- - int Frame(uint64_t clock, bool skiprequest) override + bool Frame(uint64_t clock) override { int currentclock = int(clock * 120 / 1'000'000'000); @@ -102,8 +111,7 @@ public: { twod->ClearScreen(); DrawTexture(twod, animtex.GetFrame(), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_Masked, false, TAG_DONE); - if (skiprequest && !nostopsound) soundEngine->StopAllChannels(); - return skiprequest? -1 : 1; + return true; } animtex.SetFrame(ANIM_GetPalette(&anim), ANIM_DrawFrame(&anim, curframe)); @@ -132,13 +140,18 @@ public: soundEngine->StartSound(SOURCE_None, nullptr, nullptr, CHAN_AUTO, CHANF_UI, sound, 1.f, ATTN_NONE); } } - if (!skiprequest && !nostopsound && curframe == numframes && soundEngine->GetSoundPlayingInfo(SOURCE_None, nullptr, -1)) return 1; + if (!nostopsound && curframe == numframes && soundEngine->GetSoundPlayingInfo(SOURCE_None, nullptr, -1)) return true; curframe++; - if (skiprequest && !nostopsound) soundEngine->StopAllChannels(); - return skiprequest ? -1 : curframe < numframes? 1 : 0; + return curframe < numframes; } - void OnDestroy() override + void Stop() override + { + if (!nostopsound) soundEngine->StopAllChannels(); + } + + + ~AnmPlayer() { buffer.Reset(); animtex.Clean(); @@ -151,7 +164,7 @@ public: // //--------------------------------------------------------------------------- -class DMvePlayer : public DScreenJob +class MvePlayer : public MoviePlayer { InterplayDecoder decoder; bool failed = false; @@ -159,7 +172,7 @@ class DMvePlayer : public DScreenJob public: bool isvalid() { return !failed; } - DMvePlayer(FileReader& fr) : decoder(SoundEnabled()) + MvePlayer(FileReader& fr) : decoder(SoundEnabled()) { failed = !decoder.Open(fr); } @@ -170,17 +183,16 @@ public: // //--------------------------------------------------------------------------- - int Frame(uint64_t clock, bool skiprequest) override + bool Frame(uint64_t clock) override { - if (failed) return -1; + if (failed) return false; bool playon = decoder.RunFrame(clock); twod->ClearScreen(); DrawTexture(twod, decoder.animTex().GetFrame(), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, TAG_DONE); - - return skiprequest ? -1 : playon ? 1 : 0; + return playon; } - void OnDestroy() override + ~MvePlayer() { decoder.Close(); } @@ -192,7 +204,7 @@ public: // //--------------------------------------------------------------------------- -class DVpxPlayer : public DScreenJob +class VpxPlayer : public MoviePlayer { bool failed = false; FileReader fr; @@ -222,7 +234,7 @@ public: public: bool isvalid() { return !failed; } - DVpxPlayer(FileReader& fr_, const AnimSound* animSnd_, int origframedelay) + VpxPlayer(FileReader& fr_, const AnimSound* animSnd_, int origframedelay, FString& error) { fr = std::move(fr_); animSnd = animSnd_; @@ -230,7 +242,7 @@ public: if (!ReadIVFHeader(origframedelay)) { // We should never get here, because any file failing this has been eliminated before this constructor got called. - Printf(PRINT_BOLD, "Failed reading IVF header\n"); + error.Format("Failed reading IVF header\n"); failed = true; } @@ -241,7 +253,7 @@ public: vpx_codec_dec_cfg_t cfg = { 1, width, height }; if (vpx_codec_dec_init(&codec, &vpx_codec_vp8_dx_algo, &cfg, 0)) { - Printf(PRINT_BOLD, "Error initializing VPX codec.\n"); + error.Format("Error initializing VPX codec.\n"); failed = true; } } @@ -387,16 +399,23 @@ public: // //--------------------------------------------------------------------------- - int Frame(uint64_t clock, bool skiprequest) override + void Start() override { - if (clock == 0) + if (soundtrack > 0) { - if (soundtrack > 0) - { - Mus_Play(nullptr, fileSystem.GetFileFullName(soundtrack, false), false); - } - animtex.SetSize(AnimTexture::YUV, width, height); + Mus_Play(nullptr, fileSystem.GetFileFullName(soundtrack, false), false); } + animtex.SetSize(AnimTexture::YUV, width, height); + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + bool Frame(uint64_t clock) override + { bool stop = false; if (clock > nextframetime) { @@ -432,14 +451,18 @@ public: } } DrawTexture(twod, animtex.GetFrame(), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit, TAG_DONE); - if (stop || skiprequest) Mus_Stop(); - if (stop) return 0; - return skiprequest ? -1 : 1; + return !stop; } - void OnDestroy() override + void Stop() + { + Mus_Stop(); + } + + ~VpxPlayer() { vpx_codec_destroy(&codec); + animtex.Clean(); } }; @@ -460,7 +483,7 @@ struct AudioData int nRead; }; -class DSmkPlayer : public DScreenJob +class SmkPlayer : public MoviePlayer { SmackerHandle hSMK{}; int numAudioTracks; @@ -484,7 +507,7 @@ public: static bool StreamCallbackFunc(SoundStream* stream, void* buff, int len, void* userdata) { - DSmkPlayer* pId = (DSmkPlayer*)userdata; + SmkPlayer* pId = (SmkPlayer*)userdata; memcpy(buff, &pId->adata.samples[pId->adata.nRead], len); pId->adata.nRead += len / 2; if (pId->adata.nRead >= countof(pId->adata.samples)) pId->adata.nRead = 0; @@ -511,7 +534,7 @@ public: } - DSmkPlayer(const char *fn, const AnimSound* ans, bool fixedviewport) + SmkPlayer(const char *fn, const AnimSound* ans, bool fixedviewport) { hSMK = Smacker_Open(fn); if (!hSMK.isValid) @@ -551,23 +574,32 @@ public: } + //--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + + void Start() override + { + animtex.SetSize(AnimTexture::Paletted, nWidth, nHeight); + } + //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- - int Frame(uint64_t clock, bool skiprequest) override + bool Frame(uint64_t clock) override { int frame = clock / nFrameNs; - if (clock == 0) - { - animtex.SetSize(AnimTexture::Paletted, nWidth, nHeight); - } twod->ClearScreen(); + Printf("clock = %llu, frame = %d\n", clock, frame); if (frame > nFrame) { + Printf("Updating\n"); Smacker_GetPalette(hSMK, palette); Smacker_GetFrame(hSMK, pFrame.Data()); animtex.SetFrame(palette, pFrame.Data()); @@ -607,10 +639,10 @@ public: } } - return skiprequest ? -1 : nFrame < nFrames ? 1 : 0; + return nFrame < nFrames; } - void OnDestroy() override + ~SmkPlayer() { Smacker_Close(hSMK); if (stream) S_StopCustomStream(stream); @@ -625,13 +657,56 @@ public: // //--------------------------------------------------------------------------- -DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* frameticks, bool nosoundcutoff) +class DMoviePlayer : public DSkippableScreenJob { - auto nothing = []()->DScreenJob* { return Create(); }; - if (!filename) + MoviePlayer* player; + bool started = false; + +public: + DMoviePlayer(MoviePlayer* mp) { - return nothing(); + player = mp; } + + void Draw(double smoothratio) override + { + if (!player) + { + state = stopped; + return; + } + if (!started) + { + started = true; + player->Start(); + } + uint64_t clock = (ticks + smoothratio) * 1'000'000'000. / GameTicRate; + if (state == running && !player->Frame(clock)) + { + state = finished; + } + } + + void OnDestroy() override + { + if (player) + { + player->Stop(); + delete player; + } + player = nullptr; + } +}; + + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +MoviePlayer* OpenMovie(const char* filename, const AnimSound* ans, const int* frameticks, bool nosoundcutoff, FString& error) +{ FileReader fr; // first try as .ivf - but only if sounds are provided - the decoder is video only. if (ans) @@ -653,8 +728,8 @@ DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* fra } if (!fr.isOpen()) { - Printf(PRINT_BOLD, "%s: Unable to open video\n", filename); - return nothing(); + error.Format("%s: Unable to open video\n", filename); + return nullptr; } } char id[20] = {}; @@ -664,44 +739,44 @@ DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* fra if (!memcmp(id, "LPF ", 4)) { - auto anm = Create(fr, ans, frameticks, nosoundcutoff); + auto anm = new AnmPlayer(fr, ans, frameticks, nosoundcutoff); if (!anm->isvalid()) { - Printf(PRINT_BOLD, "%s: invalid ANM file.\n", filename); - anm->Destroy(); - return nothing(); + error.Format("%s: invalid ANM file.\n", filename); + delete anm; + return nullptr; } return anm; } else if (!memcmp(id, "SMK2", 4)) { fr.Close(); - auto anm = Create(filename, ans, true); // Fixme: Handle Blood's video scaling behavior more intelligently. + auto anm = new SmkPlayer(filename, ans, true); // Fixme: Handle Blood's video scaling behavior more intelligently. if (!anm->isvalid()) { - Printf(PRINT_BOLD, "%s: invalid SMK file.\n", filename); - anm->Destroy(); - return nothing(); + error.Format("%s: invalid SMK file.\n", filename); + delete anm; + return nullptr; } return anm; } else if (!memcmp(id, "Interplay MVE File", 18)) { - auto anm = Create(fr); + auto anm = new MvePlayer(fr); if (!anm->isvalid()) { - anm->Destroy(); - return nothing(); + delete anm; + return nullptr; } return anm; } else if (!memcmp(id, "DKIF\0\0 \0VP80", 12)) { - auto anm = Create(fr, ans, frameticks? frameticks[1] : 0 ); + auto anm = new VpxPlayer(fr, ans, frameticks ? frameticks[1] : 0, error); if (!anm->isvalid()) { - anm->Destroy(); - return nothing(); + delete anm; + return nullptr; } anm->soundtrack = LookupMusic(filename, true); return anm; @@ -709,9 +784,31 @@ DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* fra // add more formats here. else { - Printf(PRINT_BOLD, "%s: Unknown video format\n", filename); + error.Format("%s: Unknown video format\n", filename); + return nullptr; } - return nothing(); +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* frameticks, bool nosoundcutoff) +{ + if (!filename) + { + return Create(); + } + FString error; + auto movie = OpenMovie(filename, ans, frameticks, nosoundcutoff, error); + if (!movie) + { + Printf(TEXTCOLOR_YELLOW, "%s", error.GetChars()); + return Create(); + } + return Create(movie); } diff --git a/source/core/screenjob.cpp b/source/core/screenjob.cpp index d57f13c53..29da6dbec 100644 --- a/source/core/screenjob.cpp +++ b/source/core/screenjob.cpp @@ -57,6 +57,13 @@ IMPLEMENT_CLASS(DScreenJob, true, false) IMPLEMENT_CLASS(DImageScreen, true, false) +bool DSkippableScreenJob::OnEvent(event_t* evt) +{ + if (evt->type == EV_GUI_KeyDown) state = skipped; + return true; +} + + int DBlackScreen::Frame(uint64_t clock, bool skiprequest) { int span = int(clock / 1'000'000); @@ -193,7 +200,7 @@ public: screenfade = 1.f; } job.job->SetClock(clock); - int state = job.job->Frame(clock, skiprequest, 0); + int state = job.job->Frame(clock, skiprequest, I_GetTimeFrac()); clock = job.job->GetClock(); if (clock == 0) clock = 1; return state; @@ -227,7 +234,8 @@ public: bool OnEvent(event_t* ev) { - if (jobs[index].job->state == DScreenJob::stopping) return false; + if (index >= jobs.Size()) return false; + if (jobs[index].job->state != DScreenJob::running) return false; return jobs[index].job->OnEvent(ev); } @@ -249,7 +257,7 @@ public: } else { - if (jobs[index].job->state == DScreenJob::stopping) return; + if (jobs[index].job->state != DScreenJob::running) return; jobs[index].job->ticks++; jobs[index].job->OnTick(); } @@ -282,6 +290,7 @@ public: startTime = -1; clock = 0; jobs[index].job->fadestate = DScreenJob::fadeout; + jobs[index].job->state = DScreenJob::stopping; gamestate = GS_INTRO; // block menu and console during fadeout - this can cause timing problems. actionState = State_Fadeout; } @@ -296,6 +305,7 @@ public: int ended = FadeoutFrame(); if (ended < 1) { + jobs[index].job->state = DScreenJob::stopped; AdvanceJob(terminateState < 0); } } diff --git a/source/core/screenjob.h b/source/core/screenjob.h index f51ae4ba4..39c24fae7 100644 --- a/source/core/screenjob.h +++ b/source/core/screenjob.h @@ -77,6 +77,21 @@ public: // //--------------------------------------------------------------------------- +class DSkippableScreenJob : public DScreenJob +{ +protected: + DSkippableScreenJob(int fade = 0, float fadet = 250.f) : DScreenJob(fade, fadet) + {} + + bool OnEvent(event_t* evt) override; +}; + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + class DBlackScreen : public DScreenJob { int wait; From 6ed1d5e6780a04c532449eeac24a5436ac0d7141 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 16 Apr 2021 00:11:02 +0200 Subject: [PATCH 07/34] - DBlackScreen and DImageScreen migrated to event-based handling. --- source/core/movie/movieplayer.cpp | 6 ++-- source/core/screenjob.cpp | 41 ++++++++++++++++----------- source/core/screenjob.h | 17 +++++++---- source/games/blood/src/credits.cpp | 4 +-- source/games/duke/src/2d_d.cpp | 2 +- source/games/exhumed/src/gameloop.cpp | 2 +- source/games/exhumed/src/movie.cpp | 2 +- 7 files changed, 44 insertions(+), 30 deletions(-) diff --git a/source/core/movie/movieplayer.cpp b/source/core/movie/movieplayer.cpp index b72f39f21..e65a04d63 100644 --- a/source/core/movie/movieplayer.cpp +++ b/source/core/movie/movieplayer.cpp @@ -666,8 +666,10 @@ public: DMoviePlayer(MoviePlayer* mp) { player = mp; + pausable = false; } + void Draw(double smoothratio) override { if (!player) @@ -799,14 +801,14 @@ DScreenJob* PlayVideo(const char* filename, const AnimSound* ans, const int* fra { if (!filename) { - return Create(); + return Create(1); } FString error; auto movie = OpenMovie(filename, ans, frameticks, nosoundcutoff, error); if (!movie) { Printf(TEXTCOLOR_YELLOW, "%s", error.GetChars()); - return Create(); + return Create(1); } return Create(movie); } diff --git a/source/core/screenjob.cpp b/source/core/screenjob.cpp index 29da6dbec..cbcb39a27 100644 --- a/source/core/screenjob.cpp +++ b/source/core/screenjob.cpp @@ -63,12 +63,19 @@ bool DSkippableScreenJob::OnEvent(event_t* evt) return true; } - -int DBlackScreen::Frame(uint64_t clock, bool skiprequest) +void DBlackScreen::OnTick() { - int span = int(clock / 1'000'000); + if (cleared) + { + int span = ticks * 1000 / GameTicRate; + if (span > wait) state = finished; + } +} + +void DBlackScreen::Draw(double) +{ + cleared = true; twod->ClearScreen(); - return span < wait ? 1 : -1; } //--------------------------------------------------------------------------- @@ -77,22 +84,22 @@ int DBlackScreen::Frame(uint64_t clock, bool skiprequest) // //--------------------------------------------------------------------------- -int DImageScreen::Frame(uint64_t clock, bool skiprequest) +void DImageScreen::OnTick() { - if (tilenum > 0) + if (cleared) { - tex = tileGetTexture(tilenum, true); + int span = ticks * 1000 / GameTicRate; + if (span > waittime) state = finished; } - if (!tex) - { - twod->ClearScreen(); - return 0; - } - int span = int(clock / 1'000'000); +} + + +void DImageScreen::Draw(double smoothratio) +{ + if (tilenum > 0) tex = tileGetTexture(tilenum, true); twod->ClearScreen(); - DrawTexture(twod, tex, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_LegacyRenderStyle, STYLE_Normal, DTA_TranslationIndex, trans, TAG_DONE); - // Only end after having faded out. - return skiprequest ? -1 : span > waittime? 0 : 1; + if (tex) DrawTexture(twod, tex, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_LegacyRenderStyle, STYLE_Normal, DTA_TranslationIndex, trans, TAG_DONE); + cleared = true; } //--------------------------------------------------------------------------- @@ -200,7 +207,7 @@ public: screenfade = 1.f; } job.job->SetClock(clock); - int state = job.job->Frame(clock, skiprequest, I_GetTimeFrac()); + int state = job.job->Frame(clock, skiprequest, M_Active()? 1. : I_GetTimeFrac()); clock = job.job->GetClock(); if (clock == 0) clock = 1; return state; diff --git a/source/core/screenjob.h b/source/core/screenjob.h index 39c24fae7..cdf72014a 100644 --- a/source/core/screenjob.h +++ b/source/core/screenjob.h @@ -20,6 +20,7 @@ class DScreenJob : public DObject protected: int ticks = 0; int state = running; + bool pausable = true; public: enum @@ -55,7 +56,7 @@ public: } virtual bool OnEvent(event_t* evt) { return false; } - virtual void OnTick() { } + virtual void OnTick() { /*state = finished;*/ } virtual int Frame(uint64_t clock, bool skiprequest) { return 1; } virtual void Draw(double smoothratio) {} @@ -95,10 +96,12 @@ protected: class DBlackScreen : public DScreenJob { int wait; + bool cleared = false; public: DBlackScreen(int w) : wait(w) {} - int Frame(uint64_t clock, bool skiprequest) override; + void OnTick() override; + void Draw(double smooth) override; }; //--------------------------------------------------------------------------- @@ -107,29 +110,31 @@ public: // //--------------------------------------------------------------------------- -class DImageScreen : public DScreenJob +class DImageScreen : public DSkippableScreenJob { DECLARE_CLASS(DImageScreen, DScreenJob) int tilenum = -1; int trans; int waittime; // in ms. + bool cleared = false; FGameTexture* tex = nullptr; public: - DImageScreen(FGameTexture* tile, int fade = DScreenJob::fadein | DScreenJob::fadeout, int wait = 3000, int translation = 0) : DScreenJob(fade), waittime(wait) + DImageScreen(FGameTexture* tile, int fade = DScreenJob::fadein | DScreenJob::fadeout, int wait = 3000, int translation = 0) : DSkippableScreenJob(fade), waittime(wait) { tex = tile; trans = translation; } - DImageScreen(int tile, int fade = DScreenJob::fadein | DScreenJob::fadeout, int wait = 3000, int translation = 0) : DScreenJob(fade), waittime(wait) + DImageScreen(int tile, int fade = DScreenJob::fadein | DScreenJob::fadeout, int wait = 3000, int translation = 0) : DSkippableScreenJob(fade), waittime(wait) { tilenum = tile; trans = translation; } - int Frame(uint64_t clock, bool skiprequest) override; + void OnTick() override; + void Draw(double smooth) override; }; diff --git a/source/games/blood/src/credits.cpp b/source/games/blood/src/credits.cpp index c18453352..90f9cbc9d 100644 --- a/source/games/blood/src/credits.cpp +++ b/source/games/blood/src/credits.cpp @@ -64,7 +64,7 @@ void playlogos() if (!userConfig.nologo) { - if (fileSystem.FindFile("logo.smk")) + if (fileSystem.FindFile("logo.smk") != -1) { jobs[job++] = { PlayVideo("logo.smk", &logosound[0], 0) }; } @@ -73,7 +73,7 @@ void playlogos() jobs[job++] = { Create(1), []() { sndStartSample("THUNDER2", 128, -1); } }; jobs[job++] = { Create(2050) }; } - if (fileSystem.FindFile("gti.smk")) + if (fileSystem.FindFile("gti.smk") != -1) { jobs[job++] = { PlayVideo("gti.smk", &logosound[2], 0) }; } diff --git a/source/games/duke/src/2d_d.cpp b/source/games/duke/src/2d_d.cpp index 28e268964..4b50d99bd 100644 --- a/source/games/duke/src/2d_d.cpp +++ b/source/games/duke/src/2d_d.cpp @@ -296,7 +296,7 @@ void Logo_d(const CompletionFunc &completion) if (!userConfig.nologo) { if (!isShareware()) jobs[job++] = { PlayVideo("logo.anm", logosound, logoframetimes), []() { S_PlaySpecialMusic(MUS_INTRO); } }; - else jobs[job++] = { Create(), []() { S_PlaySpecialMusic(MUS_INTRO); } }; + else jobs[job++] = { Create(1), []() { S_PlaySpecialMusic(MUS_INTRO); } }; if (!isNam()) jobs[job++] = { Create(), nullptr }; } else S_PlaySpecialMusic(MUS_INTRO); diff --git a/source/games/exhumed/src/gameloop.cpp b/source/games/exhumed/src/gameloop.cpp index cb05c6774..1028c1548 100644 --- a/source/games/exhumed/src/gameloop.cpp +++ b/source/games/exhumed/src/gameloop.cpp @@ -167,7 +167,7 @@ static void Intermission(MapRecord *from_map, MapRecord *to_map) showmap(from_map ? from_map->levelNumber : -1, to_map->levelNumber, nBestLevel, jobs); } else - jobs.Push({ Create() }); // we need something in here even in the multiplayer case. + jobs.Push({ Create(1) }); // we need something in here even in the multiplayer case. } } else diff --git a/source/games/exhumed/src/movie.cpp b/source/games/exhumed/src/movie.cpp index d26b9ce52..b743b473c 100644 --- a/source/games/exhumed/src/movie.cpp +++ b/source/games/exhumed/src/movie.cpp @@ -274,7 +274,7 @@ DScreenJob* PlayMovie(const char* fileName) auto fp = fileSystem.OpenFileReader(fileName); if (!fp.isOpen()) { - return Create(); + return Create(1); } char buffer[4]; fp.Read(buffer, 4); From 2a2c85c08249218b9d95776b904668c70b789bca Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 16 Apr 2021 00:20:12 +0200 Subject: [PATCH 08/34] - migrated Duke's intro images and the first episode's ending animation. --- source/core/movie/movieplayer.cpp | 2 - source/games/blood/src/endgame.cpp | 12 +- source/games/duke/src/2d_d.cpp | 169 +++++++++++++++++------------ 3 files changed, 104 insertions(+), 79 deletions(-) diff --git a/source/core/movie/movieplayer.cpp b/source/core/movie/movieplayer.cpp index e65a04d63..73fee3b99 100644 --- a/source/core/movie/movieplayer.cpp +++ b/source/core/movie/movieplayer.cpp @@ -596,10 +596,8 @@ public: int frame = clock / nFrameNs; twod->ClearScreen(); - Printf("clock = %llu, frame = %d\n", clock, frame); if (frame > nFrame) { - Printf("Updating\n"); Smacker_GetPalette(hSMK, palette); Smacker_GetFrame(hSMK, pFrame.Data()); animtex.SetFrame(palette, pFrame.Data()); diff --git a/source/games/blood/src/endgame.cpp b/source/games/blood/src/endgame.cpp index 497a7f55d..a50b2e298 100644 --- a/source/games/blood/src/endgame.cpp +++ b/source/games/blood/src/endgame.cpp @@ -91,7 +91,7 @@ static void DrawCaption(const char* text) } -class DBloodSummaryScreen : public DScreenJob +class DBloodSummaryScreen : public DSkippableScreenJob { void DrawKills(void) { @@ -139,7 +139,7 @@ class DBloodSummaryScreen : public DScreenJob } - int Frame(uint64_t clock, bool skiprequest) + void Draw(double) override { drawTextScreenBackground(); if (gGameOptions.nGameType == 0) @@ -160,7 +160,7 @@ class DBloodSummaryScreen : public DScreenJob DrawCaption(GStrings("TXTB_FRAGSTATS")); DrawKills(); } - int myclock = int(clock * 120 / 1'000'000'000); + int myclock = ticks * 120 / GameTicRate; if ((myclock & 32)) { auto text = GStrings("PRESSKEY"); @@ -168,7 +168,6 @@ class DBloodSummaryScreen : public DScreenJob if (!SmallFont2->CanPrint(text)) font = 0; viewDrawText(font, text, 160, 134, -128, 0, 1, font == 3); } - return skiprequest ? -1 : 1; } }; @@ -274,7 +273,7 @@ CSecretMgr gSecretMgr; CKillMgr gKillMgr; class DBloodLoadScreen : public DScreenJob -{ +{ const char* pzLoadingScreenText1; MapRecord* rec; @@ -285,7 +284,7 @@ public: else pzLoadingScreenText1 = GStrings(FStringf("TXTB_NETGT%d", gGameOptions.nGameType)); } - int Frame(uint64_t clock, bool skiprequest) + void Draw(double) override { twod->ClearScreen(); drawTextScreenBackground(); @@ -297,7 +296,6 @@ public: if (!SmallFont2->CanPrint(text)) font = 0; viewDrawText(font, GStrings("TXTB_PLSWAIT"), 160, 134, -128, 0, 1, font == 3); - return 0; } }; diff --git a/source/games/duke/src/2d_d.cpp b/source/games/duke/src/2d_d.cpp index 4b50d99bd..8b32a1cb0 100644 --- a/source/games/duke/src/2d_d.cpp +++ b/source/games/duke/src/2d_d.cpp @@ -165,20 +165,23 @@ static void MiniText(double x, double y, const char* t, int shade, int align = - // //--------------------------------------------------------------------------- -class DDRealmsScreen : public DScreenJob +class DDRealmsScreen : public DSkippableScreenJob { public: - DDRealmsScreen() : DScreenJob(fadein | fadeout) {} + DDRealmsScreen() : DSkippableScreenJob(fadein | fadeout) {} - int Frame(uint64_t clock, bool skiprequest) override + void OnTick() override + { + if (ticks >= 7 * GameTicRate) state = finished; + } + + void Draw(double smoothratio) override { - const uint64_t duration = 7'000'000'000; const auto tex = tileGetTexture(DREALMS, true); int translation = tex->GetTexture()->GetImage()->UseGamePalette() ? TRANSLATION(Translation_BasePalettes, DREALMSPAL) : 0; twod->ClearScreen(); DrawTexture(twod, tex, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_TranslationIndex, translation, DTA_LegacyRenderStyle, STYLE_Normal, TAG_DONE); - return skiprequest ? -1 : clock < duration ? 1 : 0; } }; @@ -188,27 +191,18 @@ public: // //--------------------------------------------------------------------------- -class DTitleScreen : public DScreenJob +class DTitleScreen : public DSkippableScreenJob { int soundanm = 0; public: - DTitleScreen() : DScreenJob(fadein | fadeout) + DTitleScreen() : DSkippableScreenJob(fadein | fadeout) { } - int Frame(uint64_t nsclock, bool skiprequest) override + void OnTick() override { - twod->ClearScreen(); - int clock = nsclock * 120 / 1'000'000'000; - - twod->ClearScreen(); - - // Only translate if the image depends on the global palette. - auto tex = tileGetTexture(BETASCREEN, true); - int translation = tex->GetTexture()->GetImage()->UseGamePalette() ? TRANSLATION(Translation_BasePalettes, TITLEPAL) : 0; - DrawTexture(twod, tex, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_TranslationIndex, translation, DTA_LegacyRenderStyle, STYLE_Normal, TAG_DONE); - + int clock = ticks * 120 / GameTicRate; if (soundanm == 0 && clock >= 120 && clock < 120 + 60) { soundanm = 1; @@ -230,6 +224,25 @@ public: if (isPlutoPak()) S_PlaySound(PIPEBOMB_EXPLODE, CHAN_AUTO, CHANF_UI); } + if (clock > (860 + 120)) + { + state = finished; + } + } + + void Draw(double smoothratio) override + { + twod->ClearScreen(); + int clock = (ticks + smoothratio) * 120 / GameTicRate; + + twod->ClearScreen(); + + // Only translate if the image depends on the global palette. + auto tex = tileGetTexture(BETASCREEN, true); + int translation = tex->GetTexture()->GetImage()->UseGamePalette() ? TRANSLATION(Translation_BasePalettes, TITLEPAL) : 0; + DrawTexture(twod, tex, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_TranslationIndex, translation, DTA_LegacyRenderStyle, STYLE_Normal, TAG_DONE); + + double scale = clamp(clock - 120, 0, 60) / 64.; if (scale > 0.) { @@ -262,13 +275,6 @@ public: DTA_CenterOffsetRel, true, DTA_TranslationIndex, translation, DTA_ScaleX, scale, DTA_ScaleY, scale, TAG_DONE); } } - - if (clock > (860 + 120)) - { - return 0; - } - - return skiprequest ? -1 : 1; } }; @@ -310,70 +316,68 @@ void Logo_d(const CompletionFunc &completion) // //--------------------------------------------------------------------------- -class DEpisode1End1 : public DScreenJob +class DEpisode1End1 : public DSkippableScreenJob { int bonuscnt = 0; + int bossani = -1; + int breatheani = -1; + bool breathebg = false; + + static inline const int breathe[] = + { + 0, 30,VICTORY1 + 1,176,59, + 30, 60,VICTORY1 + 2,176,59, + 60, 90,VICTORY1 + 1,176,59, + 90, 120,0 ,176,59 + }; + + static inline const int bossmove[] = + { + 0, 120,VICTORY1 + 3,86,59, + 220, 260,VICTORY1 + 4,86,59, + 260, 290,VICTORY1 + 5,86,59, + 290, 320,VICTORY1 + 6,86,59, + 320, 350,VICTORY1 + 7,86,59, + 350, 380,VICTORY1 + 8,86,59, + 350, 380,VICTORY1 + 8,86,59, + }; public: - DEpisode1End1() : DScreenJob(fadein | fadeout) {} + DEpisode1End1() : DSkippableScreenJob(fadein | fadeout) {} - int Frame(uint64_t nsclock, bool skiprequest) override + void OnTick() { - static const int breathe[] = - { - 0, 30,VICTORY1 + 1,176,59, - 30, 60,VICTORY1 + 2,176,59, - 60, 90,VICTORY1 + 1,176,59, - 90, 120,0 ,176,59 - }; - - static const int bossmove[] = - { - 0, 120,VICTORY1 + 3,86,59, - 220, 260,VICTORY1 + 4,86,59, - 260, 290,VICTORY1 + 5,86,59, - 290, 320,VICTORY1 + 6,86,59, - 320, 350,VICTORY1 + 7,86,59, - 350, 380,VICTORY1 + 8,86,59, - 350, 380,VICTORY1 + 8,86,59, - }; - - auto translation = TRANSLATION(Translation_BasePalettes, ENDINGPAL); - - int currentclock = nsclock * 120 / 1'000'000'000; - - uint64_t span = nsclock / 1'000'000; - - twod->ClearScreen(); - DrawTexture(twod, tileGetTexture(VICTORY1, true), 0, 50, DTA_FullscreenScale, FSMode_Fit320x200, - DTA_TranslationIndex, translation, DTA_LegacyRenderStyle, STYLE_Normal, DTA_TopLeft, true, TAG_DONE); + int currentclock = ticks * 120 / GameTicRate; + bossani = -1; + breathebg = false; + breatheani = -1; // boss if (currentclock > 390 && currentclock < 780) + { for (int t = 0; t < 35; t += 5) if (bossmove[t + 2] && (currentclock % 390) > bossmove[t] && (currentclock % 390) <= bossmove[t + 1]) { - if (t == 10 && bonuscnt == 1) - { + if (t == 10 && bonuscnt == 1) + { S_PlaySound(SHOTGUN_FIRE, CHAN_AUTO, CHANF_UI); S_PlaySound(SQUISHED, CHAN_AUTO, CHANF_UI); - bonuscnt++; + bonuscnt++; } - DrawTexture(twod, tileGetTexture(bossmove[t + 2], true), bossmove[t + 3], bossmove[t + 4], DTA_FullscreenScale, FSMode_Fit320x200, - DTA_TranslationIndex, translation, DTA_TopLeft, true, TAG_DONE); + bossani = t; } + } // Breathe if (currentclock < 450 || currentclock >= 750) { if (currentclock >= 750) { - DrawTexture(twod, tileGetTexture(VICTORY1 + 8, true), 86, 59, DTA_FullscreenScale, FSMode_Fit320x200, - DTA_TranslationIndex, translation, DTA_TopLeft, true, TAG_DONE); - if (currentclock >= 750 && bonuscnt == 2) - { + breathebg = true; + if (currentclock >= 750 && bonuscnt == 2) + { S_PlaySound(DUKETALKTOBOSS, CHAN_AUTO, CHANF_UI); - bonuscnt++; + bonuscnt++; } } for (int t = 0; t < 20; t += 5) @@ -384,12 +388,37 @@ public: S_PlaySound(BOSSTALKTODUKE, CHAN_AUTO, CHANF_UI); bonuscnt++; } - DrawTexture(twod, tileGetTexture(breathe[t + 2], true), breathe[t + 3], breathe[t + 4], DTA_FullscreenScale, FSMode_Fit320x200, - DTA_TranslationIndex, translation, DTA_TopLeft, true, TAG_DONE); + breatheani = t; } } - // Only end after having faded out. - return skiprequest ? -1 : 1; + + } + + void Draw(double) override + { + auto translation = TRANSLATION(Translation_BasePalettes, ENDINGPAL); + + twod->ClearScreen(); + DrawTexture(twod, tileGetTexture(VICTORY1, true), 0, 50, DTA_FullscreenScale, FSMode_Fit320x200, + DTA_TranslationIndex, translation, DTA_LegacyRenderStyle, STYLE_Normal, DTA_TopLeft, true, TAG_DONE); + + if (bossani != -1) + { + DrawTexture(twod, tileGetTexture(bossmove[bossani + 2], true), bossmove[bossani + 3], bossmove[bossani + 4], DTA_FullscreenScale, FSMode_Fit320x200, + DTA_TranslationIndex, translation, DTA_TopLeft, true, TAG_DONE); + } + + if (breathebg) + { + DrawTexture(twod, tileGetTexture(VICTORY1 + 8, true), 86, 59, DTA_FullscreenScale, FSMode_Fit320x200, + DTA_TranslationIndex, translation, DTA_TopLeft, true, TAG_DONE); + } + + if (breatheani != -1) + { + DrawTexture(twod, tileGetTexture(breathe[breatheani + 2], true), breathe[breatheani + 3], breathe[breatheani + 4], DTA_FullscreenScale, FSMode_Fit320x200, + DTA_TranslationIndex, translation, DTA_TopLeft, true, TAG_DONE); + } } }; From a78af92959a6b1261c76e5e0ee71984b83b3cf86 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 16 Apr 2021 00:25:22 +0200 Subject: [PATCH 09/34] - migrated the Duke end of episode animations. --- source/games/duke/src/2d_d.cpp | 36 ++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/source/games/duke/src/2d_d.cpp b/source/games/duke/src/2d_d.cpp index 8b32a1cb0..06fcc8c12 100644 --- a/source/games/duke/src/2d_d.cpp +++ b/source/games/duke/src/2d_d.cpp @@ -437,7 +437,6 @@ public: FGameTexture* getTexture() { - // Here we must provide a real texture, even if invalid, so that the sounds play. auto texid = TexMan.CheckForTexture("radlogo.anm", ETextureType::Any, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ForceLookup); if (texid.isValid()) return TexMan.GetGameTexture(texid); else return TexMan.GameByIndex(0); @@ -448,7 +447,17 @@ public: { } - int Frame(uint64_t clock, bool skiprequest) + bool OnEvent(event_t* evt) override + { + if (evt->type == EV_GUI_KeyDown) + { + state = skipped; + FX_StopAllSounds(); + } + return true; + } + + void OnTick() override { switch (sound) { @@ -493,23 +502,21 @@ public: if (!S_CheckSoundPlaying(ENDSEQVOL3SND9)) { sound++; - waittime = clock + (SoundEnabled()? 1'000'000'000 : 5'000'000'000); // if sound is off this wouldn't wait without a longer delay here. + waittime = ticks + GameTicRate * (SoundEnabled() ? 1 : 5); // if sound is off this wouldn't wait without a longer delay here. } break; case 6: if (isPlutoPak()) { - if (clock > waittime) skiprequest = true; + if (ticks > waittime) state = finished; } break; default: break; } - int ret = DImageScreen::Frame(clock, skiprequest); - if (ret != 1) FX_StopAllSounds(); - return ret; + if (state != running) FX_StopAllSounds(); } }; @@ -519,12 +526,12 @@ public: // //--------------------------------------------------------------------------- -class DEpisode4Text : public DScreenJob +class DEpisode4Text : public DSkippableScreenJob { public: - DEpisode4Text() : DScreenJob(fadein | fadeout) {} + DEpisode4Text() : DSkippableScreenJob(fadein | fadeout) {} - int Frame(uint64_t clock, bool skiprequest) + void Draw(double) { twod->ClearScreen(); BigText(160, 60, GStrings("Thanks to all our")); @@ -532,7 +539,6 @@ public: BigText(160, 60 + 16 + 16, GStrings("us big heads.")); BigText(160, 70 + 16 + 16 + 16, GStrings("Look for a Duke Nukem 3D")); BigText(160, 70 + 16 + 16 + 16 + 16, GStrings("sequel soon.")); - return skiprequest ? -1 : 1; } }; @@ -551,7 +557,7 @@ public: { } - int Frame(uint64_t clock, bool skiprequest) + void OnTick() override { switch (sound) { @@ -567,9 +573,6 @@ public: default: break; } - int ret = DImageScreen::Frame(clock, skiprequest); - if (ret != 1) FX_StopAllSounds(); - return ret; } }; @@ -1120,14 +1123,13 @@ class DDukeLoadScreen : public DScreenJob public: DDukeLoadScreen(MapRecord *maprec) : DScreenJob(0), rec(maprec) {} - int Frame(uint64_t clock, bool skiprequest) + void Draw(double) override { twod->ClearScreen(); DrawTexture(twod, tileGetTexture(LOADSCREEN), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_LegacyRenderStyle, STYLE_Normal, TAG_DONE); BigText(160, 90, (rec->flags & MI_USERMAP)? GStrings("TXT_LOADUM") : GStrings("TXT_LOADING")); BigText(160, 114, rec->DisplayName()); - return 0; } }; From 7895d67b18196a5845dd13f456fa8f7b726fb855 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 16 Apr 2021 00:43:45 +0200 Subject: [PATCH 10/34] - ported the Duke intermission screen. This also got its timing code thoroughly cleaned up. --- source/games/duke/src/2d_d.cpp | 199 +++++++++++++++++++-------------- 1 file changed, 115 insertions(+), 84 deletions(-) diff --git a/source/games/duke/src/2d_d.cpp b/source/games/duke/src/2d_d.cpp index 06fcc8c12..ac099e557 100644 --- a/source/games/duke/src/2d_d.cpp +++ b/source/games/duke/src/2d_d.cpp @@ -724,22 +724,25 @@ void doorders(const CompletionFunc& completion) // //--------------------------------------------------------------------------- -class DDukeMultiplayerBonusScreen : public DScreenJob +class DDukeMultiplayerBonusScreen : public DSkippableScreenJob { int playerswhenstarted; public: - DDukeMultiplayerBonusScreen(int pws) : DScreenJob(fadein|fadeout) + DDukeMultiplayerBonusScreen(int pws) : DSkippableScreenJob(fadein|fadeout) { playerswhenstarted = pws; } - int Frame(uint64_t clock, bool skiprequest) + void OnTick() override { - if (clock == 0) S_PlayBonusMusic(); + if (ticks == 1) S_PlayBonusMusic(); + } + void Draw(double smoothratio) override + { char tempbuf[32]; - int currentclock = int(clock * 120 / 1'000'000'000); + int currentclock = int((ticks + smoothratio) * 120 / GameTicRate); twod->ClearScreen(); DrawTexture(twod, tileGetTexture(MENUSCREEN), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_Color, 0xff808080, DTA_LegacyRenderStyle, STYLE_Normal, TAG_DONE); DrawTexture(twod, tileGetTexture(INGAMEDUKETHREEDEE, true), 160, 34, DTA_FullscreenScale, FSMode_Fit320x200, DTA_CenterOffsetRel, true, TAG_DONE); @@ -814,7 +817,6 @@ public: } MiniText(45, 96 + (8 * 7), GStrings("Deaths"), 0, -1, 8); - return skiprequest ? -1 : 1; } }; @@ -830,6 +832,22 @@ class DDukeLevelSummaryScreen : public DScreenJob int gfx_offset; int bonuscnt = 0; int speech = -1; + int displaystate = 0; + int dukeAnimStart; + + enum + { + printTimeText = 1, + printTimeVal = 2, + printKillsText = 4, + printKillsVal = 8, + printSecretsText = 16, + printSecretsVal = 32, + printStatsAll = 63, + dukeAnim = 64, + dukeWait = 128, + + }; void SetTotalClock(int tc) { @@ -849,7 +867,78 @@ public: mysnprintf(tempbuf, 32, "%02d:%02d", (time / (26 * 60)) % 60, (time / 26) % 60); } - void PrintTime(int currentclock) + bool OnEvent(event_t* ev) override + { + if (ev->type == EV_KeyDown) + { + if ((displaystate & printStatsAll) != printStatsAll) + { + S_PlaySound(PIPEBOMB_EXPLODE, CHAN_AUTO, CHANF_UI); + displaystate = printStatsAll; + } + else if (!(displaystate & dukeAnim)) + { + displaystate |= dukeAnim; + dukeAnimStart = ticks; + S_PlaySound(SHOTGUN_COCK, CHAN_AUTO, CHANF_UI); + static const uint16_t speeches[] = { BONUS_SPEECH1, BONUS_SPEECH2, BONUS_SPEECH3, BONUS_SPEECH4 }; + speech = speeches[(rand() & 3)]; + S_PlaySound(speech, CHAN_AUTO, CHANF_UI, 1); + } + return true; + } + return false; + } + + void OnTick() override + { + if (ticks == 1) S_PlayBonusMusic(); + if ((displaystate & printStatsAll) != printStatsAll) + { + if (ticks == 15 * 3) + { + displaystate |= printTimeText; + } + else if (ticks == 15 * 4) + { + displaystate |= printTimeVal; + S_PlaySound(PIPEBOMB_EXPLODE, CHAN_AUTO, CHANF_UI); + } + else if (ticks == 15 * 6) + { + displaystate |= printKillsText; + S_PlaySound(FLY_BY, CHAN_AUTO, CHANF_UI); + } + else if (ticks == 15 * 7) + { + displaystate |= printKillsVal; + S_PlaySound(PIPEBOMB_EXPLODE, CHAN_AUTO, CHANF_UI); + } + else if (ticks == 15 * 9) + { + displaystate |= printSecretsText; + } + else if (ticks == 15 * 10) + { + displaystate |= printSecretsVal; + S_PlaySound(PIPEBOMB_EXPLODE, CHAN_AUTO, CHANF_UI); + } + } + if (displaystate & dukeAnim) + { + if (ticks >= dukeAnimStart + 60) + { + displaystate ^= dukeAnim | dukeWait; + } + } + if (displaystate & dukeWait) + { + if (speech <= 0 || !soundEngine->GetSoundPlayingInfo(SOURCE_None, nullptr, speech)) + state = finished; + } + } + + void PrintTime() { char tempbuf[32]; GameText(10, 59 + 9, GStrings("TXT_YourTime"), 0); @@ -857,16 +946,8 @@ public: if (!isNamWW2GI()) GameText(10, 79 + 9, GStrings("TXT_3DRTIME"), 0); - if (bonuscnt == 0) - bonuscnt++; - - if (currentclock > (60 * 4)) + if (displaystate & printTimeVal) { - if (bonuscnt == 1) - { - bonuscnt++; - S_PlaySound(PIPEBOMB_EXPLODE, CHAN_AUTO, CHANF_UI); - } FormatTime(ps[myconnectindex].player_par, tempbuf); GameText((320 >> 2) + 71, 59 + 9, tempbuf, 0); @@ -881,25 +962,14 @@ public: } } - void PrintKills(int currentclock) + void PrintKills() { char tempbuf[32]; GameText(10, 94 + 9, GStrings("TXT_EnemiesKilled"), 0); GameText(10, 104 + 9, GStrings("TXT_EnemiesLeft"), 0); - if (bonuscnt == 2) + if (displaystate & printKillsVal) { - bonuscnt++; - S_PlaySound(FLY_BY, CHAN_AUTO, CHANF_UI); - } - - if (currentclock > (60 * 7)) - { - if (bonuscnt == 3) - { - bonuscnt++; - S_PlaySound(PIPEBOMB_EXPLODE, CHAN_AUTO, CHANF_UI); - } mysnprintf(tempbuf, 32, "%-3d", ps[myconnectindex].actors_killed); GameText((320 >> 2) + 70, 94 + 9, tempbuf, 0); @@ -918,20 +988,14 @@ public: } } - void PrintSecrets(int currentclock) + void PrintSecrets() { char tempbuf[32]; GameText(10, 119 + 9, GStrings("TXT_SECFND"), 0); GameText(10, 129 + 9, GStrings("TXT_SECMISS"), 0); - if (bonuscnt == 4) bonuscnt++; - if (currentclock > (60 * 10)) + if (displaystate & printSecretsVal) { - if (bonuscnt == 5) - { - bonuscnt++; - S_PlaySound(PIPEBOMB_EXPLODE, CHAN_AUTO, CHANF_UI); - } mysnprintf(tempbuf, 32, "%-3d", ps[myconnectindex].secret_rooms); GameText((320 >> 2) + 70, 119 + 9, tempbuf, 0); if (ps[myconnectindex].secret_rooms > 0) @@ -941,41 +1005,31 @@ public: } } - int Frame(uint64_t clock, bool skiprequest) + void Draw(double) override { - if (clock == 0) S_PlayBonusMusic(); twod->ClearScreen(); - int currentclock = int(clock * 120 / 1'000'000'000); DrawTexture(twod, tileGetTexture(gfx_offset, true), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_LegacyRenderStyle, STYLE_Normal, TAG_DONE); - GameText(160, 190, GStrings("PRESSKEY"), 8 - int(sin(currentclock / 10.) * 8), 0); + GameText(160, 190, GStrings("PRESSKEY"), 8 - int(sin(ticks * 12 / GameTicRate) * 8), 0); - if (currentclock > (60 * 3)) + if (displaystate & printTimeText) { - PrintTime(currentclock); + PrintTime(); } - if (currentclock > (60 * 6)) + if (displaystate & printKillsText) { - PrintKills(currentclock); + PrintKills(); } - if (currentclock > (60 * 9)) + if (displaystate & printSecretsText) { - PrintSecrets(currentclock); + PrintSecrets(); } - if (currentclock >= (1000000000L) && currentclock < (1000000320L)) + if (displaystate & dukeAnim) { - switch ((currentclock >> 4) % 15) + switch (((ticks - dukeAnimStart) >> 2) % 15) { case 0: - if (bonuscnt == 6) - { - bonuscnt++; - S_PlaySound(SHOTGUN_COCK, CHAN_AUTO, CHANF_UI); - static const uint16_t speeches[] = { BONUS_SPEECH1, BONUS_SPEECH2, BONUS_SPEECH3, BONUS_SPEECH4}; - speech = speeches[(rand() & 3)]; - S_PlaySound(speech, CHAN_AUTO, CHANF_UI, 1); - } case 1: case 4: case 5: @@ -987,14 +1041,9 @@ public: break; } } - else if (currentclock > (10240 + 120L)) + else if (!(displaystate & dukeWait)) { - if (speech > 0 && !skiprequest && soundEngine->GetSoundPlayingInfo(SOURCE_None, nullptr, speech)) return 1; - return 0; - } - else - { - switch((currentclock >> 5) & 3) + switch((ticks >> 3) & 3) { case 1: case 3: @@ -1008,26 +1057,6 @@ public: if (lastmapname) BigText(160, 20 - 6, lastmapname); BigText(160, 36 - 6, GStrings("Completed")); - - if (currentclock > 10240 && currentclock < 10240 + 10240) - SetTotalClock(1024); - - if (skiprequest && currentclock > (60 * 2)) - { - skiprequest = false; - if (currentclock < (60 * 13)) - { - SetTotalClock(60 * 13); - } - else if (currentclock < (1000000000)) - { - // force-set bonuscnt here so that it won't desync with the rest of the logic and Duke's voice can be heard. - if (bonuscnt < 6) bonuscnt = 6; - SetTotalClock(1000000000); - } - } - - return 1; } }; @@ -1061,7 +1090,9 @@ void dobonus_d(int bonusonly, const CompletionFunc& completion) jobs[job++] = { Create() }; } if (job) + { RunScreenJob(jobs, job, completion); + } else if (completion) completion(false); } From f4b089b7766b87eb700d9515b1604b3ec2296f09 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 16 Apr 2021 17:37:08 +0200 Subject: [PATCH 11/34] - fixed bad sound checkin Duke's intermission. --- source/games/duke/src/2d_d.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/source/games/duke/src/2d_d.cpp b/source/games/duke/src/2d_d.cpp index ac099e557..71ea4825d 100644 --- a/source/games/duke/src/2d_d.cpp +++ b/source/games/duke/src/2d_d.cpp @@ -830,7 +830,6 @@ class DDukeLevelSummaryScreen : public DScreenJob { const char* lastmapname; int gfx_offset; - int bonuscnt = 0; int speech = -1; int displaystate = 0; int dukeAnimStart; @@ -849,11 +848,6 @@ class DDukeLevelSummaryScreen : public DScreenJob }; - void SetTotalClock(int tc) - { - SetClock(tc * (uint64_t)1'000'000'000 / 120); - } - public: DDukeLevelSummaryScreen() : DScreenJob(fadein | fadeout) { @@ -933,7 +927,7 @@ public: } if (displaystate & dukeWait) { - if (speech <= 0 || !soundEngine->GetSoundPlayingInfo(SOURCE_None, nullptr, speech)) + if (speech <= 0 || !S_CheckSoundPlaying(speech)) state = finished; } } From 9dff494e6c6867a51b614182b505f75366feed67 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 16 Apr 2021 17:38:05 +0200 Subject: [PATCH 12/34] - handle all of RR's screens. --- source/games/duke/src/2d_r.cpp | 208 ++++++++++++++++++--------------- 1 file changed, 117 insertions(+), 91 deletions(-) diff --git a/source/games/duke/src/2d_r.cpp b/source/games/duke/src/2d_r.cpp index 9d01601cb..2dd27f388 100644 --- a/source/games/duke/src/2d_r.cpp +++ b/source/games/duke/src/2d_r.cpp @@ -265,9 +265,13 @@ public: playerswhenstarted = pws; } - int Frame(uint64_t clock, bool skiprequest) + void OnTick() override + { + if (ticks == 1) S_PlayBonusMusic(); + } + + void Draw(double) override { - if (clock == 0) S_PlayBonusMusic(); char tempbuf[32]; twod->ClearScreen(); DrawTexture(twod, tileGetTexture(MENUSCREEN), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_Color, 0xff808080, DTA_LegacyRenderStyle, STYLE_Normal, TAG_DONE); @@ -343,7 +347,6 @@ public: } MiniText(45, 96 + (8 * 7), GStrings("Deaths"), 0); - return skiprequest ? -1 : 1; } }; @@ -357,13 +360,23 @@ class DRRLevelSummaryScreen : public DScreenJob { const char* lastmapname; int gfx_offset; - int bonuscnt = 0; + int displaystate = 0; int speech = -1; + int exitSoundStart; - void SetTotalClock(int tc) + enum { - SetClock(tc * (uint64_t)1'000'000'000 / 120); - } + printTimeText = 1, + printTimeVal = 2, + printKillsText = 4, + printKillsVal = 8, + printSecretsText = 16, + printSecretsVal = 32, + printStatsAll = 63, + exitSound = 64, + exitWait = 128, + + }; public: DRRLevelSummaryScreen(bool dofadeout = true) : DScreenJob(dofadeout? (fadein | fadeout) : fadein) @@ -384,23 +397,84 @@ public: mysnprintf(tempbuf, 32, "%02d:%02d", (time / (26 * 60)) % 60, (time / 26) % 60); } - void PrintTime(int currentclock) + bool OnEvent(event_t* ev) override + { + if (ev->type == EV_KeyDown) + { + if ((displaystate & printStatsAll) != printStatsAll) + { + S_PlaySound(404, CHAN_AUTO, CHANF_UI); + displaystate = printStatsAll; + } + else if (!(displaystate & exitSound)) + { + displaystate |= exitSound; + exitSoundStart = ticks; + S_PlaySound(425, CHAN_AUTO, CHANF_UI); + speech = BONUS_SPEECH1 + (rand() & 3); + S_PlaySound(speech, CHAN_AUTO, CHANF_UI); + } + return true; + } + return false; + } + + void OnTick() override + { + if (ticks == 1) S_PlayBonusMusic(); + if ((displaystate & printStatsAll) != printStatsAll) + { + if (ticks == 15 * 3) + { + displaystate |= printTimeText; + } + else if (ticks == 15 * 4) + { + displaystate |= printTimeVal; + S_PlaySound(404, CHAN_AUTO, CHANF_UI); + } + else if (ticks == 15 * 6) + { + displaystate |= printKillsText; + } + else if (ticks == 15 * 7) + { + displaystate |= printKillsVal; + S_PlaySound(404, CHAN_AUTO, CHANF_UI); + } + else if (ticks == 15 * 9) + { + displaystate |= printSecretsText; + } + else if (ticks == 15 * 10) + { + displaystate |= printSecretsVal; + S_PlaySound(404, CHAN_AUTO, CHANF_UI); + } + } + if (displaystate & exitSound) + { + if (ticks >= exitSoundStart + 60) + { + displaystate ^= exitSound | exitWait; + } + } + if (displaystate & exitWait) + { + if (speech <= 0 || !S_CheckSoundPlaying(speech)) + state = finished; + } + } + + void PrintTime() { char tempbuf[32]; BigText(30, 48, GStrings("TXT_YerTime"), -1); BigText(30, 64, GStrings("TXT_ParTime"), -1); BigText(30, 80, GStrings("TXT_XTRTIME"), -1); - if (bonuscnt == 0) - bonuscnt++; - - if (currentclock > (60 * 4)) + if (displaystate & printTimeVal) { - if (bonuscnt == 1) - { - bonuscnt++; - S_PlaySound(404, CHAN_AUTO, CHANF_UI); - } FormatTime(ps[myconnectindex].player_par, tempbuf); BigText(191, 48, tempbuf, -1); @@ -415,22 +489,14 @@ public: } } - void PrintKills(int currentclock) + void PrintKills() { char tempbuf[32]; BigText(30, 112, GStrings("TXT_VarmintsKilled"), -1); BigText(30, 128, GStrings("TXT_VarmintsLeft"), -1); - if (bonuscnt == 2) - bonuscnt++; - - if (currentclock > (60 * 7)) + if (displaystate & printKillsVal) { - if (bonuscnt == 3) - { - bonuscnt++; - S_PlaySound(442, CHAN_AUTO, CHANF_UI); - } mysnprintf(tempbuf, 32, "%-3d", ps[myconnectindex].actors_killed); BigText(231, 112, tempbuf, -1); if (ud.player_skill > 3) @@ -448,20 +514,14 @@ public: } } - void PrintSecrets(int currentclock) + void PrintSecrets() { char tempbuf[32]; BigText(30, 144, GStrings("TXT_SECFND"), -1); BigText(30, 160, GStrings("TXT_SECMISS"), -1); - if (bonuscnt == 4) bonuscnt++; - if (currentclock > (60 * 10)) + if (displaystate & printSecretsVal) { - if (bonuscnt == 5) - { - bonuscnt++; - S_PlaySound(404, CHAN_AUTO, CHANF_UI); - } mysnprintf(tempbuf, 32, "%-3d", ps[myconnectindex].secret_rooms); BigText(231, 144, tempbuf, -1); if (ps[myconnectindex].secret_rooms > 0) @@ -471,64 +531,26 @@ public: } } - int Frame(uint64_t clock, bool skiprequest) + void Draw(double) override { - if (clock == 0) S_PlayBonusMusic(); twod->ClearScreen(); - int currentclock = int(clock * 120 / 1'000'000'000); DrawTexture(twod, tileGetTexture(gfx_offset, true), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_LegacyRenderStyle, STYLE_Normal, TAG_DONE); if (lastmapname) BigText(80, 16, lastmapname, -1); BigText(15, 192, GStrings("PRESSKEY"), -1); - if (currentclock > (60 * 3)) + if (displaystate & printTimeText) { - PrintTime(currentclock); + PrintTime(); } - if (currentclock > (60 * 6)) + if (displaystate & printKillsText) { - PrintKills(currentclock); + PrintKills(); } - if (currentclock > (60 * 9)) + if (displaystate & printSecretsText) { - PrintSecrets(currentclock); + PrintSecrets(); } - - if (currentclock > (1000000000L) && currentclock < (1000000320L)) - { - int val = (currentclock >> 4) % 15; - if (val == 0) - { - if (bonuscnt == 6) - { - bonuscnt++; - S_PlaySound(425, CHAN_AUTO, CHANF_UI); - speech = BONUS_SPEECH1 + (rand() & 3); - S_PlaySound(speech, CHAN_AUTO, CHANF_UI); - } - } - } - else if (currentclock > (10240 + 120L)) - { - if (speech > 0 && !skiprequest && soundEngine->GetSoundPlayingInfo(SOURCE_None, nullptr, speech)) return 1; - return 0; - } - - if (currentclock > 10240 && currentclock < 10240 + 10240) - SetTotalClock(1024); - - if (skiprequest && currentclock > (60 * 2)) - { - skiprequest = false; - if (currentclock < (60 * 13)) - { - SetTotalClock(60 * 13); - } - else if (currentclock < (1000000000)) - SetTotalClock(1000000000); - } - - return 1; } }; @@ -539,20 +561,25 @@ class DRRRAEndOfGame : public DScreenJob public: DRRRAEndOfGame() : DScreenJob(fadein|fadeout) { - S_PlaySound(35, CHAN_AUTO, CHANF_UI); } - int Frame(uint64_t clock, bool skiprequest) + bool OnEvent(event_t* ev) override { - int currentclock = int(clock * 120 / 1'000'000'000); - auto tex = tileGetTexture(ENDGAME + ((currentclock >> 4) & 1)); - DrawTexture(twod, tex, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, TAG_DONE); - if (!S_CheckSoundPlaying(-1, 35) && currentclock > 15*120) return 0; // make sure it stays, even if sound is off. - if (skiprequest) + if (ev->type == EV_GUI_KeyDown) { S_StopSound(35); - return -1; + state = skipped; } - return 1; + return true; + } + void OnTick() override + { + if (ticks == 1) S_PlaySound(35, CHAN_AUTO, CHANF_UI); + if (!S_CheckSoundPlaying(-1, 35) && ticks > 15 * GameTicRate) state = finished; // make sure it stays, even if sound is off. + } + void Draw(double) override + { + auto tex = tileGetTexture(ENDGAME + ((ticks >> 2) & 1)); + DrawTexture(twod, tex, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, TAG_DONE); } }; @@ -616,14 +643,13 @@ class DRRLoadScreen : public DScreenJob public: DRRLoadScreen(MapRecord* maprec) : DScreenJob(0), rec(maprec) {} - int Frame(uint64_t clock, bool skiprequest) + void Draw(double) override { DrawTexture(twod, tileGetTexture(LOADSCREEN), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_LegacyRenderStyle, STYLE_Normal, TAG_DONE); int y = isRRRA()? 140 : 90; BigText(160, y, (rec->flags & MI_USERMAP) ? GStrings("TXT_ENTRUM") : GStrings("TXT_ENTERIN"), 0); BigText(160, y+24, rec->DisplayName(), 0); - return 0; } }; From 4950b556c91364b83446f408cc847f8ca3cb34f4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 16 Apr 2021 18:43:59 +0200 Subject: [PATCH 13/34] - handled SW's screens. --- source/core/screenjob.cpp | 6 +- source/core/screenjob.h | 1 + source/games/duke/src/2d_d.cpp | 9 +-- source/games/duke/src/2d_r.cpp | 22 +++---- source/games/sw/src/2d.cpp | 108 +++++++++++++++++++-------------- 5 files changed, 78 insertions(+), 68 deletions(-) diff --git a/source/core/screenjob.cpp b/source/core/screenjob.cpp index cbcb39a27..6f7b53436 100644 --- a/source/core/screenjob.cpp +++ b/source/core/screenjob.cpp @@ -59,7 +59,11 @@ IMPLEMENT_CLASS(DImageScreen, true, false) bool DSkippableScreenJob::OnEvent(event_t* evt) { - if (evt->type == EV_GUI_KeyDown) state = skipped; + if (evt->type == EV_KeyDown) + { + state = skipped; + Skipped(); + } return true; } diff --git a/source/core/screenjob.h b/source/core/screenjob.h index cdf72014a..82e053781 100644 --- a/source/core/screenjob.h +++ b/source/core/screenjob.h @@ -85,6 +85,7 @@ protected: {} bool OnEvent(event_t* evt) override; + virtual void Skipped() {} }; //--------------------------------------------------------------------------- diff --git a/source/games/duke/src/2d_d.cpp b/source/games/duke/src/2d_d.cpp index 71ea4825d..b41789177 100644 --- a/source/games/duke/src/2d_d.cpp +++ b/source/games/duke/src/2d_d.cpp @@ -447,14 +447,9 @@ public: { } - bool OnEvent(event_t* evt) override + void Skipped() override { - if (evt->type == EV_GUI_KeyDown) - { - state = skipped; - FX_StopAllSounds(); - } - return true; + FX_StopAllSounds(); } void OnTick() override diff --git a/source/games/duke/src/2d_r.cpp b/source/games/duke/src/2d_r.cpp index 2dd27f388..f7eecc088 100644 --- a/source/games/duke/src/2d_r.cpp +++ b/source/games/duke/src/2d_r.cpp @@ -481,11 +481,8 @@ public: FormatTime(currentLevel->parTime, tempbuf); BigText(191, 64, tempbuf, -1); - if (!isNamWW2GI()) - { - FormatTime(currentLevel->designerTime, tempbuf); - BigText(191, 80, tempbuf, -1); - } + FormatTime(currentLevel->designerTime, tempbuf); + BigText(191, 80, tempbuf, -1); } } @@ -556,21 +553,18 @@ public: }; -class DRRRAEndOfGame : public DScreenJob +class DRRRAEndOfGame : public DSkippableScreenJob { public: - DRRRAEndOfGame() : DScreenJob(fadein|fadeout) + DRRRAEndOfGame() : DSkippableScreenJob(fadein|fadeout) { } - bool OnEvent(event_t* ev) override + + void Skipped() override { - if (ev->type == EV_GUI_KeyDown) - { - S_StopSound(35); - state = skipped; - } - return true; + S_StopSound(35); } + void OnTick() override { if (ticks == 1) S_PlaySound(35, CHAN_AUTO, CHANF_UI); diff --git a/source/games/sw/src/2d.cpp b/source/games/sw/src/2d.cpp index cfe9a88b2..8256b0be3 100644 --- a/source/games/sw/src/2d.cpp +++ b/source/games/sw/src/2d.cpp @@ -45,20 +45,23 @@ BEGIN_SW_NS // //--------------------------------------------------------------------------- -class DSWDRealmsScreen : public DScreenJob +class DSWDRealmsScreen : public DSkippableScreenJob { public: - DSWDRealmsScreen() : DScreenJob(fadein | fadeout) {} + DSWDRealmsScreen() : DSkippableScreenJob(fadein | fadeout) {} - int Frame(uint64_t clock, bool skiprequest) override + void OnTick() override + { + if (ticks > 5 * GameTicRate) state = finished; + } + + void Draw(double) override { - const uint64_t duration = 5'000'000'000; const auto tex = tileGetTexture(THREED_REALMS_PIC, true); const int translation = TRANSLATION(Translation_BasePalettes, DREALMSPAL); twod->ClearScreen(); DrawTexture(twod, tex, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_TranslationIndex, translation, DTA_LegacyRenderStyle, STYLE_Normal, TAG_DONE); - return skiprequest ? -1 : clock < duration ? 1 : 0; } }; @@ -166,7 +169,7 @@ DScreenJob* GetFinishAnim(int num) // //--------------------------------------------------------------------------- -class DSWCreditsScreen : public DScreenJob +class DSWCreditsScreen : public DSkippableScreenJob { enum { @@ -177,21 +180,23 @@ class DSWCreditsScreen : public DScreenJob int starttime; int curpic; - int Frame(uint64_t clock, bool skiprequest) + void Skipped() override { - twod->ClearScreen(); - int seconds = int(clock / 1'000'000'000); - if (clock == 0) + StopSound(); + } + + void OnTick() override + { + if (ticks == 1) { // Lo Wang feel like singing! PlaySound(DIGI_JG95012, v3df_none, CHAN_VOICE, CHANF_UI); } if (state == 0) { - if (skiprequest || !soundEngine->IsSourcePlayingSomething(SOURCE_None, nullptr, CHAN_VOICE)) + if (!soundEngine->IsSourcePlayingSomething(SOURCE_None, nullptr, CHAN_VOICE)) { - skiprequest = false; - starttime = seconds; + starttime = ticks; state = 1; StopSound(); curpic = CREDITS1_PIC; @@ -205,15 +210,19 @@ class DSWCreditsScreen : public DScreenJob } else { - if (seconds >= starttime + 8) + if (ticks >= starttime + 8 * GameTicRate) { curpic = CREDITS1_PIC + CREDITS2_PIC - curpic; - starttime = seconds; + starttime = ticks; } - DrawTexture(twod, tileGetTexture(curpic, true), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_LegacyRenderStyle, STYLE_Normal, TAG_DONE); } - if (skiprequest) StopSound(); - return skiprequest ? -1 : 1; + } + + void Draw(double) override + { + twod->ClearScreen(); + if (state == 1) + DrawTexture(twod, tileGetTexture(curpic, true), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_LegacyRenderStyle, STYLE_Normal, TAG_DONE); } }; @@ -377,31 +386,41 @@ private: (*(*State)->Animator)(0); } - int Frame(uint64_t clock, bool skiprequest) + bool OnEvent(event_t* ev) override { - twod->ClearScreen(); - int currentclock = int(clock * 120 / 1'000'000'000); + if (ev->type == EV_KeyDown) + { + if (State >= s_BonusRest && State < &s_BonusRest[countof(s_BonusRest)]) + { + State = s_BonusAnim[STD_RANDOM_RANGE(countof(s_BonusAnim))]; + Tics = 0; + nextclock = ticks; + } + } + return true; + } - if (clock == 0) + void OnTick() override + { + if (ticks == 1) { PlaySong(nullptr, ThemeSongs[1], ThemeTrack[1]); } + while (ticks > nextclock) + { + nextclock++; + gStateControl(&State, &Tics); + } - if (skiprequest && State >= s_BonusRest && State < &s_BonusRest[countof(s_BonusRest)]) + if (State == State->NextState) { - State = s_BonusAnim[STD_RANDOM_RANGE(countof(s_BonusAnim))]; - Tics = 0; - skiprequest = false; - nextclock = currentclock; - } - else - { - while (currentclock > nextclock) - { - nextclock += synctics; - gStateControl(&State, &Tics); - } + state = finished; + StopSound(); } + } + + void Draw(double) override + { twod->ClearScreen(); DrawTexture(twod, tileGetTexture(BONUS_SCREEN_PIC, true), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_LegacyRenderStyle, STYLE_Normal, TAG_DONE); MNU_DrawString(160, 20, currentLevel->DisplayName(), 1, 19, 0); @@ -437,10 +456,6 @@ private: MNU_DrawString(60, BONUS_LINE(line), ds, 1, 16); MNU_DrawString(160, 185, GStrings("PRESSKEY"), 1, 19, 0); - - int ret = (State == State->NextState)? 0 : skiprequest ? -1 : 1; - if (ret != 1) StopSound(); - return ret; } }; @@ -466,12 +481,17 @@ enum }; -class DSWMultiSummaryScreen : public DScreenJob +class DSWMultiSummaryScreen : public DSkippableScreenJob { short death_total[MAX_SW_PLAYERS_REG]{}; short kills[MAX_SW_PLAYERS_REG]{}; - int Frame(uint64_t clock, bool skiprequest) + void Skipped() override + { + StopSound(); + } + + void Draw(double) override { if (clock == 0) PlaySong(nullptr, ThemeSongs[1], ThemeTrack[1]); @@ -571,8 +591,6 @@ class DSWMultiSummaryScreen : public DScreenJob y += STAT_OFF_Y; } - if (skiprequest) StopSound(); - return skiprequest ? -1 : 1; } }; @@ -635,7 +653,7 @@ class DSWLoadScreen : public DScreenJob public: DSWLoadScreen(MapRecord* maprec) : DScreenJob(0), rec(maprec) {} - int Frame(uint64_t clock, bool skiprequest) + void Draw(double) override { const int TITLE_PIC = 2324; twod->ClearScreen(); @@ -643,8 +661,6 @@ public: MNU_DrawString(160, 170, /*DemoMode ? GStrings("TXT_LBDEMO") :*/ GStrings("TXT_ENTERING"), 1, 16, 0); MNU_DrawString(160, 180, rec->DisplayName(), 1, 16, 0); - - return 0; } }; From fed15a79e48b2c1c90e78c7029692f428d12f7ee Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 16 Apr 2021 20:08:20 +0200 Subject: [PATCH 14/34] - Exhumed's intro screens. --- source/core/screenjob.h | 1 + source/games/exhumed/src/2d.cpp | 74 +++++++++++++++++------------- source/games/exhumed/src/movie.cpp | 11 +++-- 3 files changed, 51 insertions(+), 35 deletions(-) diff --git a/source/core/screenjob.h b/source/core/screenjob.h index 82e053781..82a884006 100644 --- a/source/core/screenjob.h +++ b/source/core/screenjob.h @@ -62,6 +62,7 @@ public: int Frame(uint64_t clock, bool skiprequest, double smoothratio) { + if (state != running) smoothratio = 1; // this is necessary because the ticker won't be incremented anymore to avoid having a negative time span. Draw(smoothratio); if (state == skipped) return -1; if (state == finished) return 0; diff --git a/source/games/exhumed/src/2d.cpp b/source/games/exhumed/src/2d.cpp index 5e0fefce0..c9b3545b3 100644 --- a/source/games/exhumed/src/2d.cpp +++ b/source/games/exhumed/src/2d.cpp @@ -38,6 +38,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "v_draw.h" #include "m_random.h" #include "gstrings.h" +#include "c_bind.h" #include @@ -382,13 +383,19 @@ class DLobotomyScreen : public DImageScreen public: DLobotomyScreen(FGameTexture *tex, int fade) : DImageScreen(tex, fade) {} - - int Frame(uint64_t clock, bool skiprequest) override + + void Skipped() override { - if (clock == 0) PlayLocalSound(StaticSound[kSoundJonLaugh2], 7000, false, CHANF_UI); - if (skiprequest) StopLocalSound(); - return DImageScreen::Frame(clock, skiprequest); - } + StopLocalSound(); + } + + void OnTick() override + { + if (ticks == 1) PlayLocalSound(StaticSound[kSoundJonLaugh2], 7000, false, CHANF_UI); + + DImageScreen::OnTick(); + if (state == finished) StopLocalSound(); + } }; //--------------------------------------------------------------------------- @@ -399,12 +406,12 @@ public: static const short skullDurations[] = { 6, 25, 43, 50, 68, 78, 101, 111, 134, 158, 173, 230, 600 }; -class DMainTitle : public DScreenJob +class DMainTitle : public DSkippableScreenJob { const char* a; const char* b; int state = 0; - int var_18; + int duration; int var_4 = 0; int esi = 130; int nCount = 0; @@ -412,56 +419,64 @@ class DMainTitle : public DScreenJob public: - DMainTitle() : DScreenJob(fadein) + DMainTitle() : DSkippableScreenJob(fadein) { a = GStrings("TXT_EX_COPYRIGHT1"); b = GStrings("TXT_EX_COPYRIGHT2"); - var_18 = skullDurations[0]; + duration = skullDurations[0]; } - int Frame(uint64_t clock, bool skiprequest) override + void OnTick() override { - int ticker = clock * 120 / 1'000'000'000; - if (clock == 0) + int ticker = ticks * 120 / GameTicRate; + if (ticks == 1) { PlayLocalSound(StaticSound[59], 0, true, CHANF_UI); playCDtrack(19, true); } - if (clock > 1'000'000 && state == 0 && !soundEngine->IsSourcePlayingSomething(SOURCE_None, nullptr,CHAN_AUTO, -1)) + if (ticks > 1 && state == 0 && !soundEngine->IsSourcePlayingSomething(SOURCE_None, nullptr, CHAN_AUTO, -1)) { - if (time(0) & 0xF) + if (time(0) & 0xF) // cheap-ass random... PlayGameOverSound(); - else + else PlayLocalSound(StaticSound[61], 0, false, CHANF_UI); state = 1; start = ticker; } + if (state == 1) + { + if (ticker > duration) + { + nCount++; + if (nCount > 12) + { + state = finished; + return; + } + duration = start + skullDurations[nCount]; + var_4 = var_4 == 0; + } + } + } + void Draw(double) override + { twod->ClearScreen(); menu_DoPlasma(); DrawRel(kSkullHead, 160, 100); - switch (state) + if (state == 0) { - case 0: DrawRel(kSkullJaw, 161, 130); - break; - - case 1: + } + else { int nStringWidth = SmallFont->StringWidth(a); DrawText(twod, SmallFont, CR_UNTRANSLATED, 160 - nStringWidth / 2, 200 - 24, a, DTA_FullscreenScale, FSMode_Fit320x200, TAG_DONE); nStringWidth = SmallFont->StringWidth(b); DrawText(twod, SmallFont, CR_UNTRANSLATED, 160 - nStringWidth / 2, 200 - 16, b, DTA_FullscreenScale, FSMode_Fit320x200, TAG_DONE); - if (ticker > var_18) - { - nCount++; - if (nCount > 12) return 0; - var_18 = start + skullDurations[nCount]; - var_4 = var_4 == 0; - } short nTile = kSkullJaw; @@ -486,10 +501,7 @@ public: } DrawRel(nTile, 161, y); - break; } - } - return skiprequest? -1 : 1; } }; diff --git a/source/games/exhumed/src/movie.cpp b/source/games/exhumed/src/movie.cpp index b743b473c..eef61ba4c 100644 --- a/source/games/exhumed/src/movie.cpp +++ b/source/games/exhumed/src/movie.cpp @@ -200,7 +200,7 @@ public: // //--------------------------------------------------------------------------- -class DLmfPlayer : public DScreenJob +class DLmfPlayer : public DSkippableScreenJob { LMFPlayer decoder; double angle = 1536; @@ -216,6 +216,7 @@ public: lastclock = 0; nextclock = 0; fp = std::move(fr); + pausable = false; } //--------------------------------------------------------------------------- @@ -224,14 +225,16 @@ public: // //--------------------------------------------------------------------------- - int Frame(uint64_t clock, bool skiprequest) override + void Draw(double smoothratio) override { + uint64_t clock = (ticks + smoothratio) * 1'000'000'000. / GameTicRate; if (clock >= nextclock) { nextclock += 100'000'000; if (decoder.ReadFrame(fp) == 0) { - return 0; + state = finished; + return; } } @@ -246,6 +249,7 @@ public: angle = 0; } } + assert(z < 65536); { twod->ClearScreen(); @@ -254,7 +258,6 @@ public: } lastclock = clock; - return skiprequest ? -1 : 1; } void OnDestroy() override From a43259c40c1d8c4d59ddcf9fc9fa3514c3b0ee6f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 16 Apr 2021 20:10:46 +0200 Subject: [PATCH 15/34] - Exhumed's map. --- source/games/exhumed/src/2d.cpp | 161 +++++++++++++++----------------- 1 file changed, 75 insertions(+), 86 deletions(-) diff --git a/source/games/exhumed/src/2d.cpp b/source/games/exhumed/src/2d.cpp index c9b3545b3..77a091267 100644 --- a/source/games/exhumed/src/2d.cpp +++ b/source/games/exhumed/src/2d.cpp @@ -629,10 +629,8 @@ class DMapScreen : public DScreenJob { int i; int x = 0; - int var_2C = 0; + int delta = 0; int nIdleSeconds = 0; - int startTime = 0; - int runtimer = 0; int curYPos, destYPos; int nLevel, nLevelNew, nLevelBest; @@ -644,11 +642,11 @@ public: destYPos = MapLevelOffsets[nLevelNew] + (200 * (nLevelNew / 2)); if (curYPos < destYPos) { - var_2C = 2; + delta = 2; } if (curYPos > destYPos) { - var_2C = -2; + delta = -2; } // Trim smoke in widescreen @@ -662,20 +660,13 @@ public: } #endif } - - int Frame(uint64_t clock, bool skiprequest) override - + + void Draw(double smoothratio) { - int currentclock = int(clock * 120 / 1'000'000'000); + int currentclock = int((ticks + smoothratio) * 120 / GameTicRate); twod->ClearScreen(); - if ((currentclock - startTime) / kTimerTicks) - { - nIdleSeconds++; - startTime = currentclock; - } - int tileY = curYPos; // Draw the background screens @@ -739,84 +730,82 @@ public: DrawAbs(nTile, textX, textY, shade); } - if (curYPos != destYPos) - { - // scroll the map every couple of ms - if (currentclock - runtimer >= (kTimerTicks / 32)) { - curYPos += var_2C; - runtimer = currentclock; - } - - if (inputState.CheckAllInput()) - { - if (var_2C < 8) { - var_2C *= 2; - } - - } - - if (curYPos > destYPos&& var_2C > 0) { - curYPos = destYPos; - } - - if (curYPos < destYPos && var_2C < 0) { - curYPos = destYPos; - } - - nIdleSeconds = 0; - } selectedlevelnew = nLevelNew + 1; - return skiprequest? -1 : nIdleSeconds < 12? 1 : 0; } - bool ProcessInput() override + void OnTick() override + { + if (curYPos != destYPos) + { + // scroll the map every couple of ms + curYPos += delta; + + if (curYPos > destYPos && delta > 0) { + curYPos = destYPos; + } + + if (curYPos < destYPos && delta < 0) { + curYPos = destYPos; + } + nIdleSeconds = 0; + } + else nIdleSeconds++; + if (nIdleSeconds > 300) state = finished; + } + + bool OnEvent(event_t* ev) override { - if (buttonMap.ButtonDown(gamefunc_Move_Forward)) - { - buttonMap.ClearButton(gamefunc_Move_Forward); - - if (curYPos == destYPos && nLevelNew <= nLevelBest) - { - nLevelNew++; - assert(nLevelNew < 20); - - destYPos = MapLevelOffsets[nLevelNew] + (200 * (nLevelNew / 2)); - - if (curYPos <= destYPos) { - var_2C = 2; - } - else { - var_2C = -2; - } - - nIdleSeconds = 0; - } - return true; - } + int key = ev->data1; + if (ev->type == EV_KeyDown) + { + auto binding = Bindings.GetBinding(ev->data1); + if (!binding.CompareNoCase("+move_forward")) key = KEY_UPARROW; + if (!binding.CompareNoCase("+move_backward")) key = KEY_DOWNARROW; + + if (key == KEY_UPARROW || key == KEY_PAD_DPAD_UP || key == sc_kpad_8) + { + if (curYPos == destYPos && nLevelNew <= nLevelBest) + { + nLevelNew++; + assert(nLevelNew < 20); + + destYPos = MapLevelOffsets[nLevelNew] + (200 * (nLevelNew / 2)); + + if (curYPos <= destYPos) { + delta = 2; + } + else { + delta = -2; + } + + nIdleSeconds = 0; + } + return true; + } - if (buttonMap.ButtonDown(gamefunc_Move_Backward)) - { - buttonMap.ClearButton(gamefunc_Move_Backward); + if (key == KEY_DOWNARROW || key == KEY_PAD_DPAD_DOWN || key == sc_kpad_2) + { + if (curYPos == destYPos && nLevelNew > 0) + { + nLevelNew--; + assert(nLevelNew >= 0); - if (curYPos == destYPos && nLevelNew > 0) - { - nLevelNew--; - assert(nLevelNew >= 0); - - destYPos = MapLevelOffsets[nLevelNew] + (200 * (nLevelNew / 2)); - - if (curYPos <= destYPos) { - var_2C = 2; - } - else { - var_2C = -2; - } - - nIdleSeconds = 0; - } - return true; + destYPos = MapLevelOffsets[nLevelNew] + (200 * (nLevelNew / 2)); + + if (curYPos <= destYPos) { + delta = 2; + } + else { + delta = -2; + } + + nIdleSeconds = 0; + } + return true; + } + state = skipped; + return true; } - return false; } }; From e580407d7d4af015bacb59f0c22485854a5dca30 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 16 Apr 2021 20:48:40 +0200 Subject: [PATCH 16/34] - the remaining Exhumed screens. These are not tested yet, a bit more work is needed to allow this. --- source/core/screenjob.h | 3 +- source/games/exhumed/src/2d.cpp | 164 ++++++++++++++++++-------------- 2 files changed, 94 insertions(+), 73 deletions(-) diff --git a/source/core/screenjob.h b/source/core/screenjob.h index 82a884006..c500c139a 100644 --- a/source/core/screenjob.h +++ b/source/core/screenjob.h @@ -57,7 +57,6 @@ public: virtual bool OnEvent(event_t* evt) { return false; } virtual void OnTick() { /*state = finished;*/ } - virtual int Frame(uint64_t clock, bool skiprequest) { return 1; } virtual void Draw(double smoothratio) {} int Frame(uint64_t clock, bool skiprequest, double smoothratio) @@ -66,7 +65,7 @@ public: Draw(smoothratio); if (state == skipped) return -1; if (state == finished) return 0; - return Frame(clock, skiprequest); + return 1; } int GetFadeState() const { return fadestate; } diff --git a/source/games/exhumed/src/2d.cpp b/source/games/exhumed/src/2d.cpp index 77a091267..0c77a95a2 100644 --- a/source/games/exhumed/src/2d.cpp +++ b/source/games/exhumed/src/2d.cpp @@ -963,16 +963,17 @@ void uploadCinemaPalettes() // //--------------------------------------------------------------------------- -class DCinema : public DScreenJob +class DCinema : public DSkippableScreenJob { TextOverlay text; short cinematile; int currentCinemaPalette; int edx; int check; + int cont = 1; public: - DCinema(int nVal, int checklevel = -1) : DScreenJob(fadein|fadeout) + DCinema(int nVal, int checklevel = -1) : DSkippableScreenJob(fadein|fadeout) { if (nVal < 0 || nVal >5) return; cinematile = cinemas[nVal].tile; @@ -984,12 +985,17 @@ public: check = checklevel; } - int Frame(uint64_t clock, bool skiprequest) override + void OnTick() override { - - if (clock == 0) + if (ticks == 1) { - if (check > 0 && check != selectedlevelnew) return 0; // immediately abort if the player selected a different level on the map + if (check > 0 && check != selectedlevelnew) + { + state = finished; + return; // immediately abort if the player selected a different level on the map + } + + check = -1; StopAllSounds(); if (edx != -1) { @@ -997,19 +1003,26 @@ public: } } + if (!cont) + { + state = finished; + // quit the game if we've finished level 4 and displayed the advert text + if (isShareware() && currentCinemaPalette == 3) + { + gameaction = ga_mainmenu; + } + return; + } + } + + void Draw(double smoothratio) override + { twod->ClearScreen(); + if (check < 0) return; DrawTexture(twod, tileGetTexture(cinematile), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_TranslationIndex, TRANSLATION(Translation_BasePalettes, currentCinemaPalette), TAG_DONE); text.DisplayText(); - auto cont = text.AdvanceCinemaText(clock * (120. / 1'000'000'000)); - int ret = skiprequest ? -1 : cont ? 1 : 0; - - // quit the game if we've finished level 4 and displayed the advert text - if (isShareware() && currentCinemaPalette == 3 && ret != 1) - { - gameaction = ga_mainmenu; - } - return ret; + cont = text.AdvanceCinemaText((ticks + smoothratio) * (120. / GameTicRate)); } }; @@ -1029,6 +1042,7 @@ class DLastLevelCinema : public DScreenJob int nextclock = 4; unsigned int nStringTypeOn, nCharTypeOn; int screencnt = 0; + bool skiprequest = false; TArray screentext; @@ -1142,91 +1156,81 @@ private: } } - int Frame(uint64_t clock, bool skiprequest) override + bool OnEvent(event_t* ev) { - if (clock == 0) + if (ev->type == EV_KeyDown) skiprequest = true; + return true; + } + + void OnTick() override + { + if (ticks == 1) { PlayLocalSound(StaticSound[kSound75], 0, false, CHANF_UI); phase = 1; } - int currentclock = clock * 120 / 1'000'000'000; - twod->ClearScreen(); - DrawTexture(twod, tileGetTexture(kTileLoboLaptop), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, TAG_DONE); + switch (phase) { case 1: - if (currentclock >= nextclock) - { - Phase1(); - nextclock += 4; - } - if (skiprequest || currentclock >= 240) + Phase1(); + if (skiprequest || ticks >= 60) { InitPhase2(); phase = 2; - skiprequest = 0; + skiprequest = false; } break; case 2: - if (currentclock >= nextclock) + if (screentext[nStringTypeOn][nCharTypeOn] != ' ') + PlayLocalSound(StaticSound[kSound71], 0, false, CHANF_UI); + + nCharTypeOn++; + if (screentext[nStringTypeOn][nCharTypeOn] == 0) { - if (screentext[nStringTypeOn][nCharTypeOn] != ' ') - PlayLocalSound(StaticSound[kSound71], 0, false, CHANF_UI); - - nCharTypeOn++; - nextclock += 4; - if (screentext[nStringTypeOn][nCharTypeOn] == 0) + nCharTypeOn = 0; + nStringTypeOn++; + if (nStringTypeOn >= screentext.Size()) { - nCharTypeOn = 0; - nStringTypeOn++; - if (nStringTypeOn >= screentext.Size()) - { - nextclock = (kTimerTicks * (screentext.Size() + 2)) + currentclock; - phase = 3; - } - + nextclock = (GameTicRate * (screentext.Size() + 2)) + ticks; + phase = 3; } + } - DisplayPhase2(); if (skiprequest) { - nextclock = (kTimerTicks * (screentext.Size() + 2)) + currentclock; + nextclock = (GameTicRate * (screentext.Size() + 2)) + ticks; phase = 4; } break; case 3: - DisplayPhase2(); - if (currentclock >= nextclock || skiprequest) + if (ticks >= nextclock || skiprequest) { PlayLocalSound(StaticSound[kSound75], 0, false, CHANF_UI); phase = 4; - nextclock = currentclock + 240; - skiprequest = 0; + nextclock = ticks + 60; + skiprequest = false; } - break; case 4: - if (currentclock >= nextclock) + if (ticks >= nextclock) { skiprequest |= !Phase3(); - nextclock += 4; } - if (skiprequest || currentclock >= 240) + if (skiprequest) { - // Go to the next text page. - if (screencnt != 2) - { - screencnt++; - nextclock = currentclock + 240; - skiprequest = 0; - phase = 1; - } - else return skiprequest ? -1 : 0; + state = finished; } } - return 1; + } + + void Draw(double) override + { + twod->ClearScreen(); + DrawTexture(twod, tileGetTexture(kTileLoboLaptop), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, TAG_DONE); + if (phase == 2 || phase == 3) DisplayPhase2(); } }; @@ -1243,6 +1247,7 @@ class DExCredits : public DScreenJob TArray pagelines; uint64_t page; uint64_t pagetime; + bool skiprequest = false; public: DExCredits() @@ -1253,35 +1258,53 @@ public: credits = text.Split("\n\n"); } -private: - int Frame(uint64_t clock, bool skiprequest) override + bool OnEvent(event_t* ev) { - if (clock == 0) + if (ev->type == EV_KeyDown) skiprequest = true; + return true; + } + + void OnTick() override + { + if (ticks == 1) { - if (credits.Size() == 0) return 0; + if (credits.Size() == 0) + { + state = finished; + return; + } playCDtrack(19, false); pagetime = 0; page = -1; } - if (clock >= pagetime || skiprequest) + + if (ticks >= pagetime || skiprequest) { page++; if (page < credits.Size()) pagelines = credits[page].Split("\n"); else { - if (skiprequest || !CDplaying()) return 0; + if (skiprequest || !CDplaying()) + { + state = finished; + return; + } pagelines.Clear(); } - pagetime = clock + 2'000'000'000; // + pagetime = ticks + 60; // } + } + + void Draw(double smoothratio) override + { twod->ClearScreen(); int y = 100 - ((10 * (pagelines.Size() - 1)) / 2); for (unsigned i = 0; i < pagelines.Size(); i++) { - uint64_t ptime = (pagetime-clock) / 1'000'000; + int ptime = clamp((pagetime - ticks - smoothratio) * 1000 / GameTicRate, 0, 2000); // in milliseconds int light; if (ptime < 255) light = ptime; @@ -1294,7 +1317,6 @@ private: DrawText(twod, SmallFont, CR_UNTRANSLATED, 160 - nStringWidth / 2, y, pagelines[i], DTA_FullscreenScale, FSMode_Fit320x200, DTA_Color, color, TAG_DONE); y += 10; } - return 1; } }; From 2942e011bfdc7c485a68432c9a36614e3c0c9680 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 16 Apr 2021 21:27:54 +0200 Subject: [PATCH 17/34] - cleaned up the screen job's fade handling, now that the jobs no longer depend on an external timer. --- source/common/2d/v_2ddrawer.cpp | 3 +- source/common/2d/v_2ddrawer.h | 4 +- .../common/rendering/hwrenderer/hw_draw2d.cpp | 2 +- source/core/screenjob.cpp | 102 +++++++----------- source/core/screenjob.h | 13 +-- source/games/duke/src/2d_d.cpp | 2 +- 6 files changed, 46 insertions(+), 80 deletions(-) diff --git a/source/common/2d/v_2ddrawer.cpp b/source/common/2d/v_2ddrawer.cpp index d774d12b4..911c5d7ee 100644 --- a/source/common/2d/v_2ddrawer.cpp +++ b/source/common/2d/v_2ddrawer.cpp @@ -189,8 +189,9 @@ DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushTriangle, Shape2D_PushTriangle) // //========================================================================== -int F2DDrawer::AddCommand(const RenderCommand *data) +int F2DDrawer::AddCommand(RenderCommand *data) { + data->mScreenFade = screenFade; if (mData.Size() > 0 && data->isCompatible(mData.Last())) { // Merge with the last command. diff --git a/source/common/2d/v_2ddrawer.h b/source/common/2d/v_2ddrawer.h index d1c2a161e..b3e7d2aa5 100644 --- a/source/common/2d/v_2ddrawer.h +++ b/source/common/2d/v_2ddrawer.h @@ -118,6 +118,7 @@ public: ETexMode mDrawMode; uint8_t mLightLevel; uint8_t mFlags; + float mScreenFade; bool useTransform; DMatrix3x3 transform; @@ -149,6 +150,7 @@ public: mLightLevel == other.mLightLevel && mColor1.d == other.mColor1.d && useTransform == other.useTransform && + mScreenFade == other.mScreenFade && ( !useTransform || ( @@ -172,7 +174,7 @@ public: int fullscreenautoaspect = 3; int cliptop = -1, clipleft = -1, clipwidth = -1, clipheight = -1; - int AddCommand(const RenderCommand *data); + int AddCommand(RenderCommand *data); void AddIndices(int firstvert, int count, ...); private: void AddIndices(int firstvert, TArray &v); diff --git a/source/common/rendering/hwrenderer/hw_draw2d.cpp b/source/common/rendering/hwrenderer/hw_draw2d.cpp index 36fd8f369..cf3399432 100644 --- a/source/common/rendering/hwrenderer/hw_draw2d.cpp +++ b/source/common/rendering/hwrenderer/hw_draw2d.cpp @@ -85,7 +85,6 @@ void Draw2D(F2DDrawer *drawer, FRenderState &state) vb.UploadData(&vertices[0], vertices.Size(), &indices[0], indices.Size()); state.SetVertexBuffer(&vb); state.EnableFog(false); - state.SetScreenFade(drawer->screenFade); for(auto &cmd : commands) { @@ -94,6 +93,7 @@ void Draw2D(F2DDrawer *drawer, FRenderState &state) state.SetRenderStyle(cmd.mRenderStyle); state.EnableBrightmap(!(cmd.mRenderStyle.Flags & STYLEF_ColorIsFixed)); state.EnableFog(2); // Special 2D mode 'fog'. + state.SetScreenFade(cmd.mScreenFade); state.SetTextureMode(cmd.mDrawMode); diff --git a/source/core/screenjob.cpp b/source/core/screenjob.cpp index 6f7b53436..14bcc86ea 100644 --- a/source/core/screenjob.cpp +++ b/source/core/screenjob.cpp @@ -125,11 +125,10 @@ class ScreenJobRunner int index = -1; float screenfade; bool clearbefore; - int64_t startTime = -1; - int64_t lastTime = -1; int actionState; int terminateState; - uint64_t clock = 0; + int fadeticks = 0; + int last_M_Active_Tic = -1; public: ScreenJobRunner(JobDesc* jobs_, int count, CompletionFunc completion_, bool clearbefore_) @@ -174,73 +173,39 @@ public: index++; } actionState = clearbefore ? State_Clear : State_Run; - if (index < jobs.Size()) screenfade = jobs[index].job->fadestyle & DScreenJob::fadein ? 0.f : 1.f; - lastTime= startTime = -1; - clock = 0; + if (index < jobs.Size()) + { + jobs[index].job->fadestate = jobs[index].job->fadestyle & DScreenJob::fadein? DScreenJob::fadein : DScreenJob::visible; + } inputState.ClearAllInput(); } - int DisplayFrame() + int DisplayFrame(double smoothratio) { auto& job = jobs[index]; auto now = I_GetTimeNS(); bool processed = job.job->ProcessInput(); - if (startTime == -1) - { - lastTime = startTime = now; - } - else if (!M_Active()) - { - clock += now - lastTime; - if (clock == 0) clock = 1; - } - bool skiprequest = clock > 100'000'000 && inputState.CheckAllInput() && !processed && job.job->fadestate != DScreenJob::fadeout; - lastTime = now; - if (screenfade < 1.f && !M_Active()) + if (job.job->fadestate == DScreenJob::fadein) { - float ms = (clock / 1'000'000) / job.job->fadetime; - screenfade = clamp(ms, 0.f, 1.f); + double ms = (job.job->ticks + smoothratio) * 1000 / GameTicRate / job.job->fadetime; + float screenfade = (float)clamp(ms, 0., 1.); twod->SetScreenFade(screenfade); - if (job.job->fadestate != DScreenJob::fadeout) - job.job->fadestate = DScreenJob::fadein; + if (screenfade == 1.f) job.job->fadestate = DScreenJob::visible; } - else - { - job.job->fadestate = DScreenJob::visible; - screenfade = 1.f; - } - job.job->SetClock(clock); - int state = job.job->Frame(clock, skiprequest, M_Active()? 1. : I_GetTimeFrac()); - clock = job.job->GetClock(); - if (clock == 0) clock = 1; + int state = job.job->DrawFrame(smoothratio); + twod->SetScreenFade(1.f); return state; } - int FadeoutFrame() + int FadeoutFrame(double smoothratio) { - auto now = I_GetTimeNS(); - - if (startTime == -1) - { - lastTime = startTime = now; - } - else if (!M_Active()) - { - clock += now - lastTime; - if (clock == 0) clock = 1; - } - lastTime = now; - - float ms = (clock / 1'000'000) / jobs[index].job->fadetime; - float screenfade2 = clamp(screenfade - ms, 0.f, 1.f); - if (!M_Active()) twod->SetScreenFade(screenfade2); - if (screenfade2 <= 0.f) - { - twod->Unlock(); // must unlock before displaying. - return 0; - } - return 1; + auto& job = jobs[index]; + double ms = (job.job->ticks + smoothratio) * 1000 / GameTicRate / job.job->fadetime; + float screenfade = 1.f - (float)clamp(ms, 0., 1.); + twod->SetScreenFade(screenfade); + job.job->DrawFrame(1.); + return (screenfade > 0.f); } bool OnEvent(event_t* ev) @@ -268,9 +233,15 @@ public: } else { - if (jobs[index].job->state != DScreenJob::running) return; - jobs[index].job->ticks++; - jobs[index].job->OnTick(); + if (jobs[index].job->state == DScreenJob::running) + { + jobs[index].job->ticks++; + jobs[index].job->OnTick(); + } + else if (jobs[index].job->state == DScreenJob::stopping) + { + fadeticks++; + } } } @@ -284,6 +255,13 @@ public: if (completion) completion(false); return false; } + + // ensure that we won't go back in time if the menu is dismissed without advancing our ticker + bool menuon = M_Active(); + if (menuon) last_M_Active_Tic = jobs[index].job->ticks; + else if (last_M_Active_Tic == jobs[index].job->ticks) menuon = true; + double smoothratio = menuon ? 1. : I_GetTimeFrac(); + if (actionState == State_Clear) { actionState = State_Run; @@ -291,18 +269,14 @@ public: } else if (actionState == State_Run) { - terminateState = DisplayFrame(); + terminateState = DisplayFrame(smoothratio); if (terminateState < 1) { // Must lock before displaying. if (jobs[index].job->fadestyle & DScreenJob::fadeout) { - twod->Lock(); - startTime = -1; - clock = 0; jobs[index].job->fadestate = DScreenJob::fadeout; jobs[index].job->state = DScreenJob::stopping; - gamestate = GS_INTRO; // block menu and console during fadeout - this can cause timing problems. actionState = State_Fadeout; } else @@ -313,7 +287,7 @@ public: } else if (actionState == State_Fadeout) { - int ended = FadeoutFrame(); + int ended = FadeoutFrame(smoothratio); if (ended < 1) { jobs[index].job->state = DScreenJob::stopped; diff --git a/source/core/screenjob.h b/source/core/screenjob.h index c500c139a..b856b07a2 100644 --- a/source/core/screenjob.h +++ b/source/core/screenjob.h @@ -11,7 +11,6 @@ class ScreenJobRunner; class DScreenJob : public DObject { DECLARE_CLASS(DScreenJob, DObject) - int64_t now; const int fadestyle; const float fadetime; // in milliseconds int fadestate = fadein; @@ -45,21 +44,11 @@ public: return false; } - void SetClock(int64_t nsnow) - { - now = nsnow; - } - - int64_t GetClock() const - { - return now; - } - virtual bool OnEvent(event_t* evt) { return false; } virtual void OnTick() { /*state = finished;*/ } virtual void Draw(double smoothratio) {} - int Frame(uint64_t clock, bool skiprequest, double smoothratio) + int DrawFrame(double smoothratio) { if (state != running) smoothratio = 1; // this is necessary because the ticker won't be incremented anymore to avoid having a negative time span. Draw(smoothratio); diff --git a/source/games/duke/src/2d_d.cpp b/source/games/duke/src/2d_d.cpp index b41789177..f5c95c74b 100644 --- a/source/games/duke/src/2d_d.cpp +++ b/source/games/duke/src/2d_d.cpp @@ -526,7 +526,7 @@ class DEpisode4Text : public DSkippableScreenJob public: DEpisode4Text() : DSkippableScreenJob(fadein | fadeout) {} - void Draw(double) + void Draw(double) override { twod->ClearScreen(); BigText(160, 60, GStrings("Thanks to all our")); From 1852c0b8026101dcf5d4f69fa1f1f9018e29351f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 16 Apr 2021 22:03:01 +0200 Subject: [PATCH 18/34] - properly pause the screen job player if the menu is open. Still needs a bit of work for movies with embedded streaming sound. --- source/core/movie/movieplayer.cpp | 6 +++--- source/core/screenjob.cpp | 16 +++++++++------- source/core/screenjob.h | 2 +- source/games/exhumed/src/gameloop.cpp | 2 +- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/source/core/movie/movieplayer.cpp b/source/core/movie/movieplayer.cpp index 73fee3b99..10e3e52c2 100644 --- a/source/core/movie/movieplayer.cpp +++ b/source/core/movie/movieplayer.cpp @@ -137,7 +137,7 @@ public: if (sound == -1) soundEngine->StopAllChannels(); else if (SoundEnabled()) - soundEngine->StartSound(SOURCE_None, nullptr, nullptr, CHAN_AUTO, CHANF_UI, sound, 1.f, ATTN_NONE); + soundEngine->StartSound(SOURCE_None, nullptr, nullptr, CHAN_AUTO, CHANF_NONE, sound, 1.f, ATTN_NONE); } } if (!nostopsound && curframe == numframes && soundEngine->GetSoundPlayingInfo(SOURCE_None, nullptr, -1)) return true; @@ -444,7 +444,7 @@ public: if (sound == -1) soundEngine->StopAllChannels(); else if (SoundEnabled()) - soundEngine->StartSound(SOURCE_None, nullptr, nullptr, CHAN_AUTO, CHANF_UI, sound, 1.f, ATTN_NONE); + soundEngine->StartSound(SOURCE_None, nullptr, nullptr, CHAN_AUTO, CHANF_NONE, sound, 1.f, ATTN_NONE); } } lastsoundframe = soundframe; @@ -632,7 +632,7 @@ public: if (sound == -1) soundEngine->StopAllChannels(); else if (SoundEnabled()) - soundEngine->StartSound(SOURCE_None, nullptr, nullptr, CHAN_AUTO, CHANF_UI, sound, 1.f, ATTN_NONE); + soundEngine->StartSound(SOURCE_None, nullptr, nullptr, CHAN_AUTO, CHANF_NONE, sound, 1.f, ATTN_NONE); } } } diff --git a/source/core/screenjob.cpp b/source/core/screenjob.cpp index 14bcc86ea..b76dc6f0d 100644 --- a/source/core/screenjob.cpp +++ b/source/core/screenjob.cpp @@ -128,7 +128,7 @@ class ScreenJobRunner int actionState; int terminateState; int fadeticks = 0; - int last_M_Active_Tic = -1; + int last_paused_tic = -1; public: ScreenJobRunner(JobDesc* jobs_, int count, CompletionFunc completion_, bool clearbefore_) @@ -210,7 +210,7 @@ public: bool OnEvent(event_t* ev) { - if (index >= jobs.Size()) return false; + if (paused || index >= jobs.Size()) return false; if (jobs[index].job->state != DScreenJob::running) return false; return jobs[index].job->OnEvent(ev); } @@ -223,6 +223,7 @@ public: void OnTick() { + if (paused) return; if (index >= jobs.Size()) { //DeleteJobs(); @@ -257,9 +258,9 @@ public: } // ensure that we won't go back in time if the menu is dismissed without advancing our ticker - bool menuon = M_Active(); - if (menuon) last_M_Active_Tic = jobs[index].job->ticks; - else if (last_M_Active_Tic == jobs[index].job->ticks) menuon = true; + bool menuon = paused; + if (menuon) last_paused_tic = jobs[index].job->ticks; + else if (last_paused_tic == jobs[index].job->ticks) menuon = true; double smoothratio = menuon ? 1. : I_GetTimeFrac(); if (actionState == State_Clear) @@ -343,7 +344,7 @@ void ScreenJobTick() if (runner) runner->OnTick(); } -void ScreenJobDraw() +bool ScreenJobDraw() { // we cannot recover from this because we have no completion callback to call. if (!runner) @@ -351,7 +352,7 @@ void ScreenJobDraw() // We can get here before a gameaction has been processed. In that case just draw a black screen and wait. if (gameaction == ga_nothing) I_Error("Trying to run a non-existent screen job"); twod->ClearScreen(); - return; + return false; } auto res = runner->RunFrame(); if (!res) @@ -359,5 +360,6 @@ void ScreenJobDraw() assert((gamestate != GS_INTERMISSION && gamestate != GS_INTRO) || gameaction != ga_nothing); DeleteScreenJob(); } + return res; } diff --git a/source/core/screenjob.h b/source/core/screenjob.h index b856b07a2..067f546c4 100644 --- a/source/core/screenjob.h +++ b/source/core/screenjob.h @@ -143,7 +143,7 @@ void EndScreenJob(); void DeleteScreenJob(); bool ScreenJobResponder(event_t* ev); void ScreenJobTick(); -void ScreenJobDraw(); +bool ScreenJobDraw(); struct AnimSound { diff --git a/source/games/exhumed/src/gameloop.cpp b/source/games/exhumed/src/gameloop.cpp index 1028c1548..625648653 100644 --- a/source/games/exhumed/src/gameloop.cpp +++ b/source/games/exhumed/src/gameloop.cpp @@ -193,7 +193,7 @@ static void Intermission(MapRecord *from_map, MapRecord *to_map) gameaction = ga_nextlevel; } - }, true, true); + }); } } From f28aa8f06cf55a6ddef1a039b038639714863284 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 16 Apr 2021 22:14:11 +0200 Subject: [PATCH 19/34] - properly pause streaming soundtracks of movies as well. This is not relevant for any of the stock movies as they use separate sound files, we need to be aware of mods using the streaming sound capabilities of MVE and SMK. --- source/common/audio/music/music.cpp | 17 +++++++++++++++-- source/common/audio/music/s_music.h | 1 + source/core/gamecontrol.cpp | 7 ++++++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/source/common/audio/music/music.cpp b/source/common/audio/music/music.cpp index 9ab41c776..c1c8290f6 100644 --- a/source/common/audio/music/music.cpp +++ b/source/common/audio/music/music.cpp @@ -110,13 +110,18 @@ void S_SetMusicCallbacks(MusicCallbacks* cb) //========================================================================== static std::unique_ptr musicStream; +static TArray customStreams; SoundStream *S_CreateCustomStream(size_t size, int samplerate, int numchannels, StreamCallback cb, void *userdata) { int flags = 0; if (numchannels < 2) flags |= SoundStream::Mono; auto stream = GSnd->CreateStream(cb, int(size), flags, samplerate, userdata); - if (stream) stream->Play(true, 1); + if (stream) + { + stream->Play(true, 1); + customStreams.Push(stream); + } return stream; } @@ -125,11 +130,19 @@ void S_StopCustomStream(SoundStream *stream) if (stream) { stream->Stop(); + auto f = customStreams.Find(stream); + if (f < customStreams.Size()) customStreams.Delete(f); delete stream; } - } +void S_PauseAllCustomStreams(bool on) +{ + for (auto s : customStreams) + { + s->SetPaused(on); + } +} static TArray convert; static bool FillStream(SoundStream* stream, void* buff, int len, void* userdata) diff --git a/source/common/audio/music/s_music.h b/source/common/audio/music/s_music.h index ef852273c..a76189fc1 100644 --- a/source/common/audio/music/s_music.h +++ b/source/common/audio/music/s_music.h @@ -14,6 +14,7 @@ class SoundStream; typedef bool(*StreamCallback)(SoundStream* stream, void* buff, int len, void* userdata); SoundStream *S_CreateCustomStream(size_t size, int samplerate, int numchannels, StreamCallback cb, void *userdata); void S_StopCustomStream(SoundStream* stream); +void S_PauseAllCustomStreams(bool on); struct MusicCallbacks { diff --git a/source/core/gamecontrol.cpp b/source/core/gamecontrol.cpp index 7963c384d..3b93b0bad 100644 --- a/source/core/gamecontrol.cpp +++ b/source/core/gamecontrol.cpp @@ -998,7 +998,10 @@ void updatePauseStatus() } } - paused ? S_PauseSound(!pausedWithKey, !paused) : S_ResumeSound(paused); + if (paused) + S_PauseSound(!pausedWithKey, !paused); + else + S_ResumeSound(paused); } //========================================================================== @@ -1106,6 +1109,7 @@ void S_PauseSound (bool notmusic, bool notsfx) { soundEngine->SetPaused(true); GSnd->SetSfxPaused (true, 0); + S_PauseAllCustomStreams(true); } } @@ -1124,6 +1128,7 @@ void S_ResumeSound (bool notsfx) { soundEngine->SetPaused(false); GSnd->SetSfxPaused (false, 0); + S_PauseAllCustomStreams(false); } } From 03d517c509029df18ba4e7897fbaf83ef522b113 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 16 Apr 2021 22:16:21 +0200 Subject: [PATCH 20/34] - removed debug assert. --- source/games/exhumed/src/movie.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/source/games/exhumed/src/movie.cpp b/source/games/exhumed/src/movie.cpp index eef61ba4c..99a880b98 100644 --- a/source/games/exhumed/src/movie.cpp +++ b/source/games/exhumed/src/movie.cpp @@ -249,7 +249,6 @@ public: angle = 0; } } - assert(z < 65536); { twod->ClearScreen(); From 3910146740891a0e206f31d7e5e7da9b3ad6512c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 16 Apr 2021 22:21:57 +0200 Subject: [PATCH 21/34] - skip the fade-in of the screen job if it starts while the game is paused. While this works with the current code it simply does not look good. --- source/core/screenjob.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/core/screenjob.cpp b/source/core/screenjob.cpp index b76dc6f0d..575288588 100644 --- a/source/core/screenjob.cpp +++ b/source/core/screenjob.cpp @@ -175,7 +175,7 @@ public: actionState = clearbefore ? State_Clear : State_Run; if (index < jobs.Size()) { - jobs[index].job->fadestate = jobs[index].job->fadestyle & DScreenJob::fadein? DScreenJob::fadein : DScreenJob::visible; + jobs[index].job->fadestate = !paused && jobs[index].job->fadestyle & DScreenJob::fadein? DScreenJob::fadein : DScreenJob::visible; } inputState.ClearAllInput(); } From 584e4bfb4a7bbe90d0715425324ec6d0d5b661c3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 16 Apr 2021 22:39:48 +0200 Subject: [PATCH 22/34] - explicitly check for opening the console when running a screen job. --- source/core/screenjob.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/source/core/screenjob.cpp b/source/core/screenjob.cpp index 575288588..81e7fbdb8 100644 --- a/source/core/screenjob.cpp +++ b/source/core/screenjob.cpp @@ -211,6 +211,18 @@ public: bool OnEvent(event_t* ev) { if (paused || index >= jobs.Size()) return false; + + if (ev->type == EV_KeyDown) + { + // We never reach the key binding checks in G_Responder, so for the console we have to check for ourselves here. + auto binding = Bindings.GetBinding(ev->data1); + if (binding.CompareNoCase("toggleconsole") == 0) + { + C_ToggleConsole(); + return true; + } + } + if (jobs[index].job->state != DScreenJob::running) return false; return jobs[index].job->OnEvent(ev); } From 49e07a47c6ca0d45c709f890e3f3d4972000d815 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 16 Apr 2021 22:40:21 +0200 Subject: [PATCH 23/34] - now that everything is fixed, the map in Exhumed can be initiated from the console. --- source/games/exhumed/src/gameloop.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/source/games/exhumed/src/gameloop.cpp b/source/games/exhumed/src/gameloop.cpp index 625648653..d810eab56 100644 --- a/source/games/exhumed/src/gameloop.cpp +++ b/source/games/exhumed/src/gameloop.cpp @@ -217,16 +217,14 @@ void GameInterface::NewGame(MapRecord *map, int skill, bool frommenu) // start a new game on the given level InitNewGame(); if (map->levelNumber == 1) STAT_StartNewGame("Exhumed", 1); - if (frommenu) Intermission(nullptr, map); - else NextLevel(map, skill); + Intermission(nullptr, map); } void GameInterface::LevelCompleted(MapRecord *map, int skill) { Mus_Stop(); if (currentLevel->levelNumber == 0) gameaction = ga_mainmenu; - else if (ConsoleState == c_up) Intermission(currentLevel, map); - else gameaction = ga_nextlevel; + Intermission(currentLevel, map); } //--------------------------------------------------------------------------- From 2b9a527abaadad428c39f554d6f1333b9979077d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 16 Apr 2021 23:29:53 +0200 Subject: [PATCH 24/34] - added a 'Start' method to DScreenJob. Since the menu pauses the ticker this is needed to perform initial setup before the first frame. --- source/core/screenjob.cpp | 1 + source/core/screenjob.h | 1 + source/games/duke/src/2d_d.cpp | 10 ++-- source/games/duke/src/2d_r.cpp | 17 ++++-- source/games/exhumed/src/2d.cpp | 83 ++++++++++++++++-------------- source/games/exhumed/src/movie.cpp | 1 - source/games/sw/src/2d.cpp | 20 +++---- 7 files changed, 77 insertions(+), 56 deletions(-) diff --git a/source/core/screenjob.cpp b/source/core/screenjob.cpp index 81e7fbdb8..7845dbbae 100644 --- a/source/core/screenjob.cpp +++ b/source/core/screenjob.cpp @@ -176,6 +176,7 @@ public: if (index < jobs.Size()) { jobs[index].job->fadestate = !paused && jobs[index].job->fadestyle & DScreenJob::fadein? DScreenJob::fadein : DScreenJob::visible; + jobs[index].job->Start(); } inputState.ClearAllInput(); } diff --git a/source/core/screenjob.h b/source/core/screenjob.h index 067f546c4..b0a48b058 100644 --- a/source/core/screenjob.h +++ b/source/core/screenjob.h @@ -44,6 +44,7 @@ public: return false; } + virtual void Start() {} virtual bool OnEvent(event_t* evt) { return false; } virtual void OnTick() { /*state = finished;*/ } virtual void Draw(double smoothratio) {} diff --git a/source/games/duke/src/2d_d.cpp b/source/games/duke/src/2d_d.cpp index f5c95c74b..34e6d8a97 100644 --- a/source/games/duke/src/2d_d.cpp +++ b/source/games/duke/src/2d_d.cpp @@ -729,9 +729,9 @@ public: playerswhenstarted = pws; } - void OnTick() override + void Start() override { - if (ticks == 1) S_PlayBonusMusic(); + S_PlayBonusMusic(); } void Draw(double smoothratio) override @@ -879,9 +879,13 @@ public: return false; } + void Start() override + { + S_PlayBonusMusic(); + } + void OnTick() override { - if (ticks == 1) S_PlayBonusMusic(); if ((displaystate & printStatsAll) != printStatsAll) { if (ticks == 15 * 3) diff --git a/source/games/duke/src/2d_r.cpp b/source/games/duke/src/2d_r.cpp index f7eecc088..caf2440a5 100644 --- a/source/games/duke/src/2d_r.cpp +++ b/source/games/duke/src/2d_r.cpp @@ -265,11 +265,12 @@ public: playerswhenstarted = pws; } - void OnTick() override + void Start() override { - if (ticks == 1) S_PlayBonusMusic(); + S_PlayBonusMusic(); } + void Draw(double) override { char tempbuf[32]; @@ -419,9 +420,13 @@ public: return false; } + void Start() override + { + S_PlayBonusMusic(); + } + void OnTick() override { - if (ticks == 1) S_PlayBonusMusic(); if ((displaystate & printStatsAll) != printStatsAll) { if (ticks == 15 * 3) @@ -565,9 +570,13 @@ public: S_StopSound(35); } + void Start() override + { + S_PlaySound(35, CHAN_AUTO, CHANF_UI); + } + void OnTick() override { - if (ticks == 1) S_PlaySound(35, CHAN_AUTO, CHANF_UI); if (!S_CheckSoundPlaying(-1, 35) && ticks > 15 * GameTicRate) state = finished; // make sure it stays, even if sound is off. } void Draw(double) override diff --git a/source/games/exhumed/src/2d.cpp b/source/games/exhumed/src/2d.cpp index 0c77a95a2..1dffb4b7d 100644 --- a/source/games/exhumed/src/2d.cpp +++ b/source/games/exhumed/src/2d.cpp @@ -389,9 +389,13 @@ public: StopLocalSound(); } + void Start() override + { + PlayLocalSound(StaticSound[kSoundJonLaugh2], 7000, false, CHANF_UI); + } + void OnTick() override { - if (ticks == 1) PlayLocalSound(StaticSound[kSoundJonLaugh2], 7000, false, CHANF_UI); DImageScreen::OnTick(); if (state == finished) StopLocalSound(); @@ -426,14 +430,15 @@ public: duration = skullDurations[0]; } + void Start() override + { + PlayLocalSound(StaticSound[59], 0, true, CHANF_UI); + playCDtrack(19, true); + } + void OnTick() override { int ticker = ticks * 120 / GameTicRate; - if (ticks == 1) - { - PlayLocalSound(StaticSound[59], 0, true, CHANF_UI); - playCDtrack(19, true); - } if (ticks > 1 && state == 0 && !soundEngine->IsSourcePlayingSomething(SOURCE_None, nullptr, CHAN_AUTO, -1)) { if (time(0) & 0xF) // cheap-ass random... @@ -985,24 +990,24 @@ public: check = checklevel; } - void OnTick() override + void Start() override { - if (ticks == 1) + if (check > 0 && check != selectedlevelnew) { - if (check > 0 && check != selectedlevelnew) - { - state = finished; - return; // immediately abort if the player selected a different level on the map - } - - check = -1; - StopAllSounds(); - if (edx != -1) - { - playCDtrack(edx + 2, false); - } + state = finished; + return; // immediately abort if the player selected a different level on the map } + check = -1; + StopAllSounds(); + if (edx != -1) + { + playCDtrack(edx + 2, false); + } + } + + void OnTick() override + { if (!cont) { state = finished; @@ -1018,7 +1023,7 @@ public: void Draw(double smoothratio) override { twod->ClearScreen(); - if (check < 0) return; + if (check == 0) return; DrawTexture(twod, tileGetTexture(cinematile), 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, DTA_TranslationIndex, TRANSLATION(Translation_BasePalettes, currentCinemaPalette), TAG_DONE); text.DisplayText(); @@ -1162,14 +1167,14 @@ private: return true; } + void Start() override + { + PlayLocalSound(StaticSound[kSound75], 0, false, CHANF_UI); + phase = 1; + } + void OnTick() override { - if (ticks == 1) - { - PlayLocalSound(StaticSound[kSound75], 0, false, CHANF_UI); - phase = 1; - } - switch (phase) { case 1: @@ -1264,20 +1269,20 @@ public: return true; } + void Start() override + { + if (credits.Size() == 0) + { + state = finished; + return; + } + playCDtrack(19, false); + pagetime = 0; + page = -1; + } + void OnTick() override { - if (ticks == 1) - { - if (credits.Size() == 0) - { - state = finished; - return; - } - playCDtrack(19, false); - pagetime = 0; - page = -1; - } - if (ticks >= pagetime || skiprequest) { page++; diff --git a/source/games/exhumed/src/movie.cpp b/source/games/exhumed/src/movie.cpp index 99a880b98..cb632cc05 100644 --- a/source/games/exhumed/src/movie.cpp +++ b/source/games/exhumed/src/movie.cpp @@ -271,7 +271,6 @@ public: DScreenJob* PlayMovie(const char* fileName) { // clear keys - inputState.ClearAllInput(); auto fp = fileSystem.OpenFileReader(fileName); if (!fp.isOpen()) diff --git a/source/games/sw/src/2d.cpp b/source/games/sw/src/2d.cpp index 8256b0be3..ce85b1bbf 100644 --- a/source/games/sw/src/2d.cpp +++ b/source/games/sw/src/2d.cpp @@ -185,13 +185,14 @@ class DSWCreditsScreen : public DSkippableScreenJob StopSound(); } + void Start() override + { + // Lo Wang feel like singing! + PlaySound(DIGI_JG95012, v3df_none, CHAN_VOICE, CHANF_UI); + } + void OnTick() override { - if (ticks == 1) - { - // Lo Wang feel like singing! - PlaySound(DIGI_JG95012, v3df_none, CHAN_VOICE, CHANF_UI); - } if (state == 0) { if (!soundEngine->IsSourcePlayingSomething(SOURCE_None, nullptr, CHAN_VOICE)) @@ -400,12 +401,13 @@ private: return true; } + void Start() override + { + PlaySong(nullptr, ThemeSongs[1], ThemeTrack[1]); + } + void OnTick() override { - if (ticks == 1) - { - PlaySong(nullptr, ThemeSongs[1], ThemeTrack[1]); - } while (ticks > nextclock) { nextclock++; From 091a9b7fefc3dec398745bee032828de521be60a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 17 Apr 2021 00:01:28 +0200 Subject: [PATCH 25/34] - fixed Exhumed laptop cutscene. --- source/games/exhumed/src/2d.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/source/games/exhumed/src/2d.cpp b/source/games/exhumed/src/2d.cpp index 1dffb4b7d..8606ab507 100644 --- a/source/games/exhumed/src/2d.cpp +++ b/source/games/exhumed/src/2d.cpp @@ -1142,7 +1142,7 @@ private: int yy = ebp; auto p = GStrings["REQUIRED_CHARACTERS"]; - if (1)//p && *p) + if (p && *p) { yy *= 2; for (int i = 0; i < nStringTypeOn; i++, yy += 10) @@ -1179,7 +1179,7 @@ private: { case 1: Phase1(); - if (skiprequest || ticks >= 60) + if (skiprequest || ticks >= nextclock) { InitPhase2(); phase = 2; @@ -1224,6 +1224,19 @@ private: { skiprequest |= !Phase3(); } + if (skiprequest) + { + // Go to the next text page. + if (screencnt != 2) + { + screencnt++; + nextclock = ticks + 60; + skiprequest = 0; + phase = 1; + } + else state = finished; + } + if (skiprequest) { state = finished; From 962e313eb2373ae594d9728ac5dcc20040eb0ae6 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 17 Apr 2021 00:16:18 +0200 Subject: [PATCH 26/34] - fixed screen job fadeout. --- source/core/screenjob.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/core/screenjob.cpp b/source/core/screenjob.cpp index 7845dbbae..02cdd3ede 100644 --- a/source/core/screenjob.cpp +++ b/source/core/screenjob.cpp @@ -202,7 +202,7 @@ public: int FadeoutFrame(double smoothratio) { auto& job = jobs[index]; - double ms = (job.job->ticks + smoothratio) * 1000 / GameTicRate / job.job->fadetime; + double ms = (fadeticks + smoothratio) * 1000 / GameTicRate / job.job->fadetime; float screenfade = 1.f - (float)clamp(ms, 0., 1.); twod->SetScreenFade(screenfade); job.job->DrawFrame(1.); @@ -292,6 +292,7 @@ public: jobs[index].job->fadestate = DScreenJob::fadeout; jobs[index].job->state = DScreenJob::stopping; actionState = State_Fadeout; + fadeticks = 0; } else { From 42b87362ee0b485efe657e7b701f883d30e4cb67 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 17 Apr 2021 09:37:38 +0200 Subject: [PATCH 27/34] - When keeping around a dummy sprite, make sure that the engine's utilities cannot find it anymore. This was causing issues with the master switch sprites in Duke that have to be kept for sound purposes. Unfortunately, both hitscan and neartag are far too dumb to analyze sprites they may hit in any way and needed some help skipping such sprites. --- source/build/include/buildtypes.h | 1 + source/build/src/clip.cpp | 4 ++++ source/build/src/engine.cpp | 2 ++ source/games/duke/src/actors.cpp | 2 +- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/source/build/include/buildtypes.h b/source/build/include/buildtypes.h index d526315a0..1432efd83 100644 --- a/source/build/include/buildtypes.h +++ b/source/build/include/buildtypes.h @@ -152,6 +152,7 @@ enum // Raze extensions, using the higher bits to avoid conflitcs with the reserved and undocumented bits above. CSTAT_SPRITE_MDLROTATE = 1u<<16u, // Only for tsprites: rotate if this is a model or voxel. + CSTAT_SPRITE_NOFIND = 1u<<17u, // Invisible to neartag and hitscan }; enum diff --git a/source/build/src/clip.cpp b/source/build/src/clip.cpp index f8f2fa38e..bedbf0eab 100644 --- a/source/build/src/clip.cpp +++ b/source/build/src/clip.cpp @@ -1428,6 +1428,10 @@ int32_t hitscan(const vec3_t *sv, int16_t sectnum, int32_t vx, int32_t vy, int32 { auto const spr = (uspriteptr_t)&sprite[z]; uint32_t const cstat = spr->cstat; + + if (cstat & CSTAT_SPRITE_NOFIND) + continue; + #ifdef USE_OPENGL if (!hitallsprites) #endif diff --git a/source/build/src/engine.cpp b/source/build/src/engine.cpp index 52648e5d6..f8b3f014d 100644 --- a/source/build/src/engine.cpp +++ b/source/build/src/engine.cpp @@ -2360,6 +2360,8 @@ void neartag(int32_t xs, int32_t ys, int32_t zs, int16_t sectnum, int16_t ange, { auto const spr = (uspriteptr_t)&sprite[z]; + if (spr->cstat & CSTAT_SPRITE_NOFIND) + continue; if (blacklist_sprite_func && blacklist_sprite_func(z)) continue; diff --git a/source/games/duke/src/actors.cpp b/source/games/duke/src/actors.cpp index e2ab87b15..d24915c25 100644 --- a/source/games/duke/src/actors.cpp +++ b/source/games/duke/src/actors.cpp @@ -1014,7 +1014,7 @@ void movemasterswitch(DDukeActor *actor, int spectype1, int spectype2) // This originally depended on undefined behavior as the deleted sprite was still used for the sound // with no checking if it got reused in the mean time. spri->picnum = 0; // give it a picnum without any behavior attached, just in case - spri->cstat |= CSTAT_SPRITE_INVISIBLE; + spri->cstat |= CSTAT_SPRITE_INVISIBLE|CSTAT_SPRITE_NOFIND; changespritestat(actor->GetIndex(), STAT_REMOVED); } } From 839547a9fcf19e273ff72fd1bf833fb2bc73540e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 17 Apr 2021 10:12:40 +0200 Subject: [PATCH 28/34] - Blood: gave FXDATA meaningful member names --- source/games/blood/src/fx.cpp | 58 +++++++++++++++++------------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/source/games/blood/src/fx.cpp b/source/games/blood/src/fx.cpp index 9ee8ec4fe..074b71f03 100644 --- a/source/games/blood/src/fx.cpp +++ b/source/games/blood/src/fx.cpp @@ -32,18 +32,18 @@ CFX gFX; struct FXDATA { CALLBACK_ID funcID; // callback - char at1; // detail - short at2; // seq - short Kills; // flags - int at6; // gravity - int ata; // air drag + uint8_t detail; // detail + short seq; // seq + short flags; // flags + int gravity; // gravity + int drag; // air drag int ate; - short at12; // picnum - unsigned char at14; // xrepeat - unsigned char at15; // yrepeat - short at16; // cstat - signed char at18; // shade - char at19; // pal + short picnum; // picnum + uint8_t xrepeat; // xrepeat + uint8_t yrepeat; // yrepeat + short cstat; // cstat + int8_t shade; // shade + uint8_t pal; // pal }; FXDATA gFXData[] = { @@ -166,23 +166,23 @@ spritetype * CFX::fxSpawn(FX_ID nFx, int nSector, int x, int y, int z, unsigned } spritetype *pSprite = actSpawnSprite(nSector, x, y, z, 1, 0); pSprite->type = nFx; - pSprite->picnum = pFX->at12; - pSprite->cstat |= pFX->at16; - pSprite->shade = pFX->at18; - pSprite->pal = pFX->at19; - sprite[pSprite->index].detail = pFX->at1; - if (pFX->at14 > 0) - pSprite->xrepeat = pFX->at14; - if (pFX->at15 > 0) - pSprite->yrepeat = pFX->at15; - if ((pFX->Kills & 1) && Chance(0x8000)) + pSprite->picnum = pFX->picnum; + pSprite->cstat |= pFX->cstat; + pSprite->shade = pFX->shade; + pSprite->pal = pFX->pal; + sprite[pSprite->index].detail = pFX->detail; + if (pFX->xrepeat > 0) + pSprite->xrepeat = pFX->xrepeat; + if (pFX->yrepeat > 0) + pSprite->yrepeat = pFX->yrepeat; + if ((pFX->flags & 1) && Chance(0x8000)) pSprite->cstat |= 4; - if ((pFX->Kills & 2) && Chance(0x8000)) + if ((pFX->flags & 2) && Chance(0x8000)) pSprite->cstat |= 8; - if (pFX->at2) + if (pFX->seq) { int nXSprite = dbInsertXSprite(pSprite->index); - seqSpawn(pFX->at2, 3, nXSprite, -1); + seqSpawn(pFX->seq, 3, nXSprite, -1); } if (a6 == 0) a6 = pFX->ate; @@ -203,7 +203,7 @@ void CFX::fxProcess(void) assert(nSector >= 0 && nSector < kMaxSectors); assert(pSprite->type < kFXMax); FXDATA *pFXData = &gFXData[pSprite->type]; - actAirDrag(pSprite, pFXData->ata); + actAirDrag(pSprite, pFXData->drag); if (xvel[nSprite]) pSprite->x += xvel[nSprite]>>12; if (yvel[nSprite]) @@ -257,7 +257,7 @@ void CFX::fxProcess(void) continue; } } - zvel[nSprite] += pFXData->at6; + zvel[nSprite] += pFXData->gravity; } } @@ -349,9 +349,9 @@ void fxPrecache() { for (int i = 0; i < kFXMax; i++) { - tilePrecacheTile(gFXData[i].at12, 0, 0); - if (gFXData[i].at2) - seqPrecacheId(gFXData[i].at2, 0); + tilePrecacheTile(gFXData[i].picnum, 0, 0); + if (gFXData[i].seq) + seqPrecacheId(gFXData[i].seq, 0); } } From ada28d8d04a9b054419972068f0f768c96dd1a51 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 17 Apr 2021 10:14:03 +0200 Subject: [PATCH 29/34] - Blood: replaced 'unsigned char' with 'uint8_t' and 'signed char' with 'int8_t'. Preparation for getting rid of all those excessively used plain chars which are a menace to code stability. --- source/games/blood/src/actor.cpp | 2 +- source/games/blood/src/actor.h | 32 +++++++++++++-------------- source/games/blood/src/db.cpp | 2 +- source/games/blood/src/dude.h | 2 +- source/games/blood/src/fire.cpp | 4 ++-- source/games/blood/src/hudsprites.cpp | 4 ++-- source/games/blood/src/levels.h | 4 ++-- source/games/blood/src/misc.h | 2 +- source/games/blood/src/player.h | 2 +- source/games/blood/src/qav.h | 8 +++---- source/games/blood/src/seq.h | 4 ++-- source/games/blood/src/tile.cpp | 2 +- 12 files changed, 34 insertions(+), 34 deletions(-) diff --git a/source/games/blood/src/actor.cpp b/source/games/blood/src/actor.cpp index 364373526..e892cc8db 100644 --- a/source/games/blood/src/actor.cpp +++ b/source/games/blood/src/actor.cpp @@ -6533,7 +6533,7 @@ void actFireVector(spritetype *pShooter, int a2, int a3, int a4, int a5, int a6, int y = gHitInfo.hity-MulScale(a5, 16, 14); int z = gHitInfo.hitz-MulScale(a6, 256, 14); short nSector = gHitInfo.hitsect; - unsigned char nSurf = kSurfNone; + uint8_t nSurf = kSurfNone; if (nRange == 0 || approxDist(gHitInfo.hitx-pShooter->x, gHitInfo.hity-pShooter->y) < nRange) { switch (hit) diff --git a/source/games/blood/src/actor.h b/source/games/blood/src/actor.h index de2f2788c..590927a7b 100644 --- a/source/games/blood/src/actor.h +++ b/source/games/blood/src/actor.h @@ -70,16 +70,16 @@ struct THINGINFO { short startHealth; short mass; - unsigned char clipdist; + uint8_t clipdist; short flags; int elastic; // elasticity int dmgResist; // damage resistance short cstat; short picnum; char shade; - unsigned char pal; - unsigned char xrepeat; // xrepeat - unsigned char yrepeat; // yrepeat + uint8_t pal; + uint8_t xrepeat; // xrepeat + uint8_t yrepeat; // yrepeat int dmgControl[kDamageMax]; // damage }; @@ -89,11 +89,11 @@ struct AMMOITEMDATA short picnum; char shade; char pal; - unsigned char xrepeat; - unsigned char yrepeat; + uint8_t xrepeat; + uint8_t yrepeat; short count; - unsigned char type; - unsigned char weaponType; + uint8_t type; + uint8_t weaponType; }; struct WEAPONITEMDATA @@ -102,8 +102,8 @@ struct WEAPONITEMDATA short picnum; char shade; char pal; - unsigned char xrepeat; - unsigned char yrepeat; + uint8_t xrepeat; + uint8_t yrepeat; short type; short ammoType; short count; @@ -115,8 +115,8 @@ struct ITEMDATA short picnum; char shade; char pal; - unsigned char xrepeat; - unsigned char yrepeat; + uint8_t xrepeat; + uint8_t yrepeat; short packSlot; }; @@ -125,15 +125,15 @@ struct MissileType short picnum; int velocity; int angleOfs; - unsigned char xrepeat; - unsigned char yrepeat; + uint8_t xrepeat; + uint8_t yrepeat; char shade; - unsigned char clipDist; + uint8_t clipDist; }; struct EXPLOSION { - unsigned char repeat; + uint8_t repeat; char dmg; char dmgRng; int radius; diff --git a/source/games/blood/src/db.cpp b/source/games/blood/src/db.cpp index 07d372ab7..9b0d3b362 100644 --- a/source/games/blood/src/db.cpp +++ b/source/games/blood/src/db.cpp @@ -979,7 +979,7 @@ void dbLoadMap(const char *pPath, int *pX, int *pY, int *pZ, short *pAngle, shor fr.Seek(0, FileReader::SeekSet); auto buffer = fr.Read(); - unsigned char md4[16]; + uint8_t md4[16]; md4once(buffer.Data(), buffer.Size(), md4); G_LoadMapHack(mapname, md4); diff --git a/source/games/blood/src/dude.h b/source/games/blood/src/dude.h index dd899dd0f..5bf74b744 100644 --- a/source/games/blood/src/dude.h +++ b/source/games/blood/src/dude.h @@ -30,7 +30,7 @@ struct DUDEINFO { short startHealth; // health unsigned short mass; // mass int at6; // unused? - unsigned char clipdist; // clipdist + uint8_t clipdist; // clipdist int eyeHeight; int aimHeight; // used by just Cerberus int hearDist; // hear radius diff --git a/source/games/blood/src/fire.cpp b/source/games/blood/src/fire.cpp index de4f759cb..9b76b20cd 100644 --- a/source/games/blood/src/fire.cpp +++ b/source/games/blood/src/fire.cpp @@ -109,10 +109,10 @@ void FireProcess(void) void CellularFrame(char *pFrame, int sizeX, int sizeY) { int nSquare = sizeX * sizeY; - unsigned char *pPtr1 = (unsigned char*)pFrame; + uint8_t *pPtr1 = (uint8_t*)pFrame; while (nSquare--) { - unsigned char *pPtr2 = pPtr1+sizeX; + uint8_t *pPtr2 = pPtr1+sizeX; int sum = *(pPtr2-1) + *pPtr2 + *(pPtr2+1) + *(pPtr2+sizeX); if (*(pPtr2+sizeX) > 96) { diff --git a/source/games/blood/src/hudsprites.cpp b/source/games/blood/src/hudsprites.cpp index c570b115d..b7324cdd4 100644 --- a/source/games/blood/src/hudsprites.cpp +++ b/source/games/blood/src/hudsprites.cpp @@ -44,8 +44,8 @@ BEGIN_BLD_NS static struct { short nTile; - unsigned char nStat; - unsigned char nPal; + uint8_t nStat; + uint8_t nPal; int nScale; short nX, nY; } burnTable[9] = { diff --git a/source/games/blood/src/levels.h b/source/games/blood/src/levels.h index ac0be6f78..27d65964d 100644 --- a/source/games/blood/src/levels.h +++ b/source/games/blood/src/levels.h @@ -47,8 +47,8 @@ enum EGameFlag }; struct GAMEOPTIONS { - unsigned char nGameType; - unsigned char nDifficulty; + uint8_t nGameType; + uint8_t nDifficulty; char nMonsterSettings; int uGameFlags; int uNetGameFlags; diff --git a/source/games/blood/src/misc.h b/source/games/blood/src/misc.h index 0a2ad62fa..ca42e1124 100644 --- a/source/games/blood/src/misc.h +++ b/source/games/blood/src/misc.h @@ -115,7 +115,7 @@ enum SurfaceType { }; extern char surfType[MAXTILES]; -extern signed char tileShade[MAXTILES]; +extern int8_t tileShade[MAXTILES]; extern short voxelIndex[MAXTILES]; extern int nPrecacheCount; diff --git a/source/games/blood/src/player.h b/source/games/blood/src/player.h index 84bd5030c..53f4dc4a3 100644 --- a/source/games/blood/src/player.h +++ b/source/games/blood/src/player.h @@ -182,7 +182,7 @@ struct PLAYER struct AMMOINFO { int max; - signed char vectorType; + int8_t vectorType; }; struct POWERUPINFO diff --git a/source/games/blood/src/qav.h b/source/games/blood/src/qav.h index 8b73ca51c..9c1cdde93 100644 --- a/source/games/blood/src/qav.h +++ b/source/games/blood/src/qav.h @@ -46,7 +46,7 @@ struct TILE_FRAME int y; int z; int stat; - signed char shade; + int8_t shade; char palnum; unsigned short angle; }; @@ -54,9 +54,9 @@ struct TILE_FRAME struct SOUNDINFO { int sound; - unsigned char priority; - unsigned char sndFlags; // (by NoOne) Various sound flags - unsigned char sndRange; // (by NoOne) Random sound range + uint8_t priority; + uint8_t sndFlags; // (by NoOne) Various sound flags + uint8_t sndRange; // (by NoOne) Random sound range char reserved[1]; }; diff --git a/source/games/blood/src/seq.h b/source/games/blood/src/seq.h index 724f5b081..7e0baed6f 100644 --- a/source/games/blood/src/seq.h +++ b/source/games/blood/src/seq.h @@ -74,7 +74,7 @@ struct Seq { struct ACTIVE { - unsigned char type; + uint8_t type; unsigned short xindex; }; @@ -86,7 +86,7 @@ struct SEQINST int nSeqID; int callback; short timeCounter; - unsigned char frameIndex; + uint8_t frameIndex; void Update(); }; diff --git a/source/games/blood/src/tile.cpp b/source/games/blood/src/tile.cpp index ac46809d1..0eff626e5 100644 --- a/source/games/blood/src/tile.cpp +++ b/source/games/blood/src/tile.cpp @@ -41,7 +41,7 @@ int tileEnd[256]; int hTileFile[256]; char surfType[kMaxTiles]; -signed char tileShade[kMaxTiles]; +int8_t tileShade[kMaxTiles]; short voxelIndex[kMaxTiles]; const char *pzBaseFileName = "TILES%03i.ART"; //"TILES%03i.ART"; From 9828b0228e1f82b3097e100ad9e1363abc5b76dd Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 17 Apr 2021 10:22:00 +0200 Subject: [PATCH 30/34] - made type of shade variables consistent. Some were char, some signed char and the initializers needed type casts. This wasn't serious but created a lot of casting noise. --- source/games/blood/src/actor.cpp | 268 +++++++++++++++---------------- source/games/blood/src/actor.h | 16 +- 2 files changed, 142 insertions(+), 142 deletions(-) diff --git a/source/games/blood/src/actor.cpp b/source/games/blood/src/actor.cpp index e892cc8db..28bf6f1fe 100644 --- a/source/games/blood/src/actor.cpp +++ b/source/games/blood/src/actor.cpp @@ -662,7 +662,7 @@ const ITEMDATA gItemData[] = { { 0, 2552, - (char)-8, + -8, 0, 32, 32, @@ -671,7 +671,7 @@ const ITEMDATA gItemData[] = { { 0, 2553, - (char)-8, + -8, 0, 32, 32, @@ -680,7 +680,7 @@ const ITEMDATA gItemData[] = { { 0, 2554, - (char)-8, + -8, 0, 32, 32, @@ -689,7 +689,7 @@ const ITEMDATA gItemData[] = { { 0, 2555, - (char)-8, + -8, 0, 32, 32, @@ -698,7 +698,7 @@ const ITEMDATA gItemData[] = { { 0, 2556, - (char)-8, + -8, 0, 32, 32, @@ -707,7 +707,7 @@ const ITEMDATA gItemData[] = { { 0, 2557, - (char)-8, + -8, 0, 32, 32, @@ -716,7 +716,7 @@ const ITEMDATA gItemData[] = { { 0, -1, - (char)-8, + -8, 0, 255, 255, @@ -725,7 +725,7 @@ const ITEMDATA gItemData[] = { { 0, 519, - (char)-8, + -8, 0, 48, 48, @@ -734,7 +734,7 @@ const ITEMDATA gItemData[] = { { 0, 822, - (char)-8, + -8, 0, 40, 40, @@ -743,7 +743,7 @@ const ITEMDATA gItemData[] = { { 0, 2169, - (char)-8, + -8, 0, 40, 40, @@ -752,7 +752,7 @@ const ITEMDATA gItemData[] = { { 0, 2433, - (char)-8, + -8, 0, 40, 40, @@ -761,7 +761,7 @@ const ITEMDATA gItemData[] = { { 0, 517, - (char)-8, + -8, 0, 40, 40, @@ -770,7 +770,7 @@ const ITEMDATA gItemData[] = { { 0, 783, - (char)-8, + -8, 0, 40, 40, @@ -779,7 +779,7 @@ const ITEMDATA gItemData[] = { { 0, 896, - (char)-8, + -8, 0, 40, 40, @@ -788,7 +788,7 @@ const ITEMDATA gItemData[] = { { 0, 825, - (char)-8, + -8, 0, 40, 40, @@ -797,7 +797,7 @@ const ITEMDATA gItemData[] = { { 0, 827, - (char)-8, + -8, 0, 40, 40, @@ -806,7 +806,7 @@ const ITEMDATA gItemData[] = { { 0, 828, - (char)-8, + -8, 0, 40, 40, @@ -815,7 +815,7 @@ const ITEMDATA gItemData[] = { { 0, 829, - (char)-8, + -8, 0, 40, 40, @@ -824,7 +824,7 @@ const ITEMDATA gItemData[] = { { 0, 830, - (char)-8, + -8, 0, 80, 64, @@ -833,7 +833,7 @@ const ITEMDATA gItemData[] = { { 0, 831, - (char)-8, + -8, 0, 40, 40, @@ -842,7 +842,7 @@ const ITEMDATA gItemData[] = { { 0, 863, - (char)-8, + -8, 0, 40, 40, @@ -851,7 +851,7 @@ const ITEMDATA gItemData[] = { { 0, 760, - (char)-8, + -8, 0, 40, 40, @@ -860,7 +860,7 @@ const ITEMDATA gItemData[] = { { 0, 836, - (char)-8, + -8, 0, 40, 40, @@ -869,7 +869,7 @@ const ITEMDATA gItemData[] = { { 0, 851, - (char)-8, + -8, 0, 40, 40, @@ -878,7 +878,7 @@ const ITEMDATA gItemData[] = { { 0, 2428, - (char)-8, + -8, 0, 40, 40, @@ -887,7 +887,7 @@ const ITEMDATA gItemData[] = { { 0, 839, - (char)-8, + -8, 0, 40, 40, @@ -896,7 +896,7 @@ const ITEMDATA gItemData[] = { { 0, 768, - (char)-8, + -8, 0, 64, 64, @@ -905,7 +905,7 @@ const ITEMDATA gItemData[] = { { 0, 840, - (char)-8, + -8, 0, 48, 48, @@ -914,7 +914,7 @@ const ITEMDATA gItemData[] = { { 0, 841, - (char)-8, + -8, 0, 48, 48, @@ -923,7 +923,7 @@ const ITEMDATA gItemData[] = { { 0, 842, - (char)-8, + -8, 0, 48, 48, @@ -932,7 +932,7 @@ const ITEMDATA gItemData[] = { { 0, 843, - (char)-8, + -8, 0, 48, 48, @@ -941,7 +941,7 @@ const ITEMDATA gItemData[] = { { 0, 683, - (char)-8, + -8, 0, 40, 40, @@ -950,7 +950,7 @@ const ITEMDATA gItemData[] = { { 0, 521, - (char)-8, + -8, 0, 40, 40, @@ -959,7 +959,7 @@ const ITEMDATA gItemData[] = { { 0, 604, - (char)-8, + -8, 0, 40, 40, @@ -968,7 +968,7 @@ const ITEMDATA gItemData[] = { { 0, 520, - (char)-8, + -8, 0, 40, 40, @@ -977,7 +977,7 @@ const ITEMDATA gItemData[] = { { 0, 803, - (char)-8, + -8, 0, 40, 40, @@ -986,7 +986,7 @@ const ITEMDATA gItemData[] = { { 0, 518, - (char)-8, + -8, 0, 40, 40, @@ -995,7 +995,7 @@ const ITEMDATA gItemData[] = { { 0, 522, - (char)-8, + -8, 0, 40, 40, @@ -1004,7 +1004,7 @@ const ITEMDATA gItemData[] = { { 0, 523, - (char)-8, + -8, 0, 40, 40, @@ -1013,7 +1013,7 @@ const ITEMDATA gItemData[] = { { 0, 837, - (char)-8, + -8, 0, 80, 64, @@ -1022,7 +1022,7 @@ const ITEMDATA gItemData[] = { { 0, 2628, - (char)-8, + -8, 0, 64, 64, @@ -1031,7 +1031,7 @@ const ITEMDATA gItemData[] = { { 0, 2586, - (char)-8, + -8, 0, 64, 64, @@ -1040,7 +1040,7 @@ const ITEMDATA gItemData[] = { { 0, 2578, - (char)-8, + -8, 0, 64, 64, @@ -1049,7 +1049,7 @@ const ITEMDATA gItemData[] = { { 0, 2602, - (char)-8, + -8, 0, 64, 64, @@ -1058,7 +1058,7 @@ const ITEMDATA gItemData[] = { { 0, 2594, - (char)-8, + -8, 0, 64, 64, @@ -1067,7 +1067,7 @@ const ITEMDATA gItemData[] = { { 0, 753, - (char)-8, + -8, 0, 64, 64, @@ -1076,7 +1076,7 @@ const ITEMDATA gItemData[] = { { 0, 753, - (char)-8, + -8, 7, 64, 64, @@ -1085,7 +1085,7 @@ const ITEMDATA gItemData[] = { { 0, 3558, - (char)-128, + -128, 0, 64, 64, @@ -1094,7 +1094,7 @@ const ITEMDATA gItemData[] = { { 0, 3558, - (char)-128, + -128, 7, 64, 64, @@ -1106,7 +1106,7 @@ const AMMOITEMDATA gAmmoItemData[] = { { 0, 618, - (char)-8, + -8, 0, 40, 40, @@ -1117,7 +1117,7 @@ const AMMOITEMDATA gAmmoItemData[] = { { 0, 589, - (char)-8, + -8, 0, 48, 48, @@ -1128,7 +1128,7 @@ const AMMOITEMDATA gAmmoItemData[] = { { 0, 589, - (char)-8, + -8, 0, 48, 48, @@ -1139,7 +1139,7 @@ const AMMOITEMDATA gAmmoItemData[] = { { 0, 809, - (char)-8, + -8, 0, 48, 48, @@ -1150,7 +1150,7 @@ const AMMOITEMDATA gAmmoItemData[] = { { 0, 811, - (char)-8, + -8, 0, 48, 48, @@ -1161,7 +1161,7 @@ const AMMOITEMDATA gAmmoItemData[] = { { 0, 810, - (char)-8, + -8, 0, 48, 48, @@ -1172,7 +1172,7 @@ const AMMOITEMDATA gAmmoItemData[] = { { 0, 820, - (char)-8, + -8, 0, 24, 24, @@ -1183,7 +1183,7 @@ const AMMOITEMDATA gAmmoItemData[] = { { 0, 619, - (char)-8, + -8, 0, 48, 48, @@ -1194,7 +1194,7 @@ const AMMOITEMDATA gAmmoItemData[] = { { 0, 812, - (char)-8, + -8, 0, 48, 48, @@ -1205,7 +1205,7 @@ const AMMOITEMDATA gAmmoItemData[] = { { 0, 813, - (char)-8, + -8, 0, 48, 48, @@ -1216,7 +1216,7 @@ const AMMOITEMDATA gAmmoItemData[] = { { 0, 525, - (char)-8, + -8, 0, 48, 48, @@ -1227,7 +1227,7 @@ const AMMOITEMDATA gAmmoItemData[] = { { 0, 814, - (char)-8, + -8, 0, 48, 48, @@ -1238,7 +1238,7 @@ const AMMOITEMDATA gAmmoItemData[] = { { 0, 817, - (char)-8, + -8, 0, 48, 48, @@ -1249,7 +1249,7 @@ const AMMOITEMDATA gAmmoItemData[] = { { 0, 548, - (char)-8, + -8, 0, 24, 24, @@ -1260,7 +1260,7 @@ const AMMOITEMDATA gAmmoItemData[] = { { 0, 0, - (char)-8, + -8, 0, 48, 48, @@ -1271,7 +1271,7 @@ const AMMOITEMDATA gAmmoItemData[] = { { 0, 0, - (char)-8, + -8, 0, 48, 48, @@ -1282,7 +1282,7 @@ const AMMOITEMDATA gAmmoItemData[] = { { 0, 816, - (char)-8, + -8, 0, 48, 48, @@ -1293,7 +1293,7 @@ const AMMOITEMDATA gAmmoItemData[] = { { 0, 818, - (char)-8, + -8, 0, 48, 48, @@ -1304,7 +1304,7 @@ const AMMOITEMDATA gAmmoItemData[] = { { 0, 819, - (char)-8, + -8, 0, 48, 48, @@ -1315,7 +1315,7 @@ const AMMOITEMDATA gAmmoItemData[] = { { 0, 801, - (char)-8, + -8, 0, 48, 48, @@ -1340,7 +1340,7 @@ const WEAPONITEMDATA gWeaponItemData[] = { { 0, -1, - (char)0, + 0, 0, 0, 0, @@ -1351,7 +1351,7 @@ const WEAPONITEMDATA gWeaponItemData[] = { { 0, 559, - (char)-8, + -8, 0, 48, 48, @@ -1362,7 +1362,7 @@ const WEAPONITEMDATA gWeaponItemData[] = { { 0, 558, - (char)-8, + -8, 0, 48, 48, @@ -1373,7 +1373,7 @@ const WEAPONITEMDATA gWeaponItemData[] = { { 0, 524, - (char)-8, + -8, 0, 48, 48, @@ -1384,7 +1384,7 @@ const WEAPONITEMDATA gWeaponItemData[] = { { 0, 525, - (char)-8, + -8, 0, 48, 48, @@ -1395,7 +1395,7 @@ const WEAPONITEMDATA gWeaponItemData[] = { { 0, 539, - (char)-8, + -8, 0, 48, 48, @@ -1406,7 +1406,7 @@ const WEAPONITEMDATA gWeaponItemData[] = { { 0, 526, - (char)-8, + -8, 0, 48, 48, @@ -1417,7 +1417,7 @@ const WEAPONITEMDATA gWeaponItemData[] = { { 0, -1, - (char)0, + 0, 0, 0, 0, @@ -1428,7 +1428,7 @@ const WEAPONITEMDATA gWeaponItemData[] = { { 0, 618, - (char)-8, + -8, 0, 48, 48, @@ -1439,7 +1439,7 @@ const WEAPONITEMDATA gWeaponItemData[] = { { 0, 589, - (char)-8, + -8, 0, 48, 48, @@ -1450,7 +1450,7 @@ const WEAPONITEMDATA gWeaponItemData[] = { { 0, 800, - (char)-8, + -8, 0, 48, 48, @@ -1468,7 +1468,7 @@ const MissileType missileInfo[] = { 512, 40, 40, - (char)-16, + -16, 16, }, // Regular flare @@ -1478,7 +1478,7 @@ const MissileType missileInfo[] = { 0, 32, 32, - (char)-128, + -128, 32, }, // Tesla alt @@ -1488,7 +1488,7 @@ const MissileType missileInfo[] = { 0, 32, 32, - (char)-128, + -128, 32, }, // Flare alt @@ -1498,7 +1498,7 @@ const MissileType missileInfo[] = { 0, 32, 32, - (char)-128, + -128, 4, }, // Spray flame @@ -1508,7 +1508,7 @@ const MissileType missileInfo[] = { 0, 24, 24, - (char)-128, + -128, 16, }, // Fireball @@ -1518,7 +1518,7 @@ const MissileType missileInfo[] = { 0, 32, 32, - (char)-128, + -128, 32, }, // Tesla regular @@ -1528,7 +1528,7 @@ const MissileType missileInfo[] = { 0, 32, 32, - (char)-128, + -128, 16, }, // EctoSkull @@ -1538,7 +1538,7 @@ const MissileType missileInfo[] = { 0, 32, 32, - (char)-24, + -24, 32, }, // Hellhound flame @@ -1548,7 +1548,7 @@ const MissileType missileInfo[] = { 0, 24, 24, - (char)-128, + -128, 16, }, // Puke @@ -1558,7 +1558,7 @@ const MissileType missileInfo[] = { 0, 16, 16, - (char)-16, + -16, 16, }, // Reserved @@ -1568,7 +1568,7 @@ const MissileType missileInfo[] = { 0, 8, 8, - (char)0, + 0, 16, }, // Stone gargoyle projectile @@ -1578,7 +1578,7 @@ const MissileType missileInfo[] = { 0, 32, 32, - (char)-128, + -128, 16, }, // Napalm launcher @@ -1588,7 +1588,7 @@ const MissileType missileInfo[] = { 0, 30, 30, - (char)-128, + -128, 24, }, // Cerberus fireball @@ -1598,7 +1598,7 @@ const MissileType missileInfo[] = { 0, 30, 30, - (char)-128, + -128, 24, }, // Tchernobog fireball @@ -1608,7 +1608,7 @@ const MissileType missileInfo[] = { 0, 24, 24, - (char)-128, + -128, 16, }, // Regular life leech @@ -1618,7 +1618,7 @@ const MissileType missileInfo[] = { 0, 32, 32, - (char)-128, + -128, 16, }, // Dropped life leech (enough ammo) @@ -1628,7 +1628,7 @@ const MissileType missileInfo[] = { 0, 16, 16, - (char)-128, + -128, 16, }, // Dropped life leech (no ammo) @@ -1638,7 +1638,7 @@ const MissileType missileInfo[] = { 0, 32, 32, - (char)-128, + -128, 16, } }; @@ -1654,7 +1654,7 @@ const THINGINFO thingInfo[] = { 80, 384, 907, - (char)0, + 0, 0, 0, 0, @@ -1671,7 +1671,7 @@ const THINGINFO thingInfo[] = { 1600, 256, 3444, - (char)-16, + -16, 0, 32, 32, @@ -1687,7 +1687,7 @@ const THINGINFO thingInfo[] = { 1600, 256, 3457, - (char)-16, + -16, 0, 32, 32, @@ -1703,7 +1703,7 @@ const THINGINFO thingInfo[] = { 80, 0, 739, - (char)0, + 0, 0, 0, 0, @@ -1719,7 +1719,7 @@ const THINGINFO thingInfo[] = { 80, 0, 642, - (char)0, + 0, 0, 0, 0, @@ -1735,7 +1735,7 @@ const THINGINFO thingInfo[] = { 0, 0, 462, - (char)0, + 0, 0, 0, 0, @@ -1751,7 +1751,7 @@ const THINGINFO thingInfo[] = { 0, 0, 266, - (char)0, + 0, 0, 0, 0, @@ -1767,7 +1767,7 @@ const THINGINFO thingInfo[] = { 0, 0, 796, - (char)0, + 0, 0, 0, 0, @@ -1783,7 +1783,7 @@ const THINGINFO thingInfo[] = { 0, 0, 1127, - (char)0, + 0, 0, 0, 0, @@ -1799,7 +1799,7 @@ const THINGINFO thingInfo[] = { 0, 0, 1142, - (char)0, + 0, 0, 0, 0, @@ -1815,7 +1815,7 @@ const THINGINFO thingInfo[] = { 0, 0, 1069, - (char)0, + 0, 0, 0, 0, @@ -1831,7 +1831,7 @@ const THINGINFO thingInfo[] = { 0, 0, 483, - (char)0, + 0, 0, 0, 0, @@ -1847,7 +1847,7 @@ const THINGINFO thingInfo[] = { 0, 0, -1, - (char)0, + 0, 0, 0, 0, @@ -1863,7 +1863,7 @@ const THINGINFO thingInfo[] = { 0, 0, -1, - (char)0, + 0, 0, 0, 0, @@ -1879,7 +1879,7 @@ const THINGINFO thingInfo[] = { 0, 0, -1, - (char)0, + 0, 0, 0, 0, @@ -1895,7 +1895,7 @@ const THINGINFO thingInfo[] = { 0, 0, -1, - (char)0, + 0, 0, 0, 0, @@ -1911,7 +1911,7 @@ const THINGINFO thingInfo[] = { 0, 0, -1, - (char)0, + 0, 0, 0, 0, @@ -1927,7 +1927,7 @@ const THINGINFO thingInfo[] = { 0, 0, -1, - (char)0, + 0, 0, 0, 0, @@ -1943,7 +1943,7 @@ const THINGINFO thingInfo[] = { 1600, 256, 3422, - (char)-32, + -32, 0, 32, 32, @@ -1959,7 +1959,7 @@ const THINGINFO thingInfo[] = { 1600, 256, 3433, - (char)-32, + -32, 0, 32, 32, @@ -1975,7 +1975,7 @@ const THINGINFO thingInfo[] = { 1600, 256, 3467, - (char)-128, + -128, 0, 32, 32, @@ -1991,7 +1991,7 @@ const THINGINFO thingInfo[] = { 1600, 256, 1462, - (char)0, + 0, 0, 32, 32, @@ -2007,7 +2007,7 @@ const THINGINFO thingInfo[] = { 1600, 256, -1, - (char)0, + 0, 0, 0, 0, @@ -2023,7 +2023,7 @@ const THINGINFO thingInfo[] = { 0, 0, 1147, - (char)0, + 0, 10, 0, 0, @@ -2039,7 +2039,7 @@ const THINGINFO thingInfo[] = { 0, 0, 1160, - (char)0, + 0, 2, 0, 0, @@ -2055,7 +2055,7 @@ const THINGINFO thingInfo[] = { 0, 257, -1, - (char)0, + 0, 0, 0, 0, @@ -2071,7 +2071,7 @@ const THINGINFO thingInfo[] = { 0, 257, -1, - (char)0, + 0, 0, 0, 0, @@ -2087,7 +2087,7 @@ const THINGINFO thingInfo[] = { 1280, 257, 3405, - (char)0, + 0, 0, 40, 40, @@ -2103,7 +2103,7 @@ const THINGINFO thingInfo[] = { 1600, 256, 3281, - (char)-128, + -128, 0, 32, 32, @@ -2119,7 +2119,7 @@ const THINGINFO thingInfo[] = { 1600, 256, 2020, - (char)-128, + -128, 0, 32, 32, @@ -2135,7 +2135,7 @@ const THINGINFO thingInfo[] = { 1600, 256, 1860, - (char)-128, + -128, 0, 32, 32, @@ -2151,7 +2151,7 @@ const THINGINFO thingInfo[] = { 1600, 257, 800, - (char)-128, + -128, 0, 48, 48, @@ -2167,7 +2167,7 @@ const THINGINFO thingInfo[] = { 1600, 0, 2443, - (char)-128, + -128, 0, 16, 16, @@ -2183,7 +2183,7 @@ const THINGINFO thingInfo[] = { 1600, 256, 3444, - (char)-16, + -16, 7, 32, 32, @@ -2199,7 +2199,7 @@ const THINGINFO thingInfo[] = { 1600, 256, 1462, - (char)0, + 0, 0, 32, 32, @@ -2215,7 +2215,7 @@ const THINGINFO thingInfo[] = { 1600, 257, 800, - (char)-128, + -128, 0, 44, 44, diff --git a/source/games/blood/src/actor.h b/source/games/blood/src/actor.h index 590927a7b..28a80be2c 100644 --- a/source/games/blood/src/actor.h +++ b/source/games/blood/src/actor.h @@ -76,7 +76,7 @@ struct THINGINFO int dmgResist; // damage resistance short cstat; short picnum; - char shade; + int8_t shade; uint8_t pal; uint8_t xrepeat; // xrepeat uint8_t yrepeat; // yrepeat @@ -87,8 +87,8 @@ struct AMMOITEMDATA { short cstat; short picnum; - char shade; - char pal; + int8_t shade; + uint8_t pal; uint8_t xrepeat; uint8_t yrepeat; short count; @@ -100,8 +100,8 @@ struct WEAPONITEMDATA { short cstat; short picnum; - char shade; - char pal; + int8_t shade; + uint8_t pal; uint8_t xrepeat; uint8_t yrepeat; short type; @@ -113,8 +113,8 @@ struct ITEMDATA { short cstat; short picnum; - char shade; - char pal; + int8_t shade; + uint8_t pal; uint8_t xrepeat; uint8_t yrepeat; short packSlot; @@ -127,7 +127,7 @@ struct MissileType int angleOfs; uint8_t xrepeat; uint8_t yrepeat; - char shade; + int8_t shade; uint8_t clipDist; }; From 0cdb7a53ce4dac1114b503177413effe53a83102 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 17 Apr 2021 10:34:12 +0200 Subject: [PATCH 31/34] - more char removal - mostly weapon.cpp --- source/games/blood/src/misc.h | 2 +- source/games/blood/src/weapon.cpp | 46 +++++++++++++++---------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/source/games/blood/src/misc.h b/source/games/blood/src/misc.h index ca42e1124..b10ac1616 100644 --- a/source/games/blood/src/misc.h +++ b/source/games/blood/src/misc.h @@ -50,7 +50,7 @@ void WeaponInit(void); void WeaponDraw(PLAYER *pPlayer, int a2, double a3, double a4, int a5, int smoothratio); void WeaponRaise(PLAYER *pPlayer); void WeaponLower(PLAYER *pPlayer); -char WeaponUpgrade(PLAYER *pPlayer, char newWeapon); +int WeaponUpgrade(PLAYER *pPlayer, int newWeapon); void WeaponProcess(PLAYER *pPlayer); void WeaponUpdateState(PLAYER* pPlayer); void teslaHit(spritetype *pMissile, int a2); diff --git a/source/games/blood/src/weapon.cpp b/source/games/blood/src/weapon.cpp index 8e168f2ff..86cffff6a 100644 --- a/source/games/blood/src/weapon.cpp +++ b/source/games/blood/src/weapon.cpp @@ -144,7 +144,7 @@ enum QAV *weaponQAV[kQAVEnd]; -char sub_4B1A4(PLAYER *pPlayer) +static bool sub_4B1A4(PLAYER *pPlayer) { switch (pPlayer->curWeapon) { @@ -169,12 +169,12 @@ char sub_4B1A4(PLAYER *pPlayer) return 0; } -char BannedUnderwater(int nWeapon) +static bool BannedUnderwater(int nWeapon) { return nWeapon == 7 || nWeapon == 6; } -char CheckWeaponAmmo(PLAYER *pPlayer, int weapon, int ammotype, int count) +static bool CheckWeaponAmmo(PLAYER *pPlayer, int weapon, int ammotype, int count) { if (gInfiniteAmmo) return 1; @@ -187,7 +187,7 @@ char CheckWeaponAmmo(PLAYER *pPlayer, int weapon, int ammotype, int count) return pPlayer->ammoCount[ammotype] >= count; } -char CheckAmmo(PLAYER *pPlayer, int ammotype, int count) +static bool CheckAmmo(PLAYER *pPlayer, int ammotype, int count) { if (gInfiniteAmmo) return 1; @@ -200,7 +200,7 @@ char CheckAmmo(PLAYER *pPlayer, int ammotype, int count) return pPlayer->ammoCount[ammotype] >= count; } -char checkAmmo2(PLAYER *pPlayer, int ammotype, int amount) +static bool checkAmmo2(PLAYER *pPlayer, int ammotype, int amount) { if (gInfiniteAmmo) return 1; @@ -1735,7 +1735,7 @@ void FireBeast(int nTrigger, PLAYER * pPlayer) actFireVector(pPlayer->pSprite, 0, pPlayer->zWeapon-pPlayer->pSprite->z, pPlayer->aim.dx+r1, pPlayer->aim.dy+r2, pPlayer->aim.dz+r3, VECTOR_TYPE_9); } -char gWeaponUpgrade[][13] = { +uint8_t gWeaponUpgrade[][13] = { { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, @@ -1751,9 +1751,9 @@ char gWeaponUpgrade[][13] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, }; -char WeaponUpgrade(PLAYER *pPlayer, char newWeapon) +int WeaponUpgrade(PLAYER *pPlayer, int newWeapon) { - char weapon = pPlayer->curWeapon; + int weapon = pPlayer->curWeapon; if (!sub_4B1A4(pPlayer) && (cl_weaponswitch&1) && (gWeaponUpgrade[pPlayer->curWeapon][newWeapon] || (cl_weaponswitch&2))) weapon = newWeapon; return weapon; @@ -1762,7 +1762,7 @@ char WeaponUpgrade(PLAYER *pPlayer, char newWeapon) int OrderNext[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 1 }; int OrderPrev[] = { 12, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1 }; -char WeaponFindNext(PLAYER *pPlayer, int *a2, char bDir) +static int WeaponFindNext(PLAYER *pPlayer, int *a2, int bDir) { int weapon = pPlayer->curWeapon; do @@ -1795,9 +1795,9 @@ char WeaponFindNext(PLAYER *pPlayer, int *a2, char bDir) return weapon; } -char WeaponFindLoaded(PLAYER *pPlayer, int *a2) +static int WeaponFindLoaded(PLAYER *pPlayer, int *a2) { - char v4 = 1; + int v4 = 1; int v14 = 0; if (weaponModes[pPlayer->curWeapon].update > 1) { @@ -1874,7 +1874,7 @@ int processSprayCan(PLAYER *pPlayer) return 0; } -char processTNT(PLAYER *pPlayer) +static bool processTNT(PLAYER *pPlayer) { switch (pPlayer->weaponState) { @@ -1912,7 +1912,7 @@ char processTNT(PLAYER *pPlayer) return 0; } -char processProxy(PLAYER *pPlayer) +static bool processProxy(PLAYER *pPlayer) { switch (pPlayer->weaponState) { @@ -1929,7 +1929,7 @@ char processProxy(PLAYER *pPlayer) return 0; } -char processRemote(PLAYER *pPlayer) +static bool processRemote(PLAYER *pPlayer) { switch (pPlayer->weaponState) { @@ -1945,7 +1945,7 @@ char processRemote(PLAYER *pPlayer) return 0; } -char processLeech(PLAYER *pPlayer) +static bool processLeech(PLAYER *pPlayer) { switch (pPlayer->weaponState) { @@ -1969,7 +1969,7 @@ char processLeech(PLAYER *pPlayer) return 0; } -char processTesla(PLAYER *pPlayer) +static bool processTesla(PLAYER *pPlayer) { switch (pPlayer->weaponState) { @@ -2109,7 +2109,7 @@ void WeaponProcess(PLAYER *pPlayer) { } pPlayer->nextWeapon = 0; int t; - char weapon = WeaponFindNext(pPlayer, &t, 1); + int weapon = WeaponFindNext(pPlayer, &t, 1); pPlayer->weaponMode[weapon] = t; if (VanillaMode()) { @@ -2131,7 +2131,7 @@ void WeaponProcess(PLAYER *pPlayer) { } pPlayer->nextWeapon = 0; int t; - char weapon = WeaponFindNext(pPlayer, &t, 0); + int weapon = WeaponFindNext(pPlayer, &t, 0); pPlayer->weaponMode[weapon] = t; if (VanillaMode()) { @@ -2146,7 +2146,7 @@ void WeaponProcess(PLAYER *pPlayer) { } else if (pPlayer->input.getNewWeapon() == WeaponSel_Alt) { - char weapon; + int weapon; switch (pPlayer->curWeapon) { @@ -2189,7 +2189,7 @@ void WeaponProcess(PLAYER *pPlayer) { { pPlayer->weaponState = 0; int t; - char weapon = WeaponFindLoaded(pPlayer, &t); + int weapon = WeaponFindLoaded(pPlayer, &t); pPlayer->weaponMode[weapon] = t; if (pPlayer->curWeapon) { @@ -2263,7 +2263,7 @@ void WeaponProcess(PLAYER *pPlayer) { { pPlayer->weaponState = 0; int t; - char weapon = WeaponFindLoaded(pPlayer, &t); + int weapon = WeaponFindLoaded(pPlayer, &t); pPlayer->weaponMode[weapon] = t; if (pPlayer->curWeapon) { @@ -2597,11 +2597,11 @@ void teslaHit(spritetype *pMissile, int a2) int nSector = pMissile->sectnum; int nOwner = pMissile->owner; GetClosestSpriteSectors(nSector, x, y, nDist, va4); - char v4 = 1; + bool v4 = true; int v24 = -1; actHitcodeToData(a2, &gHitInfo, &v24, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (a2 == 3 && v24 >= 0 && sprite[v24].statnum == kStatDude) - v4 = 0; + v4 = false; int nSprite; StatIterator it(kStatDude); while ((nSprite = it.NextIndex()) >= 0) From d2c9b5979d7de4d6f5a756664184168a98af829b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 17 Apr 2021 12:05:37 +0200 Subject: [PATCH 32/34] - gave key 7 a proper spawn record using the blue outline as image. A proper definition here is needed to allow dropping this item. The original code had a picnum of -1 here which caused crashes. --- source/games/blood/src/actor.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/games/blood/src/actor.cpp b/source/games/blood/src/actor.cpp index 28bf6f1fe..f78571942 100644 --- a/source/games/blood/src/actor.cpp +++ b/source/games/blood/src/actor.cpp @@ -715,11 +715,11 @@ const ITEMDATA gItemData[] = { }, { 0, - -1, + 2558, -8, 0, - 255, - 255, + 32, + 32, -1, }, { From cd58b1d055ba86a85b1fa8c5ddec65b02d964fea Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 17 Apr 2021 12:40:23 +0200 Subject: [PATCH 33/34] - made the tile size getters a bit more robust. They should not crash on invalid sprites. --- source/core/textures/buildtiles.cpp | 2 +- source/core/textures/buildtiles.h | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/source/core/textures/buildtiles.cpp b/source/core/textures/buildtiles.cpp index 5a4c39554..6d2d6ec7a 100644 --- a/source/core/textures/buildtiles.cpp +++ b/source/core/textures/buildtiles.cpp @@ -820,7 +820,7 @@ void tileUpdateAnimations() { for (int i = 0; i < MAXTILES; i++) { - if (picanm[i].sf & PICANM_ANIMTYPE_MASK) + if (TileFiles.tiledata[i].picanm.sf & PICANM_ANIMTYPE_MASK) { int j = i + animateoffs(i, 0); diff --git a/source/core/textures/buildtiles.h b/source/core/textures/buildtiles.h index c875f7084..28dab021b 100644 --- a/source/core/textures/buildtiles.h +++ b/source/core/textures/buildtiles.h @@ -407,25 +407,29 @@ extern PicAnm picanm; inline int tileWidth(int num) { - assert(num < MAXTILES); + assert((unsigned)num < MAXTILES); + if ((unsigned)num >= MAXTILES) return 1; return (int)TileFiles.tiledata[num].texture->GetDisplayWidth(); } inline int tileHeight(int num) { - assert(num < MAXTILES); + assert((unsigned)num < MAXTILES); + if ((unsigned)num >= MAXTILES) return 1; return (int)TileFiles.tiledata[num].texture->GetDisplayHeight(); } inline int tileLeftOffset(int num) { - assert(num < MAXTILES); + assert((unsigned)num < MAXTILES); + if ((unsigned)num >= MAXTILES) return 0; return (int)TileFiles.tiledata[num].texture->GetDisplayLeftOffset(); } inline int tileTopOffset(int num) { - assert(num < MAXTILES); + assert((unsigned)num < MAXTILES); + if ((unsigned)num >= MAXTILES) return 0; return (int)TileFiles.tiledata[num].texture->GetDisplayTopOffset(); } @@ -440,11 +444,11 @@ int32_t animateoffs(int const tilenum, int fakevar); inline FGameTexture* tileGetTexture(int tile, bool animate = false) { - assert(tile < MAXTILES); + assert((unsigned)tile < MAXTILES); if (tile < 0 || tile >= MAXTILES) return nullptr; if (animate) { - if (picanm[tile].sf & PICANM_ANIMTYPE_MASK) + if (TileFiles.tiledata[tile].picanm.sf & PICANM_ANIMTYPE_MASK) tile += animateoffs(tile, 0); } From 53cd8958ae18c348104f9627ab782a1f7d078bd7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 17 Apr 2021 13:11:02 +0200 Subject: [PATCH 34/34] - added a fallback generic record for identifying Blood.rff based on content. This is for loading mods that have been set up to require running BARF before they can be used. Strict CRC identification does not work for these. --- wadsrc/static/engine/grpinfo.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/wadsrc/static/engine/grpinfo.txt b/wadsrc/static/engine/grpinfo.txt index 9dcf1b2d7..9bddfdb43 100644 --- a/wadsrc/static/engine/grpinfo.txt +++ b/wadsrc/static/engine/grpinfo.txt @@ -404,12 +404,11 @@ grpinfo GameID "Blood" } -/* this doesn't work with the current setup. grpinfo { // This is for identifying older Blood versions. Since I have no information, all I can do is testing for a few known files. name "BLOOD: Unknown Version" - mustcontain "help1.qav", "cult2d2.seq", "tombstn1.kvx", "normal.plu" + mustcontain "help1.qav", "normal.plu", "inverse.clu", "cosine.dat", "blood.pal" defname "blood.def" scriptname "BLOOD.INI" flags GAMEFLAG_BLOOD @@ -417,7 +416,6 @@ grpinfo loadgrp "SOUNDS.RFF", "GUI.RFF" gamefilter "Blood.Blood" } -*/ grpinfo {