2019-11-20 16:21:32 +00:00
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
/*
|
|
|
|
Copyright (C) 2010-2019 EDuke32 developers and contributors
|
|
|
|
Copyright (C) 2019 sirlemonhead, Nuke.YKT
|
|
|
|
This file is part of PCExhumed.
|
|
|
|
PCExhumed is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License version 2
|
|
|
|
as published by the Free Software Foundation.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
//-------------------------------------------------------------------------
|
2019-11-22 23:11:37 +00:00
|
|
|
#include "ns.h"
|
2021-04-11 06:40:18 +00:00
|
|
|
#include "gamehud.h"
|
2019-08-26 03:59:14 +00:00
|
|
|
#include "sequence.h"
|
|
|
|
#include "engine.h"
|
|
|
|
#include "exhumed.h"
|
|
|
|
#include "sound.h"
|
|
|
|
#include "player.h"
|
2020-08-18 07:52:08 +00:00
|
|
|
#include "aistuff.h"
|
2019-08-26 03:59:14 +00:00
|
|
|
#include "view.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
2019-11-22 23:11:37 +00:00
|
|
|
BEGIN_PS_NS
|
|
|
|
|
2020-10-11 11:14:32 +00:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
kMaxSequences = 4096,
|
|
|
|
kMaxSEQFiles = 78,
|
|
|
|
kMaxSEQFrames = 18000,
|
|
|
|
kMaxSEQChunks = 21000
|
|
|
|
};
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-11-21 19:48:11 +00:00
|
|
|
int16_t nPilotLightFrame;
|
|
|
|
int16_t nPilotLightCount;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2023-04-16 06:46:07 +00:00
|
|
|
static FTextureID nShadowPic;
|
|
|
|
static int16_t nShadowWidth = 1;
|
2021-11-21 19:48:11 +00:00
|
|
|
int16_t nFlameHeight = 1;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2019-08-31 07:47:15 +00:00
|
|
|
const char *SeqNames[kMaxSEQFiles] =
|
2019-08-26 03:59:14 +00:00
|
|
|
{
|
|
|
|
"rothands",
|
|
|
|
"sword",
|
|
|
|
"pistol",
|
|
|
|
"m_60",
|
|
|
|
"flamer", // 4
|
|
|
|
"grenade",
|
|
|
|
"cobra",
|
|
|
|
"bonesaw",
|
|
|
|
"scramble",
|
|
|
|
"glove",
|
|
|
|
"mummy", // 10
|
|
|
|
"skull",
|
|
|
|
"poof",
|
|
|
|
"kapow",
|
|
|
|
"fireball",
|
|
|
|
"bubble",
|
|
|
|
"spider", // 16
|
|
|
|
"anubis",
|
|
|
|
"anuball",
|
|
|
|
"fish",
|
|
|
|
"snakehed", // 20?
|
|
|
|
"snakbody",
|
|
|
|
"wasp",
|
|
|
|
"cobrapow",
|
|
|
|
"scorp",
|
|
|
|
"joe", // 25
|
|
|
|
"status",
|
|
|
|
"dead",
|
|
|
|
"deadex",
|
|
|
|
"anupoof",
|
|
|
|
"skulpoof", // 30
|
|
|
|
"bullet",
|
|
|
|
"shadow",
|
|
|
|
"grenroll",
|
|
|
|
"grenboom",
|
|
|
|
"splash",
|
|
|
|
"grenpow",
|
|
|
|
"skulstrt",
|
|
|
|
"firepoof",
|
|
|
|
"bloodhit",
|
|
|
|
"lion", // 40
|
|
|
|
"items",
|
|
|
|
"lavag", // 42
|
|
|
|
"lsplash",
|
|
|
|
"lavashot",
|
|
|
|
"smokebal",
|
|
|
|
"firepot",
|
|
|
|
"rex",
|
|
|
|
"set", // 48
|
|
|
|
"queen",
|
|
|
|
"roach", // 50
|
|
|
|
"hawk",
|
|
|
|
"setghost",
|
|
|
|
"setgblow",
|
|
|
|
"bizztail",
|
|
|
|
"bizzpoof",
|
|
|
|
"queenegg",
|
|
|
|
"roacshot",
|
|
|
|
"backgrnd",
|
|
|
|
"screens", // 59
|
|
|
|
"arrow",
|
|
|
|
"fonts",
|
|
|
|
"drips",
|
|
|
|
"firetrap",
|
|
|
|
"magic2",
|
|
|
|
"creepy",
|
|
|
|
"slider", // 66
|
|
|
|
"ravolt",
|
|
|
|
"eyehit",
|
|
|
|
"font2", // 69
|
|
|
|
"seebubbl",
|
|
|
|
"blood",
|
|
|
|
"drum",
|
|
|
|
"poof2",
|
|
|
|
"deadbrn",
|
|
|
|
"grenbubb",
|
|
|
|
"rochfire",
|
|
|
|
"rat"
|
|
|
|
};
|
|
|
|
|
2023-04-15 22:03:23 +00:00
|
|
|
static TMap<FName, TArray<Seq>> FileSeqMap;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2023-04-06 09:27:42 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2023-04-15 22:03:23 +00:00
|
|
|
TArray<Seq>* getFileSeqs(const FName nSeqFile)
|
2023-04-21 11:11:52 +00:00
|
|
|
{
|
2023-04-16 06:49:51 +00:00
|
|
|
return FileSeqMap.CheckKey(nSeqFile);
|
2023-04-21 11:11:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2023-04-15 10:49:52 +00:00
|
|
|
int addSeq(const char *seqName)
|
|
|
|
{
|
|
|
|
const FStringf seqfilename("%s.seq", seqName);
|
|
|
|
const auto hFile = fileSystem.ReopenFileReader(fileSystem.FindFile(seqfilename), true);
|
|
|
|
|
|
|
|
if (!hFile.isOpen())
|
|
|
|
{
|
|
|
|
Printf("Unable to open '%s'!\n", seqfilename.GetChars());
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t tag;
|
|
|
|
hFile.Read(&tag, sizeof(tag));
|
|
|
|
if (tag < MAKE_ID('I', 'H', 0, 0) || (tag > MAKE_ID('I', 'H', 0, 0) && tag != MAKE_ID('D', 'S', 0, 0)))
|
|
|
|
{
|
|
|
|
Printf("Unsupported sequence version!\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int16_t CenterX, CenterY, nSeqs;
|
|
|
|
hFile.Read(&CenterX, sizeof(CenterX));
|
|
|
|
hFile.Read(&CenterY, sizeof(CenterY));
|
|
|
|
hFile.Read(&nSeqs, sizeof(nSeqs));
|
|
|
|
|
|
|
|
if (nSeqs <= 0)
|
|
|
|
{
|
|
|
|
Printf("Invalid sequence count!\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
TArray<int16_t> nSeqFrames(nSeqs, true);
|
|
|
|
TArray<int16_t> nSeqFrameCount(nSeqs, true);
|
|
|
|
TArray<int16_t> nSeqFlags(nSeqs, true);
|
|
|
|
hFile.Read(nSeqFrames.Data(), nSeqs * sizeof(int16_t));
|
|
|
|
hFile.Read(nSeqFrameCount.Data(), nSeqs * sizeof(int16_t));
|
|
|
|
hFile.Read(nSeqFlags.Data(), nSeqs * sizeof(int16_t));
|
|
|
|
|
|
|
|
int16_t nFrames;
|
|
|
|
hFile.Read(&nFrames, sizeof(nFrames));
|
|
|
|
|
|
|
|
if (nFrames <= 0 )
|
|
|
|
{
|
|
|
|
Printf("Invalid frame count!\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
TArray<int16_t> nSeqFrameChunks(nFrames, true);
|
|
|
|
TArray<int16_t> nSeqFrameChunkCount(nFrames, true);
|
|
|
|
TArray<int16_t> nSeqFrameFlags(nFrames, true);
|
|
|
|
TArray<int16_t> nSeqFrameSounds(nFrames, true);
|
|
|
|
hFile.Read(nSeqFrameChunks.Data(), nFrames * sizeof(int16_t));
|
|
|
|
hFile.Read(nSeqFrameChunkCount.Data(), nFrames * sizeof(int16_t));
|
|
|
|
hFile.Read(nSeqFrameFlags.Data(), nFrames * sizeof(int16_t));
|
|
|
|
memset(nSeqFrameSounds.Data(), -1, nFrames * sizeof(int16_t));
|
|
|
|
|
|
|
|
int16_t nChunks;
|
|
|
|
hFile.Read(&nChunks, sizeof(nChunks));
|
|
|
|
|
|
|
|
if (nChunks <= 0)
|
|
|
|
{
|
|
|
|
Printf("Invalid chunk count!\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
TArray<int16_t> nSeqFrameChunkPosX(nChunks, true);
|
|
|
|
TArray<int16_t> nSeqFrameChunkPosY(nChunks, true);
|
|
|
|
TArray<int16_t> nSeqFrameChunkPicnum(nChunks, true);
|
|
|
|
TArray<int16_t> nSeqFrameChunkFlags(nChunks, true);
|
|
|
|
hFile.Read(nSeqFrameChunkPosX.Data(), nChunks * sizeof(int16_t));
|
|
|
|
hFile.Read(nSeqFrameChunkPosY.Data(), nChunks * sizeof(int16_t));
|
|
|
|
hFile.Read(nSeqFrameChunkPicnum.Data(), nChunks * sizeof(int16_t));
|
|
|
|
hFile.Read(nSeqFrameChunkFlags.Data(), nChunks * sizeof(int16_t));
|
|
|
|
|
|
|
|
if (tag == MAKE_ID('D', 'S', 0, 0))
|
|
|
|
{
|
|
|
|
int16_t nSounds;
|
|
|
|
hFile.Read(&nSounds, sizeof(nSounds));
|
|
|
|
TArray<char> buffer(nSounds * 10, true);
|
|
|
|
memset(buffer.Data(), 0, nSounds * 10);
|
|
|
|
|
|
|
|
for (int i = 0; i < nSounds; i++)
|
|
|
|
{
|
|
|
|
hFile.Read(&buffer[i * 10], 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
int16_t nSounds2;
|
|
|
|
hFile.Read(&nSounds2, sizeof(nSounds2));
|
|
|
|
|
|
|
|
for (int i = 0; i < nSounds2; i++)
|
|
|
|
{
|
|
|
|
int16_t nSeqFrame, nSndIndex;
|
|
|
|
hFile.Read(&nSeqFrame, sizeof(nSeqFrame));
|
|
|
|
hFile.Read(&nSndIndex, sizeof(nSndIndex));
|
|
|
|
|
|
|
|
int ndx = (nSndIndex & 0x1FF);
|
|
|
|
int hSound = 0;
|
|
|
|
|
|
|
|
if (ndx >= nSounds)
|
|
|
|
{
|
|
|
|
Printf("Invalid sound index %d in %s, maximum is %d\n", ndx, seqfilename.GetChars(), nSounds);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
hSound = LoadSound(&buffer[ndx * 10]);
|
|
|
|
}
|
|
|
|
|
|
|
|
nSeqFrameSounds[nSeqFrame] = hSound | (nSndIndex & 0xFE00);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add hastable entry for the amount of sequences this file contains.
|
2023-04-15 22:03:23 +00:00
|
|
|
auto& gSequences = FileSeqMap.Insert(FName(seqName), TArray<Seq>(nSeqs, true));
|
2023-04-15 10:49:52 +00:00
|
|
|
|
|
|
|
// Read all this data into something sane.
|
|
|
|
for (int nSeq = 0; nSeq < nSeqs; nSeq++)
|
|
|
|
{
|
2023-04-15 22:03:23 +00:00
|
|
|
// Store unused sequence flags, they may be used with future expansion.
|
|
|
|
auto& gSeq = gSequences[nSeq];
|
|
|
|
gSeq.flags = nSeqFlags[nSeq];
|
|
|
|
|
2023-04-15 10:49:52 +00:00
|
|
|
// Determine where we are in our frame array.
|
|
|
|
const int firstFrame = nSeqFrames[nSeq];
|
|
|
|
const int lastFrame = nSeqFrameCount[nSeq] + firstFrame;
|
|
|
|
|
|
|
|
// Get sequence's frame array and resize.
|
2023-04-15 22:03:23 +00:00
|
|
|
auto& gSeqFrames = gSeq.frames;
|
2023-04-15 10:49:52 +00:00
|
|
|
gSeqFrames.Resize(lastFrame - firstFrame);
|
|
|
|
|
|
|
|
// Build out frame array.
|
|
|
|
for (int nFrame = firstFrame; nFrame < lastFrame; nFrame++)
|
|
|
|
{
|
|
|
|
// Store reference to this frame and start filling.
|
|
|
|
auto& gSeqFrame = gSeqFrames[nFrame - firstFrame];
|
|
|
|
gSeqFrame.sound = nSeqFrameSounds[nFrame];
|
|
|
|
gSeqFrame.flags = nSeqFrameFlags[nFrame];
|
|
|
|
|
|
|
|
// Determine where we are in our chunk array.
|
|
|
|
const int firstChunk = nSeqFrameChunks[nFrame];
|
|
|
|
const int lastChunk = nSeqFrameChunkCount[nFrame] + firstChunk;
|
|
|
|
|
|
|
|
// Build out chunk array.
|
|
|
|
for (int nChunk = firstChunk; nChunk < lastChunk; nChunk++)
|
|
|
|
{
|
|
|
|
gSeqFrame.chunks.Push({
|
|
|
|
(int16_t)(nSeqFrameChunkPosX[nChunk] - CenterX),
|
|
|
|
(int16_t)(nSeqFrameChunkPosY[nChunk] - CenterY),
|
2023-04-17 00:38:34 +00:00
|
|
|
tileGetTextureID(nSeqFrameChunkPicnum[nChunk]),
|
2023-04-15 10:49:52 +00:00
|
|
|
nSeqFrameChunkFlags[nChunk],
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nSeqs;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2019-08-26 03:59:14 +00:00
|
|
|
void seq_LoadSequences()
|
|
|
|
{
|
2023-04-15 10:25:40 +00:00
|
|
|
for (unsigned i = 0; i < kMaxSEQFiles; i++)
|
2019-08-31 07:47:15 +00:00
|
|
|
{
|
2023-04-21 04:34:27 +00:00
|
|
|
if (addSeq(SeqNames[i]) == 0)
|
2023-04-15 10:49:52 +00:00
|
|
|
{
|
2020-04-11 21:45:45 +00:00
|
|
|
Printf("Error loading '%s'\n", SeqNames[i]);
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2023-04-16 23:05:21 +00:00
|
|
|
nShadowPic = getSequence("shadow").getFirstFrameTexture();
|
2023-04-17 00:38:34 +00:00
|
|
|
nShadowWidth = (int16_t)TexMan.GetGameTexture(nShadowPic)->GetDisplayWidth();
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2023-04-16 23:05:21 +00:00
|
|
|
nFlameHeight = (int16_t)TexMan.GetGameTexture(getSequence("firepoof").getFirstFrameTexture())->GetDisplayHeight();
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2023-04-15 22:03:23 +00:00
|
|
|
nPilotLightCount = getSequence("flamer", 3).frames.Size();
|
2019-08-31 07:47:15 +00:00
|
|
|
nPilotLightFrame = 0;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2023-04-15 10:25:40 +00:00
|
|
|
const auto& fontSeq = getSequence("font2");
|
2023-04-16 23:05:21 +00:00
|
|
|
const int nFontFirstChar = legacyTileNum(fontSeq.getFirstFrameTexture());
|
2019-11-20 16:21:32 +00:00
|
|
|
|
2023-04-15 22:03:23 +00:00
|
|
|
for (unsigned i = 0; i < fontSeq.frames.Size(); i++)
|
2019-08-31 07:47:15 +00:00
|
|
|
{
|
2020-05-24 10:31:38 +00:00
|
|
|
auto tex = tileGetTexture(nFontFirstChar + i);
|
|
|
|
tex->SetOffsets(0, 0);
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
}
|
|
|
|
|
2022-09-11 06:09:26 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2020-08-24 03:22:52 +00:00
|
|
|
void seq_DrawPilotLightSeq(double xOffset, double yOffset)
|
2019-08-26 03:59:14 +00:00
|
|
|
{
|
2021-11-22 23:20:15 +00:00
|
|
|
auto pSect = PlayerList[nLocalPlayer].pPlayerViewSect;
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2021-11-22 23:20:15 +00:00
|
|
|
if (!(pSect->Flag & kSectUnderwater))
|
2019-08-31 07:47:15 +00:00
|
|
|
{
|
2023-04-15 08:10:48 +00:00
|
|
|
const auto& pilotlightSeq = getSequence("flamer", 3);
|
2023-04-15 22:03:23 +00:00
|
|
|
const auto& seqFrame = pilotlightSeq.frames[0];
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2023-04-15 08:10:48 +00:00
|
|
|
for (unsigned i = 0; i < seqFrame.chunks.Size(); i++)
|
2019-08-31 07:47:15 +00:00
|
|
|
{
|
2023-04-15 08:10:48 +00:00
|
|
|
const auto& frameChunk = seqFrame.chunks[i];
|
|
|
|
const double x = frameChunk.xpos + (160 + xOffset);
|
|
|
|
const double y = frameChunk.ypos + (100 + yOffset);
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2023-04-17 00:38:34 +00:00
|
|
|
hud_drawsprite(x, y, 65536, PlayerList[nLocalPlayer].pActor->spr.Angles.Yaw.Normalized180().Degrees() * 2., legacyTileNum(frameChunk.tex), 0, 0, 1);
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
}
|
|
|
|
|
2022-09-11 06:09:26 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2023-04-15 22:03:23 +00:00
|
|
|
void seq_DrawGunSequence(const Seq& weapSeq, int16_t frameIndex, double xOffs, double yOffs, int nShade, int nPal, DAngle angle, bool align)
|
2019-08-26 03:59:14 +00:00
|
|
|
{
|
2023-04-15 22:03:23 +00:00
|
|
|
const auto& seqFrame = weapSeq.frames[frameIndex];
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2023-04-16 06:49:51 +00:00
|
|
|
if (seqFrame.flags & 4)
|
|
|
|
nShade = -100;
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < seqFrame.chunks.Size(); i++)
|
2019-08-31 07:47:15 +00:00
|
|
|
{
|
2023-04-16 06:49:51 +00:00
|
|
|
const auto& frameChunk = seqFrame.chunks[i];
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2023-04-16 06:49:51 +00:00
|
|
|
int x = frameChunk.xpos + 160;
|
|
|
|
int y = frameChunk.ypos + 100;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2020-08-23 12:55:19 +00:00
|
|
|
int stat = 0;
|
2023-04-16 06:49:51 +00:00
|
|
|
if (frameChunk.flags & 1)
|
2020-08-23 12:55:19 +00:00
|
|
|
stat |= RS_XFLIPHUD;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2023-04-16 06:49:51 +00:00
|
|
|
if (frameChunk.flags & 2)
|
2020-08-23 12:55:19 +00:00
|
|
|
stat |= RS_YFLIPHUD;
|
2022-05-05 22:03:54 +00:00
|
|
|
|
|
|
|
if (align) stat |= RS_ALIGN_R;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2020-08-23 12:55:19 +00:00
|
|
|
double alpha = 1;
|
2021-05-13 17:15:53 +00:00
|
|
|
if (PlayerList[nLocalPlayer].nInvisible) {
|
2020-08-23 12:55:19 +00:00
|
|
|
alpha = 0.3;
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2023-04-17 00:38:34 +00:00
|
|
|
hud_drawsprite(x + xOffs, y + yOffs, 65536, angle.Degrees(), legacyTileNum(frameChunk.tex), nShade, nPal, stat, alpha);
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
}
|
|
|
|
|
2022-09-11 06:09:26 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2023-04-15 22:20:04 +00:00
|
|
|
void seq_PlotArrowSequence(const int nSprite, const FName seqFile, const int16_t seqIndex, const int frameIndex)
|
2019-08-26 03:59:14 +00:00
|
|
|
{
|
2022-08-07 08:25:15 +00:00
|
|
|
tspritetype* pTSprite = mytspriteArray->get(nSprite);
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2023-04-15 22:20:04 +00:00
|
|
|
const DAngle nAngle = (nCamerapos.XY() - pTSprite->pos.XY()).Angle();
|
|
|
|
const int seqOffset = (((pTSprite->Angles.Yaw + DAngle90 + DAngle22_5 - nAngle).Buildang()) & kAngleMask) >> 8;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2023-04-15 22:03:23 +00:00
|
|
|
const auto& seqFrame = getSequence(seqFile, seqIndex + seqOffset).frames[frameIndex];
|
2023-04-15 22:20:04 +00:00
|
|
|
const auto& frameChunk = seqFrame.chunks[0];
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2023-04-15 22:20:04 +00:00
|
|
|
auto nStat = pTSprite->cstat | CSTAT_SPRITE_YCENTER;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2023-04-15 22:20:04 +00:00
|
|
|
if (seqOffset & 3) {
|
2021-12-18 18:08:55 +00:00
|
|
|
nStat |= CSTAT_SPRITE_ALIGNMENT_WALL | CSTAT_SPRITE_YFLIP;
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
|
|
|
else {
|
2021-12-18 18:08:55 +00:00
|
|
|
nStat &= ~(CSTAT_SPRITE_ALIGNMENT_WALL | CSTAT_SPRITE_YFLIP);
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2020-01-03 04:20:56 +00:00
|
|
|
pTSprite->cstat = nStat;
|
2023-04-15 22:20:04 +00:00
|
|
|
pTSprite->shade = (seqFrame.flags & 4) ? pTSprite->shade - 100 : pTSprite->shade;
|
|
|
|
pTSprite->statnum = seqFrame.chunks.Size();
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2023-04-15 22:20:04 +00:00
|
|
|
if (frameChunk.flags & 1)
|
2019-08-31 07:47:15 +00:00
|
|
|
{
|
2023-04-15 22:20:04 +00:00
|
|
|
pTSprite->xoffset = (int8_t)frameChunk.xpos;
|
2021-12-18 15:02:15 +00:00
|
|
|
pTSprite->cstat |= CSTAT_SPRITE_XFLIP;
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-04-15 22:20:04 +00:00
|
|
|
pTSprite->xoffset = (int8_t)-frameChunk.xpos;
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2023-04-15 22:20:04 +00:00
|
|
|
pTSprite->yoffset = -frameChunk.ypos;
|
2023-04-17 00:38:34 +00:00
|
|
|
pTSprite->setspritetexture(frameChunk.tex);
|
2019-08-26 03:59:14 +00:00
|
|
|
}
|
|
|
|
|
2022-09-11 06:09:26 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2023-04-21 11:11:52 +00:00
|
|
|
void seq_PlotSequence(const int nSprite, const FName seqFile, const int16_t seqIndex, const int16_t frameIndex, const int16_t nFlags)
|
2019-08-26 03:59:14 +00:00
|
|
|
{
|
2022-08-07 08:25:15 +00:00
|
|
|
tspritetype* pTSprite = mytspriteArray->get(nSprite);
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2023-04-21 11:11:52 +00:00
|
|
|
int seqOffset = 0;
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2023-04-14 23:05:02 +00:00
|
|
|
if (!(nFlags & 1))
|
2019-08-31 07:47:15 +00:00
|
|
|
{
|
2023-04-21 11:11:52 +00:00
|
|
|
const DAngle nAngle = (nCamerapos.XY() - pTSprite->pos.XY()).Angle();
|
|
|
|
seqOffset = (((pTSprite->Angles.Yaw + DAngle22_5 - nAngle).Buildang()) & kAngleMask) >> 8;
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
|
|
|
|
2023-04-16 06:49:51 +00:00
|
|
|
const auto fileSeqs = getFileSeqs(seqFile);
|
2023-04-15 22:03:23 +00:00
|
|
|
const auto& baseFrame = fileSeqs->operator[](seqIndex).frames[frameIndex];
|
|
|
|
const auto& drawFrame = fileSeqs->operator[](seqIndex + seqOffset).frames[frameIndex];
|
2023-04-21 11:11:52 +00:00
|
|
|
const auto chunkCount = drawFrame.chunks.Size();
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2023-04-21 11:11:52 +00:00
|
|
|
const auto nShade = (baseFrame.flags & 4) ? pTSprite->shade - 100 : pTSprite->shade;
|
|
|
|
const auto nStatnum = (nFlags & 0x100) ? -3 : 100;
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2023-04-21 11:11:52 +00:00
|
|
|
for (unsigned i = 0; i < chunkCount; i++)
|
2019-08-31 07:47:15 +00:00
|
|
|
{
|
2023-04-21 11:11:52 +00:00
|
|
|
const auto& seqFrameChunk = drawFrame.chunks[i];
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2022-08-07 08:25:15 +00:00
|
|
|
tspritetype* tsp = mytspriteArray->newTSprite();
|
2022-08-16 21:46:18 +00:00
|
|
|
tsp->pos = pTSprite->pos;
|
2023-04-21 11:11:52 +00:00
|
|
|
tsp->shade = nShade;
|
2021-12-04 18:08:50 +00:00
|
|
|
tsp->pal = pTSprite->pal;
|
2022-10-07 21:41:15 +00:00
|
|
|
tsp->scale = pTSprite->scale;
|
2022-11-25 12:13:50 +00:00
|
|
|
tsp->Angles.Yaw = pTSprite->Angles.Yaw;
|
2021-12-04 18:08:50 +00:00
|
|
|
tsp->ownerActor = pTSprite->ownerActor;
|
2021-12-06 16:40:33 +00:00
|
|
|
tsp->sectp = pTSprite->sectp;
|
2021-12-18 17:40:25 +00:00
|
|
|
tsp->cstat = pTSprite->cstat |= CSTAT_SPRITE_YCENTER;
|
2021-12-30 18:00:35 +00:00
|
|
|
tsp->clipdist = pTSprite->clipdist;
|
2023-04-21 11:11:52 +00:00
|
|
|
tsp->statnum = chunkCount - i + nStatnum + 1;
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2023-04-21 11:11:52 +00:00
|
|
|
if (seqFrameChunk.flags & 1)
|
2019-08-31 07:47:15 +00:00
|
|
|
{
|
2023-04-21 11:11:52 +00:00
|
|
|
tsp->xoffset = (int8_t)seqFrameChunk.xpos;
|
2021-12-18 15:02:15 +00:00
|
|
|
tsp->cstat |= CSTAT_SPRITE_XFLIP; // x-flipped
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-04-21 11:11:52 +00:00
|
|
|
tsp->xoffset = -seqFrameChunk.xpos;
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
|
|
|
|
2023-04-21 11:11:52 +00:00
|
|
|
tsp->yoffset = -seqFrameChunk.ypos;
|
2023-04-17 00:38:34 +00:00
|
|
|
tsp->setspritetexture(seqFrameChunk.tex);
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
|
|
|
|
2023-04-14 23:05:02 +00:00
|
|
|
if (!(pTSprite->cstat & CSTAT_SPRITE_BLOCK_ALL) || (pTSprite->ownerActor->spr.statnum == 100 && nNetPlayerCount))
|
2019-08-31 07:47:15 +00:00
|
|
|
{
|
2021-12-04 18:08:50 +00:00
|
|
|
pTSprite->ownerActor = nullptr;
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-04-14 23:05:02 +00:00
|
|
|
const auto pSector = pTSprite->sectp;
|
|
|
|
const double nFloorZ = pSector->floorz;
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2023-04-14 23:05:02 +00:00
|
|
|
if (nFloorZ <= PlayerList[nLocalPlayer].pActor->viewzoffset + PlayerList[nLocalPlayer].pActor->spr.pos.Z)
|
|
|
|
{
|
2021-12-04 18:08:50 +00:00
|
|
|
pTSprite->ownerActor = nullptr;
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-04-17 00:38:34 +00:00
|
|
|
pTSprite->setspritetexture(nShadowPic);
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2023-04-16 23:05:21 +00:00
|
|
|
const auto nTexWidth = (int)TexMan.GetGameTexture(drawFrame.getFirstChunkTexture())->GetDisplayWidth();
|
2023-04-17 00:38:34 +00:00
|
|
|
const auto nScale = max(((nTexWidth << 5) / nShadowWidth) - int16_t((nFloorZ - pTSprite->pos.Z) * 2.), 1) * REPEAT_SCALE;
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2021-12-18 18:08:55 +00:00
|
|
|
pTSprite->cstat = CSTAT_SPRITE_ALIGNMENT_FLOOR | CSTAT_SPRITE_TRANSLUCENT;
|
2022-08-20 14:44:30 +00:00
|
|
|
pTSprite->pos.Z = pSector->floorz;
|
2023-04-14 23:05:02 +00:00
|
|
|
pTSprite->scale = DVector2(nScale, nScale);
|
2020-01-03 04:20:56 +00:00
|
|
|
pTSprite->statnum = -3;
|
|
|
|
pTSprite->pal = 0;
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
}
|
2019-12-26 21:00:04 +00:00
|
|
|
|
2022-09-11 06:09:26 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2023-04-16 05:31:40 +00:00
|
|
|
DEFINE_FIELD_X(SeqFrameChunk, SeqFrameChunk, xpos);
|
|
|
|
DEFINE_FIELD_X(SeqFrameChunk, SeqFrameChunk, ypos);
|
|
|
|
DEFINE_FIELD_X(SeqFrameChunk, SeqFrameChunk, tex);
|
|
|
|
DEFINE_FIELD_X(SeqFrameChunk, SeqFrameChunk, flags);
|
|
|
|
|
|
|
|
DEFINE_FIELD_X(SeqFrame, SeqFrame, sound);
|
|
|
|
DEFINE_FIELD_X(SeqFrame, SeqFrame, flags);
|
|
|
|
|
|
|
|
DEFINE_FIELD_X(Seq, Seq, flags);
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
DEFINE_ACTION_FUNCTION(_SeqFrame, playSound)
|
|
|
|
{
|
|
|
|
PARAM_SELF_STRUCT_PROLOGUE(SeqFrame);
|
|
|
|
self->playSound(PlayerList[nLocalPlayer].pActor);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFINE_ACTION_FUNCTION(_SeqFrame, Size)
|
|
|
|
{
|
|
|
|
PARAM_SELF_STRUCT_PROLOGUE(SeqFrame);
|
|
|
|
ACTION_RETURN_INT(self->chunks.Size());
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFINE_ACTION_FUNCTION(_SeqFrame, getChunk)
|
|
|
|
{
|
|
|
|
PARAM_SELF_STRUCT_PROLOGUE(SeqFrame);
|
|
|
|
PARAM_INT(chunkId);
|
|
|
|
ACTION_RETURN_POINTER(self->chunks.Data(chunkId));
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFINE_ACTION_FUNCTION(_Seq, Size)
|
|
|
|
{
|
|
|
|
PARAM_SELF_STRUCT_PROLOGUE(Seq);
|
|
|
|
ACTION_RETURN_INT(self->frames.Size());
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFINE_ACTION_FUNCTION(_Seq, getFrame)
|
|
|
|
{
|
|
|
|
PARAM_SELF_STRUCT_PROLOGUE(Seq);
|
|
|
|
PARAM_INT(frameId);
|
|
|
|
ACTION_RETURN_POINTER(self->frames.Data(frameId));
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFINE_ACTION_FUNCTION(_Exhumed, GetStatusSequence)
|
|
|
|
{
|
|
|
|
PARAM_PROLOGUE;
|
|
|
|
PARAM_INT(seqId);
|
|
|
|
ACTION_RETURN_POINTER(getFileSeqs("status")->Data(seqId));
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2020-11-29 23:18:32 +00:00
|
|
|
void SerializeSequence(FSerializer& arc)
|
|
|
|
{
|
|
|
|
if (arc.BeginObject("sequence"))
|
|
|
|
{
|
|
|
|
arc("pilotlightframe", nPilotLightFrame)
|
|
|
|
("pilotlightcount", nPilotLightCount)
|
|
|
|
("shadowwidth", nShadowWidth)
|
|
|
|
("flameheight", nFlameHeight)
|
|
|
|
.EndObject();
|
|
|
|
}
|
|
|
|
}
|
2019-12-26 21:00:04 +00:00
|
|
|
|
2019-11-22 23:11:37 +00:00
|
|
|
END_PS_NS
|