Merge branch 'blood-qavrework'

# Conflicts:
#	source/core/gamecvars.cpp
#	source/core/gamecvars.h
#	source/games/blood/src/weapon.cpp
This commit is contained in:
Mitchell Richters 2021-08-23 11:02:09 +10:00
commit 1ee6fd76c4
170 changed files with 1806 additions and 527 deletions

View file

@ -912,6 +912,12 @@ LumpShortName& FileSystem::GetShortName(int i)
return FileInfo[i].shortName;
}
FString& FileSystem::GetLongName(int i)
{
if ((unsigned)i >= NumEntries) I_Error("GetShortName: Invalid index");
return FileInfo[i].longName;
}
void FileSystem::RenameFile(int num, const char* newfn)
{
if ((unsigned)num >= NumEntries) I_Error("RenameFile: Invalid index");

View file

@ -117,6 +117,7 @@ public:
}
LumpShortName& GetShortName(int i); // may only be called before the hash chains are set up.
FString& GetLongName(int i); // may only be called before the hash chains are set up.
void RenameFile(int num, const char* fn);
bool CreatePathlessCopy(const char* name, int id, int flags);

View file

@ -1036,6 +1036,7 @@ DEFINE_FIELD(DListMenuDescriptor, mFont)
DEFINE_FIELD(DListMenuDescriptor, mFontColor)
DEFINE_FIELD(DListMenuDescriptor, mFontColor2)
DEFINE_FIELD(DListMenuDescriptor, mAnimatedTransition)
DEFINE_FIELD(DListMenuDescriptor, mAnimated)
DEFINE_FIELD(DListMenuDescriptor, mCenter)
DEFINE_FIELD(DListMenuDescriptor, mVirtWidth)
DEFINE_FIELD(DListMenuDescriptor, mVirtHeight)
@ -1066,6 +1067,7 @@ DEFINE_FIELD(DImageScrollerDescriptor, textBackgroundBrightness)
DEFINE_FIELD(DImageScrollerDescriptor,textFont)
DEFINE_FIELD(DImageScrollerDescriptor, textScale)
DEFINE_FIELD(DImageScrollerDescriptor, mAnimatedTransition)
DEFINE_FIELD(DImageScrollerDescriptor, mAnimated)
DEFINE_FIELD(DImageScrollerDescriptor, virtWidth)
DEFINE_FIELD(DImageScrollerDescriptor, virtHeight)

View file

@ -141,6 +141,7 @@ public:
FFont *textFont;
double textScale;
bool mAnimatedTransition;
bool mAnimated;
int virtWidth, virtHeight;
};

View file

@ -344,6 +344,10 @@ static void DoParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc, bool &s
{
desc->mAnimatedTransition = true;
}
else if (sc.Compare("animated"))
{
desc->mAnimated = true;
}
else if (sc.Compare("MouseWindow"))
{
sc.MustGetNumber();
@ -1212,6 +1216,10 @@ static void ParseImageScrollerBody(FScanner& sc, DImageScrollerDescriptor* desc)
{
desc->mAnimatedTransition = true;
}
else if (sc.Compare("animated"))
{
desc->mAnimated = true;
}
else if (sc.Compare("textBackground"))
{
sc.MustGetString();

View file

@ -67,22 +67,14 @@ static uint64_t NSToMS(uint64_t ns)
return static_cast<uint64_t>(ns / 1'000'000);
}
static int NSToTic(uint64_t ns)
static int NSToTic(uint64_t ns, double const ticrate)
{
return static_cast<int>(ns * GameTicRate / 1'000'000'000);
return static_cast<int>(ns * ticrate / 1'000'000'000);
}
static int NSToBuildTic(uint64_t ns)
static uint64_t TicToNS(double tic, double const ticrate)
{
return static_cast<int>(ns * 120 / 1'000'000'000);
}
static uint64_t TicToNS(int tic)
{
return static_cast<uint64_t>(tic) * 1'000'000'000 / GameTicRate;
}
static uint64_t BuildTicToNS(int tic)
{
return static_cast<uint64_t>(tic) * 1'000'000'000 / 120;
return static_cast<uint64_t>(tic * 1'000'000'000 / ticrate);
}
void I_SetFrameTime()
@ -111,18 +103,18 @@ void I_WaitVBL(int count)
I_SetFrameTime();
}
int I_WaitForTic(int prevtic)
int I_WaitForTic(int prevtic, double const ticrate)
{
// Waits until the current tic is greater than prevtic. Time must not be frozen.
int time;
while ((time = I_GetTime()) <= prevtic)
while ((time = I_GetTime(ticrate)) <= prevtic)
{
// Windows-specific note:
// The minimum amount of time a thread can sleep is controlled by timeBeginPeriod.
// We set this to 1 ms in DoMain.
const uint64_t next = FirstFrameStartTime + TicToNS(prevtic + 1);
const uint64_t next = FirstFrameStartTime + TicToNS(prevtic + 1, ticrate);
const uint64_t now = I_nsTime();
if (next > now)
@ -166,21 +158,16 @@ uint64_t I_GetTimeNS()
return CurrentFrameStartTime - FirstFrameStartTime;
}
int I_GetTime()
int I_GetTime(double const ticrate)
{
return NSToTic(CurrentFrameStartTime - FirstFrameStartTime);
return NSToTic(CurrentFrameStartTime - FirstFrameStartTime, ticrate);
}
int I_GetBuildTime()
double I_GetTimeFrac(double const ticrate)
{
return NSToBuildTic(CurrentFrameStartTime - FirstFrameStartTime);
}
double I_GetTimeFrac()
{
int currentTic = NSToTic(CurrentFrameStartTime - FirstFrameStartTime);
uint64_t ticStartTime = FirstFrameStartTime + TicToNS(currentTic);
uint64_t ticNextTime = FirstFrameStartTime + TicToNS(currentTic + 1);
int currentTic = NSToTic(CurrentFrameStartTime - FirstFrameStartTime, ticrate);
uint64_t ticStartTime = FirstFrameStartTime + TicToNS(currentTic, ticrate);
uint64_t ticNextTime = FirstFrameStartTime + TicToNS(currentTic + 1, ticrate);
return (CurrentFrameStartTime - ticStartTime) / (double)(ticNextTime - ticStartTime);
}

View file

@ -9,17 +9,14 @@ extern double TimeScale;
void I_SetFrameTime();
// Called by D_DoomLoop, returns current time in tics.
int I_GetTime();
int I_GetTime(double const ticrate = GameTicRate);
// same, but using nanoseconds
uint64_t I_GetTimeNS();
// Called by Build games in lieu of totalclock, returns current time in tics at ticrate of 120.
int I_GetBuildTime();
double I_GetTimeFrac();
double I_GetTimeFrac(double const ticrate = GameTicRate);
// like I_GetTime, except it waits for a new tic before returning
int I_WaitForTic(int);
int I_WaitForTic(int prevtic, double const ticrate = GameTicRate);
// Freezes tic counting temporarily. While frozen, calls to I_GetTime()
// will always return the same value.

View file

@ -292,6 +292,17 @@ public:
return i;
}
bool Contains(const T& item) const
{
unsigned int i;
for(i = 0;i < Count;++i)
{
if(Array[i] == item)
return true;
}
return false;
}
template<class Func>
unsigned int FindEx(Func compare) const
{

View file

@ -40,6 +40,7 @@
#include "buildtiles.h"
#include "bitmap.h"
#include "m_argv.h"
#include "gamestruct.h"
#include "gamecontrol.h"
#include "palettecontainer.h"
#include "mapinfo.h"
@ -2008,6 +2009,166 @@ void parseModel(FScanner& sc, FScriptPosition& pos)
}
}
//===========================================================================
//
//
//
//===========================================================================
static bool parseDefineQAVInterpolateIgnoreBlock(FScanner& sc, const int& res_id, TMap<int, TArray<int>>& ignoredata, const int& numframes)
{
FScanner::SavedPos blockend;
FScriptPosition pos = sc;
FString scframes, sctiles;
TArray<int> framearray, tilearray;
if (sc.StartBraces(&blockend))
{
pos.Message(MSG_ERROR, "defineqav (%d): interpolate: malformed syntax, unable to continue", res_id);
return false;
}
while (!sc.FoundEndBrace(blockend))
{
sc.GetString();
if (sc.Compare("frames")) sc.GetString(scframes);
else if (sc.Compare("tiles")) sc.GetString(sctiles);
}
// Confirm we received something for 'frames' and 'tiles'.
if (scframes.IsEmpty() || sctiles.IsEmpty())
{
pos.Message(MSG_ERROR, "defineqav (%d): interpolate: unable to get any values for 'frames' or 'tiles', unable to continue", res_id);
return false;
}
auto arraybuilder = [&](const FString& input, TArray<int>& output, const int& maxvalue) -> bool
{
// Split input if it is an array, otherwise push the singular value twice.
if (input.IndexOf("-") != -1)
{
auto temparray = input.Split("-");
for (auto& value : temparray) output.Push(atoi(value));
}
else
{
auto tempvalue = atoi(input);
for (auto i = 0; i < 2; i++) output.Push(tempvalue);
}
if (output.Size() != 2 || output[0] > output[1] || output[1] > maxvalue)
{
pos.Message(MSG_ERROR, "defineqav (%d): interpolate: ignore: value of '%s' is malformed, unable to continue", res_id, input.GetChars());
return false;
}
return true;
};
if (!arraybuilder(scframes, framearray, numframes - 1)) return false;
if (!arraybuilder(sctiles, tilearray, 7)) return false;
// Process arrays and add ignored frames as required.
for (auto i = framearray[0]; i <= framearray[1]; i++)
{
auto& frametiles = ignoredata[i];
for (auto j = tilearray[0]; j <= tilearray[1]; j++)
{
if (!frametiles.Contains(j)) frametiles.Push(j);
}
}
return true;
}
static bool parseDefineQAVInterpolateBlock(FScanner& sc, const int& res_id, const int& numframes)
{
FScanner::SavedPos blockend;
FScriptPosition pos = sc;
FString interptype;
bool loopable = false;
TMap<int, TArray<int>> ignoredata;
if (sc.StartBraces(&blockend))
{
pos.Message(MSG_ERROR, "defineqav (%d): interpolate (%s): malformed syntax, unable to continue", res_id, interptype.GetChars());
return false;
}
while (!sc.FoundEndBrace(blockend))
{
sc.GetString();
if (sc.Compare("type"))
{
sc.GetString(interptype);
if (!gi->IsQAVInterpTypeValid(interptype))
{
pos.Message(MSG_ERROR, "defineqav (%d): interpolate (%s): interpolation type not found", res_id, interptype.GetChars());
return false;
}
}
else if (sc.Compare("loopable")) loopable = true;
else if (sc.Compare("ignore")) if (!parseDefineQAVInterpolateIgnoreBlock(sc, res_id, ignoredata, numframes)) return false;
}
// Add interpolation properties to game for processing while drawing.
gi->AddQAVInterpProps(res_id, interptype, loopable, ignoredata);
return true;
}
void parseDefineQAV(FScanner& sc, FScriptPosition& pos)
{
FScanner::SavedPos blockend;
FString fn;
int res_id = -1;
int numframes = -1;
bool interpolate = false;
if (!sc.GetNumber(res_id, true))
{
pos.Message(MSG_ERROR, "defineqav: invalid or non-defined resource ID");
return;
}
if (sc.StartBraces(&blockend))
{
pos.Message(MSG_ERROR, "defineqav (%d): malformed syntax, unable to continue", res_id);
return;
}
while (!sc.FoundEndBrace(blockend))
{
sc.MustGetString();
if (sc.Compare("file"))
{
sc.GetString(fn);
// Test file's validity.
FixPathSeperator(fn);
auto lump = fileSystem.FindFile(fn);
if (lump < 0)
{
pos.Message(MSG_ERROR, "defineqav (%d): file '%s' could not be found", res_id, fn.GetChars());
return;
}
// Read file to get number of frames from QAV, skipping first 8 bytes.
auto fr = fileSystem.OpenFileReader(lump);
fr.ReadUInt64();
numframes = fr.ReadInt32();
}
else if (sc.Compare("interpolate"))
{
interpolate = true;
if (!parseDefineQAVInterpolateBlock(sc, res_id, numframes)) return;
}
}
// If we're not interpolating, remove any reference to interpolation data for this res_id.
if (!interpolate) gi->RemoveQAVInterpProps(res_id);
// Add new file to filesystem.
fileSystem.CreatePathlessCopy(fn, res_id, 0);
}
//===========================================================================
//
//
@ -2098,6 +2259,7 @@ static const dispatch basetokens[] =
{ "shadefactor", parseSkip<1> },
{ "newgamechoices", parseEmptyBlock },
{ "rffdefineid", parseRffDefineId },
{ "defineqav", parseDefineQAV },
{ nullptr, nullptr },
};

View file

@ -85,7 +85,8 @@ CVARD(Bool, cl_hudinterpolation, true, CVAR_ARCHIVE, "enable/disable HUD (weapon
CVARD(Bool, cl_bloodvanillarun, true, CVAR_ARCHIVE, "enable/disable Blood's vanilla run mode")
CVARD(Bool, cl_bloodvanillabobbing, true, CVAR_ARCHIVE, "enable/disable Blood's vanilla bobbing while not using vanilla run mode")
CVARD(Bool, cl_bloodvanillaexplosions, false, CVAR_ARCHIVE, "enable/disable Blood's original explosion behavior")
CVARD(Bool, cl_bloodhudinterp, false, CVAR_ARCHIVE, "enable/disable Blood's HUD interpolation")
CVARD(Bool, cl_bloodqavinterp, true, CVAR_ARCHIVE, "enable/disable Blood's QAV interpolation")
CVARD(Bool, cl_bloodweapinterp, false, CVAR_ARCHIVE, "enable/disable Blood's weapon interpolation. Depends on 'cl_bloodqavinterp'")
CVARD(Bool, cl_bloodoldweapbalance, false, CVAR_ARCHIVE, "enable/disable legacy 1.0 weapon handling for Blood")

View file

@ -30,7 +30,8 @@ EXTERN_CVAR(Bool, cl_hudinterpolation)
EXTERN_CVAR(Bool, cl_bloodvanillarun)
EXTERN_CVAR(Bool, cl_bloodvanillabobbing)
EXTERN_CVAR(Bool, cl_bloodvanillaexplosions)
EXTERN_CVAR(Bool, cl_bloodhudinterp)
EXTERN_CVAR(Bool, cl_bloodqavinterp)
EXTERN_CVAR(Bool, cl_bloodweapinterp)
EXTERN_CVAR(Bool, cl_bloodoldweapbalance)
EXTERN_CVAR(Bool, demorec_seeds_cvar)

View file

@ -156,3 +156,8 @@ inline int spriteGetSlope(int spritenum)
auto spr = &sprite[spritenum];
return ((spr->cstat & CSTAT_SPRITE_ALIGNMENT_MASK) != CSTAT_SPRITE_ALIGNMENT_SLOPE) ? 0 : uint8_t(spr->xoffset) + (uint8_t(spr->yoffset) << 8);
}
inline int I_GetBuildTime()
{
return I_GetTime(120);
}

View file

@ -122,6 +122,9 @@ struct GameInterface
virtual int Voxelize(int sprnum) { return -1; }
virtual void AddExcludedEpisode(FString episode) {}
virtual int GetCurrentSkill() { return -1; }
virtual bool IsQAVInterpTypeValid(const FString& type) { return false; }
virtual void AddQAVInterpProps(const int& res_id, const FString& interptype, const bool& loopable, const TMap<int, TArray<int>>& ignoredata) { }
virtual void RemoveQAVInterpProps(const int& res_id) { }
virtual FString statFPS()
{

View file

@ -444,7 +444,7 @@ static tspritetype *viewAddEffect(spritetype* tsprite, int& spritesortcnt, int n
assert(pTSprite->type >= kDudePlayer1 && pTSprite->type <= kDudePlayer8);
PLAYER *pPlayer = &gPlayer[pTSprite->type-kDudePlayer1];
WEAPONICON weaponIcon = gWeaponIcon[pPlayer->curWeapon];
const int nTile = weaponIcon.nTile;
auto& nTile = weaponIcon.nTile;
if (nTile < 0) break;
auto pNSprite = viewInsertTSprite(tsprite, spritesortcnt, pTSprite->sectnum, 32767, pTSprite);
if (!pNSprite)
@ -457,15 +457,14 @@ static tspritetype *viewAddEffect(spritetype* tsprite, int& spritesortcnt, int n
pNSprite->shade = pTSprite->shade;
pNSprite->xrepeat = 32;
pNSprite->yrepeat = 32;
const int nVoxel = voxelIndex[nTile];
auto& nVoxel = voxelIndex[nTile];
if (cl_showweapon == 2 && r_voxels && nVoxel != -1)
{
pNSprite->cstat |= 48;
pNSprite->cstat &= ~8;
pNSprite->picnum = nVoxel;
pNSprite->z -= weaponIcon.zOffset<<8;
const int lifeLeech = 9;
if (pPlayer->curWeapon == lifeLeech)
if (pPlayer->curWeapon == kWeapLifeLeech)
{
pNSprite->x -= MulScale(128, Cos(pNSprite->ang), 30);
pNSprite->y -= MulScale(128, Sin(pNSprite->ang), 30);
@ -479,7 +478,7 @@ static tspritetype *viewAddEffect(spritetype* tsprite, int& spritesortcnt, int n
static void viewApplyDefaultPal(tspritetype *pTSprite, sectortype const *pSector)
{
int const nXSector = pSector->extra;
auto& nXSector = pSector->extra;
XSECTOR const *pXSector = nXSector >= 0 ? &xsector[nXSector] : NULL;
if (pXSector && pXSector->color && (VanillaMode() || pSector->floorpal != 0))
{

View file

@ -200,6 +200,8 @@ void StartLevel(MapRecord* level, bool newgame)
pPlayer->qavLoop = gPlayerTemp[i].qavLoop;
pPlayer->weaponTimer = gPlayerTemp[i].weaponTimer;
pPlayer->nextWeapon = gPlayerTemp[i].nextWeapon;
pPlayer->qavLastTick = gPlayerTemp[i].qavLastTick;
pPlayer->qavTimer = gPlayerTemp[i].qavTimer;
}
}
PreloadCache();

View file

@ -150,6 +150,9 @@ struct GameInterface : public ::GameInterface
void LeavePortal(spritetype* viewer, int type) override;
void LoadGameTextures() override;
int GetCurrentSkill() override;
bool IsQAVInterpTypeValid(const FString& type) override;
void AddQAVInterpProps(const int& res_id, const FString& interptype, const bool& loopable, const TMap<int, TArray<int>>& ignoredata) override;
void RemoveQAVInterpProps(const int& res_id) override;
GameStats getStats() override;
};

View file

@ -449,6 +449,25 @@ enum
kAng360 = 2048,
};
// Weapon numbers
enum
{
kWeapNone = 0,
kWeapPitchFork = 1,
kWeapFlareGun = 2,
kWeapShotgun = 3,
kWeapTommyGun = 4,
kWeapNapalm = 5,
kWeapDynamite = 6,
kWeapSpraycan = 7,
kWeapTeslaCannon = 8,
kWeapLifeLeech = 9,
kWeapVoodooDoll = 10,
kWeapProximity = 11,
kWeapRemote = 12,
kWeapBeast = 13,
};
// -------------------------------
#pragma pack(push,1)

View file

@ -41,38 +41,30 @@ BEGIN_BLD_NS
class CGameMenuItemQAV
{
public:
int m_nX, m_nY;
TArray<uint8_t> raw;
QAV* data;
int duration;
int lastTick;
bool bWideScreen;
bool bClearBackground;
const char* filename;
CGameMenuItemQAV(int, int, const char*, bool widescreen = false, bool clearbackground = false);
void Draw(void);
};
CGameMenuItemQAV::CGameMenuItemQAV(int a3, int a4, const char* name, bool widescreen, bool clearbackground)
{
m_nY = a4;
m_nX = a3;
bWideScreen = widescreen;
bClearBackground = clearbackground;
filename = name;
if (name)
{
// NBlood read this directly from the file system cache, but let's better store the data locally for robustness.
raw = fileSystem.LoadFile(name, 0);
if (raw.Size() != 0)
data = getQAV(fileSystem.GetResourceId(fileSystem.FindFile(name)));
if (data)
{
auto data = (QAV*)raw.Data();
data->nSprite = -1;
data->x = m_nX;
data->y = m_nY;
//data->Preload();
data->x = a3;
data->y = a4;
duration = data->duration;
lastTick = I_GetTime();
lastTick = I_GetTime(data->ticrate);
}
}
}
@ -82,29 +74,18 @@ void CGameMenuItemQAV::Draw(void)
if (bClearBackground)
twod->ClearScreen();
if (raw.Size() > 0)
if (data)
{
auto data = (QAV*)raw.Data();
auto thisTick = I_GetTime();
if (!lastTick)
{
lastTick = thisTick;
}
if (lastTick < thisTick)
{
lastTick = thisTick;
duration -= 4;
}
qavProcessTicker(data, &duration, &lastTick);
if (duration <= 0 || duration > data->duration)
{
duration = data->duration;
}
auto currentDuration = data->duration - duration;
auto smoothratio = I_GetTimeFrac() * MaxSmoothRatio;
auto smoothratio = I_GetTimeFrac(data->ticrate) * MaxSmoothRatio;
data->Play(currentDuration - 4, currentDuration, -1, NULL);
data->Play(currentDuration - data->ticksPerFrame, currentDuration, -1, NULL);
if (bWideScreen)
{
@ -113,13 +94,13 @@ void CGameMenuItemQAV::Draw(void)
int backX = data->x;
for (int i = 0; i < nCount; i++)
{
data->Draw(currentDuration, 10 + kQavOrientationLeft, 0, 0, false, smoothratio, filename == "BDRIP.QAV");
data->Draw(currentDuration, 10 + kQavOrientationLeft, 0, 0, false, smoothratio);
data->x += 320;
}
data->x = backX;
}
else
data->Draw(currentDuration, 10, 0, 0, false, smoothratio, filename == "BDRIP.QAV");
data->Draw(currentDuration, 10, 0, 0, false, smoothratio);
}
}

View file

@ -127,14 +127,14 @@ void hudDraw(PLAYER *gView, int nSectnum, double bobx, double boby, double zDelt
}
#ifdef NOONE_EXTENSIONS
if (gView->sceneQav < 0) WeaponDraw(gView, nShade, cX, cY, nPalette, smoothratio);
else if (gView->pXSprite->health > 0) playerQavSceneDraw(gView, nShade, cX, cY, nPalette, smoothratio);
if (gView->sceneQav < 0) WeaponDraw(gView, nShade, cX, cY, nPalette);
else if (gView->pXSprite->health > 0) playerQavSceneDraw(gView, nShade, cX, cY, nPalette);
else {
gView->sceneQav = gView->weaponQav = -1;
gView->weaponTimer = gView->curWeapon = 0;
gView->sceneQav = gView->weaponQav = kQAVNone;
gView->qavTimer = gView->weaponTimer = gView->curWeapon = 0;
}
#else
WeaponDraw(gView, nShade, cX, cY, nPalette, smoothratio);
WeaponDraw(gView, nShade, cX, cY, nPalette);
#endif
}
if (gViewPos == 0 && gView->pXSprite->burnTime > 60)

View file

@ -102,8 +102,8 @@ void SetWeapons(bool stat)
{
// Keep the pitchfork to avoid freeze
gMe->hasWeapon[1] = 1;
gMe->curWeapon = 0;
gMe->nextWeapon = 1;
gMe->curWeapon = kWeapNone;
gMe->nextWeapon = kWeapPitchFork;
}
viewSetMessage(GStrings("TXTB_NOWEAP"));
}
@ -400,8 +400,8 @@ const char* GameInterface::GenericCheat(int player, int cheat)
powerupActivate(gMe, kPwUpDeliriumShroom);
gMe->pXSprite->health = 16;
gMe->hasWeapon[1] = 1;
gMe->curWeapon = 0;
gMe->nextWeapon = 1;
gMe->curWeapon = kWeapNone;
gMe->nextWeapon = kWeapPitchFork;
break;
default:

View file

@ -41,12 +41,10 @@ void DrawMirrors(int x, int y, int z, fixed_t a, fixed_t horiz, int smooth, int
int qanimateoffs(int a1, int a2);
void HookReplaceFunctions();
struct QAV;
struct PLAYER;
extern QAV* weaponQAV[];
void WeaponInit(void);
void WeaponDraw(PLAYER *pPlayer, int a2, double a3, double a4, int a5, double smoothratio);
void WeaponDraw(PLAYER *pPlayer, int a2, double a3, double a4, int a5);
void WeaponRaise(PLAYER *pPlayer);
void WeaponLower(PLAYER *pPlayer);
int WeaponUpgrade(PLAYER *pPlayer, int newWeapon);

View file

@ -1844,6 +1844,8 @@ void trPlayerCtrlStartScene(XSPRITE* pXSource, PLAYER* pPlayer, bool force) {
pPlayer->weaponTimer = pCtrl->qavScene.qavResrc->duration;
pPlayer->qavCallback = (pXSource->data3 > 0) ? ClipRange(pXSource->data3 - 1, 0, 32) : -1;
pPlayer->qavLoop = false;
pPlayer->qavLastTick = I_GetTime(pCtrl->qavScene.qavResrc->ticrate);
pPlayer->qavTimer = pCtrl->qavScene.qavResrc->duration;
}
@ -2037,8 +2039,8 @@ void trPlayerCtrlEraseStuff(XSPRITE* pXSource, PLAYER* pPlayer) {
}
pPlayer->hasWeapon[1] = true;
pPlayer->curWeapon = 0;
pPlayer->nextWeapon = 1;
pPlayer->curWeapon = kWeapNone;
pPlayer->nextWeapon = kWeapPitchFork;
WeaponRaise(pPlayer);
if (pXSource->data2) break;
@ -2080,8 +2082,8 @@ void trPlayerCtrlGiveStuff(XSPRITE* pXSource, PLAYER* pPlayer, TRPLAYERCTRL* pCt
break;
}
switch (weapon) {
case 11: // remote bomb
case 12: // prox bomb
case kWeapProximity: // remote bomb
case kWeapRemote: // prox bomb
pPlayer->hasWeapon[weapon] = true;
weapon--;
pPlayer->ammoCount[weapon] = ClipHigh(pPlayer->ammoCount[weapon] + ((pXSource->data2 == 2) ? pXSource->data4 : 1), gAmmoInfo[weapon].max);
@ -2108,7 +2110,7 @@ void trPlayerCtrlGiveStuff(XSPRITE* pXSource, PLAYER* pPlayer, TRPLAYERCTRL* pCt
break;
}
if (pPlayer->hasWeapon[weapon] && pXSource->data4 == 0) { // switch on it
pPlayer->nextWeapon = 0;
pPlayer->nextWeapon = kWeapNone;
if (pPlayer->sceneQav >= 0 && spriRangeIsFine(pCtrl->qavScene.index)) {
XSPRITE* pXScene = &xsprite[sprite[pCtrl->qavScene.index].extra];
@ -5062,7 +5064,7 @@ bool modernTypeOperateSprite(int nSprite, spritetype* pSprite, XSPRITE* pXSprite
switch (cmd) {
case 36:
actHealDude(pPlayer->pXSprite, ((pXSprite->data2 > 0) ? ClipHigh(pXSprite->data2, 200) : getDudeInfo(pPlayer->pSprite->type)->startHealth), 200);
pPlayer->curWeapon = 1;
pPlayer->curWeapon = kWeapPitchFork;
break;
}
@ -6180,7 +6182,7 @@ void playerQavSceneProcess(PLAYER* pPlayer, QAVSCENE* pQavScene) {
}
}
void playerQavSceneDraw(PLAYER* pPlayer, int a2, double a3, double a4, int a5, double smoothratio) {
void playerQavSceneDraw(PLAYER* pPlayer, int a2, double a3, double a4, int a5) {
if (pPlayer == NULL || pPlayer->sceneQav == -1) return;
QAVSCENE* pQavScene = &gPlayerCtrl[pPlayer->nPlayer].qavScene;
@ -6189,7 +6191,10 @@ void playerQavSceneDraw(PLAYER* pPlayer, int a2, double a3, double a4, int a5, d
if (pQavScene->qavResrc != NULL) {
QAV* pQAV = pQavScene->qavResrc;
int v4 = (pPlayer->weaponTimer == 0) ? ((PlayClock + MulScale(4, int(smoothratio), 16)) % pQAV->duration) : pQAV->duration - pPlayer->weaponTimer;
int v4;
double smoothratio;
qavProcessTimer(pPlayer, pQAV, &v4, &smoothratio);
int flags = 2; int nInv = powerupCheck(pPlayer, kPwUpShadowCloak);
if (nInv >= 120 * 8 || (nInv != 0 && (PlayClock & 32))) {

View file

@ -384,7 +384,7 @@ void playerDeactivateShrooms(PLAYER* pPlayer);
QAV* playerQavSceneLoad(int qavId);
void playerQavSceneProcess(PLAYER* pPlayer, QAVSCENE* pQavScene);
void playerQavScenePlay(PLAYER* pPlayer);
void playerQavSceneDraw(PLAYER* pPlayer, int a2, double a3, double a4, int a5, double smoothratio);
void playerQavSceneDraw(PLAYER* pPlayer, int a2, double a3, double a4, int a5);
void playerQavSceneReset(PLAYER* pPlayer);
// ------------------------------------------------------------------------- //
void callbackUniMissileBurst(int nSprite);

View file

@ -722,7 +722,7 @@ void playerStart(int nPlayer, int bNewLevel)
gFullMap = 0;
pPlayer->throwPower = 0;
pPlayer->deathTime = 0;
pPlayer->nextWeapon = 0;
pPlayer->nextWeapon = kWeapNone;
xvel[pSprite->index] = yvel[pSprite->index] = zvel[pSprite->index] = 0;
pInput->avel = 0;
pInput->actions = 0;
@ -739,7 +739,9 @@ void playerStart(int nPlayer, int bNewLevel)
pPlayer->handTime = 0;
pPlayer->weaponTimer = 0;
pPlayer->weaponState = 0;
pPlayer->weaponQav = -1;
pPlayer->weaponQav = kQAVNone;
pPlayer->qavLastTick = 0;
pPlayer->qavTimer = 0;
#ifdef NOONE_EXTENSIONS
playerQavSceneReset(pPlayer); // reset qav scene
@ -792,9 +794,9 @@ void playerReset(PLAYER *pPlayer)
pPlayer->weaponMode[i] = 0;
}
pPlayer->hasWeapon[1] = 1;
pPlayer->curWeapon = 0;
pPlayer->curWeapon = kWeapNone;
pPlayer->qavCallback = -1;
pPlayer->newWeapon = 1;
pPlayer->newWeapon = kWeapPitchFork;
for (int i = 0; i < 14; i++)
{
pPlayer->weaponOrder[0][i] = dword_136400[i];
@ -811,8 +813,10 @@ void playerReset(PLAYER *pPlayer)
pPlayer->armor[i] = 0;
pPlayer->weaponTimer = 0;
pPlayer->weaponState = 0;
pPlayer->weaponQav = -1;
pPlayer->weaponQav = kQAVNone;
pPlayer->qavLoop = 0;
pPlayer->qavLastTick = 0;
pPlayer->qavTimer = 0;
pPlayer->packItemId = -1;
for (int i = 0; i < 5; i++) {
@ -1964,7 +1968,7 @@ int playerDamageSprite(DBloodActor* source, PLAYER *pPlayer, DAMAGE_TYPE nDamage
}
pPlayer->deathTime = 0;
pPlayer->qavLoop = 0;
pPlayer->curWeapon = 0;
pPlayer->curWeapon = kWeapNone;
pPlayer->fraggerId = nSource;
pPlayer->voodooTargets = 0;
if (nDamageType == kDamageExplode && nDamage < (9<<4))
@ -2130,7 +2134,7 @@ void PlayerSurvive(int, DBloodActor* actor)
sprintf(buffer, "%s lives again!", PlayerName(pPlayer->nPlayer));
viewSetMessage(buffer);
}
pPlayer->newWeapon = 1;
pPlayer->newWeapon = kWeapPitchFork;
}
}
}
@ -2249,6 +2253,8 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, PLAYER& w, PLAYER*
.Array("weaponorder", &w.weaponOrder[0][0], 14*2)
.Array("ammocount", w.ammoCount, countof(w.ammoCount))
("qavloop", w.qavLoop)
("qavlastTick", w.qavLastTick)
("qavtimer", w.qavTimer)
("fusetime", w.fuseTime)
("throwtime", w.throwTime)
("throwpower", w.throwPower)

View file

@ -127,6 +127,8 @@ struct PLAYER
//int at149[14];
int ammoCount[12];
bool qavLoop;
int qavLastTick;
int qavTimer;
int fuseTime;
int throwTime;
int throwPower;

View file

@ -34,6 +34,73 @@ BEGIN_BLD_NS
extern void (*qavClientCallback[])(int, void *);
//==========================================================================
//
// QAV interpolation functions
//
//==========================================================================
enum
{
kQAVIsLoopable,
};
static TMap<FString, QAVPrevTileFinder> qavPrevTileFinders;
static TMap<int, QAVInterpProps> qavInterpProps;
static void qavInitTileFinderMap()
{
// Interpolate between frames if the picnums match. This is safest but could miss interpolations between suitable picnums.
qavPrevTileFinders.Insert("picnum", [](FRAMEINFO* const thisFrame, FRAMEINFO* const prevFrame, const int& i) -> TILE_FRAME* {
return prevFrame->tiles[i].picnum == thisFrame->tiles[i].picnum ? &prevFrame->tiles[i] : nullptr;
});
// Interpolate between frames if the picnum is valid. This can be problematic if tile indices change between frames.
qavPrevTileFinders.Insert("index", [](FRAMEINFO* const thisFrame, FRAMEINFO* const prevFrame, const int& i) -> TILE_FRAME* {
return prevFrame->tiles[i].picnum > 0 ? &prevFrame->tiles[i] : nullptr;
});
// Find previous frame by iterating all previous frame's tiles and return on first matched x coordinate.
qavPrevTileFinders.Insert("x", [](FRAMEINFO* const thisFrame, FRAMEINFO* const prevFrame, const int& i) -> TILE_FRAME* {
for (int j = 0; j < 8; j++) if (thisFrame->tiles[i].x == prevFrame->tiles[j].x)
{
return &prevFrame->tiles[j];
}
return nullptr;
});
// Find previous frame by iterating all previous frame's tiles and return on first matched y coordinate.
qavPrevTileFinders.Insert("y", [](FRAMEINFO* const thisFrame, FRAMEINFO* const prevFrame, const int& i) -> TILE_FRAME* {
for (int j = 0; j < 8; j++) if (thisFrame->tiles[i].y == prevFrame->tiles[j].y)
{
return &prevFrame->tiles[j];
}
return nullptr;
});
}
QAVPrevTileFinder qavGetInterpType(const FString& type)
{
if (!qavPrevTileFinders.CountUsed()) qavInitTileFinderMap();
return *qavPrevTileFinders.CheckKey(type);
}
bool GameInterface::IsQAVInterpTypeValid(const FString& type)
{
return qavGetInterpType(type) != nullptr;
}
void GameInterface::AddQAVInterpProps(const int& res_id, const FString& interptype, const bool& loopable, const TMap<int, TArray<int>>& ignoredata)
{
qavInterpProps.Insert(res_id, { loopable << kQAVIsLoopable, qavGetInterpType(interptype), ignoredata });
}
void GameInterface::RemoveQAVInterpProps(const int& res_id)
{
qavInterpProps.Remove(res_id);
}
void DrawFrame(double x, double y, double z, double a, TILE_FRAME *pTile, int stat, int shade, int palnum, bool to3dview)
{
stat |= pTile->stat;
@ -72,85 +139,48 @@ void DrawFrame(double x, double y, double z, double a, TILE_FRAME *pTile, int st
}
}
void QAV::Draw(double x, double y, int ticks, int stat, int shade, int palnum, bool to3dview, double const smoothratio, bool const menudrip)
void QAV::Draw(double x, double y, int ticks, int stat, int shade, int palnum, bool to3dview, double const smoothratio)
{
assert(ticksPerFrame > 0);
int nFrame = ticks / ticksPerFrame;
assert(nFrame >= 0 && nFrame < nFrames);
FRAMEINFO *thisFrame = &frames[nFrame];
auto const interpdata = qavInterpProps.CheckKey(res_id);
if ((nFrame == (nFrames - 1)) && !lastframetic)
{
lastframetic = ticks;
}
else if (lastframetic > ticks)
{
lastframetic = 0;
}
auto const nFrame = clamp(ticks / ticksPerFrame, 0, nFrames - 1);
FRAMEINFO* const thisFrame = &frames[nFrame];
int oFrame = nFrame == 0 || (lastframetic && ticks > lastframetic) ? nFrame : nFrame - 1;
assert(oFrame >= 0 && oFrame < nFrames);
FRAMEINFO *prevFrame = &frames[oFrame];
auto const oFrame = clamp((nFrame == 0 && (interpdata && (interpdata->flags & kQAVIsLoopable)) ? nFrames : nFrame) - 1, 0, nFrames - 1);
FRAMEINFO* const prevFrame = &frames[oFrame];
auto drawTile = [&](TILE_FRAME *thisTile, TILE_FRAME *prevTile, bool const interpolate = true)
{
double tileX = x;
double tileY = y;
double tileZ;
double tileA;
if (cl_bloodhudinterp && prevTile && cl_hudinterpolation && (nFrames > 1) && (nFrame != oFrame) && (smoothratio != MaxSmoothRatio) && interpolate)
{
tileX += interpolatedvaluef(prevTile->x, thisTile->x, smoothratio);
tileY += interpolatedvaluef(prevTile->y, thisTile->y, smoothratio);
tileZ = interpolatedvaluef(prevTile->z, thisTile->z, smoothratio);
tileA = interpolatedangle(buildang(prevTile->angle), buildang(thisTile->angle), smoothratio).asbuildf();
}
else
{
tileX += thisTile->x;
tileY += thisTile->y;
tileZ = thisTile->z;
tileA = thisTile->angle;
}
DrawFrame(tileX, tileY, tileZ, tileA, thisTile, stat, shade, palnum, to3dview);
};
bool const interpolate = interpdata && cl_hudinterpolation && cl_bloodqavinterp && (nFrames > 1) && (nFrame != oFrame) && (smoothratio != MaxSmoothRatio);
for (int i = 0; i < 8; i++)
{
TILE_FRAME *thisTile = &thisFrame->tiles[i];
TILE_FRAME *prevTile = nullptr;
if (thisTile->picnum > 0)
if (thisFrame->tiles[i].picnum > 0)
{
// Menu's blood drip requires special treatment.
if (menudrip)
{
if (i != 0)
{
// Find previous frame by iterating all previous frame's tiles and match on the consistent x coordinate.
// Tile indices can change between frames for no reason, we need to accomodate that.
for (int j = 0; j < 8; j++) if (thisTile->x == prevFrame->tiles[j].x)
{
prevTile = &prevFrame->tiles[j];
break;
}
TILE_FRAME* const thisTile = &thisFrame->tiles[i];
TILE_FRAME* const prevTile = interpolate && interpdata->CanInterpFrameTile(nFrame, i) ? interpdata->PrevTileFinder(thisFrame, prevFrame, i) : nullptr;
drawTile(thisTile, prevTile, true);
}
else
{
// First index is always the dripping bar at the top.
drawTile(thisTile, prevTile, false);
}
double tileX = x;
double tileY = y;
double tileZ;
double tileA;
if (prevTile)
{
tileX += interpolatedvaluef(prevTile->x, thisTile->x, smoothratio);
tileY += interpolatedvaluef(prevTile->y, thisTile->y, smoothratio);
tileZ = interpolatedvaluef(prevTile->z, thisTile->z, smoothratio);
tileA = interpolatedangle(buildang(prevTile->angle), buildang(thisTile->angle), smoothratio).asbuildf();
}
else
{
prevTile = &prevFrame->tiles[i];
drawTile(thisTile, prevTile, thisTile->picnum == prevTile->picnum);
tileX += thisTile->x;
tileY += thisTile->y;
tileZ = thisTile->z;
tileA = thisTile->angle;
}
DrawFrame(tileX, tileY, tileZ, tileA, thisTile, stat, shade, palnum, to3dview);
}
}
}
@ -221,35 +251,44 @@ void QAV::Precache(int palette)
}
}
void ByteSwapQAV(void* p)
void qavProcessTicker(QAV* const pQAV, int* duration, int* lastTick)
{
#if B_BIG_ENDIAN == 1
QAV* qav = (QAV*)p;
qav->nFrames = LittleLong(qav->nFrames);
qav->ticksPerFrame = LittleLong(qav->ticksPerFrame);
qav->version = LittleLong(qav->version);
qav->x = LittleLong(qav->x);
qav->y = LittleLong(qav->y);
qav->nSprite = LittleLong(qav->nSprite);
for (int i = 0; i < qav->nFrames; i++)
if (*duration > 0)
{
FRAMEINFO* pFrame = &qav->frames[i];
SOUNDINFO* pSound = &pFrame->sound;
pFrame->nCallbackId = LittleLong(pFrame->nCallbackId);
pSound->sound = LittleLong(pSound->sound);
for (int j = 0; j < 8; j++)
auto thisTick = I_GetTime(pQAV->ticrate);
auto numTicks = thisTick - (*lastTick);
if (numTicks)
{
TILE_FRAME* pTile = &pFrame->tiles[j];
pTile->picnum = LittleLong(pTile->picnum);
pTile->x = LittleLong(pTile->x);
pTile->y = LittleLong(pTile->y);
pTile->z = LittleLong(pTile->z);
pTile->stat = LittleLong(pTile->stat);
pTile->angle = LittleShort(pTile->angle);
*lastTick = thisTick;
*duration -= pQAV->ticksPerFrame * numTicks;
}
}
#endif
*duration = ClipLow(*duration, 0);
}
void qavProcessTimer(PLAYER* const pPlayer, QAV* const pQAV, int* duration, double* smoothratio, bool const fixedduration)
{
// Process clock based on QAV's ticrate and last tick value.
qavProcessTicker(pQAV, &pPlayer->qavTimer, &pPlayer->qavLastTick);
if (pPlayer->weaponTimer == 0)
{
// Check if we're playing an idle QAV as per the ticker's weapon timer.
*duration = fixedduration ? pQAV->duration - 1 : I_GetBuildTime() % pQAV->duration;
*smoothratio = MaxSmoothRatio;
}
else if (pPlayer->qavTimer == 0)
{
// If qavTimer is 0, play the last frame uninterpolated. Sometimes the timer can be just ahead of weaponTimer.
*duration = pQAV->duration - 1;
*smoothratio = MaxSmoothRatio;
}
else
{
// Apply normal values.
*duration = pQAV->duration - pPlayer->qavTimer;
*smoothratio = I_GetTimeFrac(pQAV->ticrate) * MaxSmoothRatio;
}
}
@ -269,10 +308,52 @@ QAV* getQAV(int res_id)
return nullptr;
}
auto fr = fileSystem.OpenFileReader(index);
auto qavdata = (QAV*)seqcache.Alloc(fr.GetLength());
fr.Read(qavdata, fr.GetLength());
// Start reading QAV for nFrames, skipping padded data.
for (int i = 0; i < 8; i++) fr.ReadUInt8();
int nFrames = fr.ReadInt32();
auto qavdata = (QAV*)seqcache.Alloc(sizeof(QAV) + ((nFrames - 1) * sizeof(FRAMEINFO)));
// Write out QAV data.
qavdata->nFrames = nFrames;
qavdata->ticksPerFrame = fr.ReadInt32();
qavdata->duration = fr.ReadInt32();
qavdata->x = fr.ReadInt32();
qavdata->y = fr.ReadInt32();
qavdata->nSprite = fr.ReadInt32();
for (int i = 0; i < 4; i++) fr.ReadUInt8();
// Read FRAMEINFO data.
for (int i = 0; i < qavdata->nFrames; i++)
{
qavdata->frames[i].nCallbackId = fr.ReadInt32();
// Read SOUNDINFO data.
qavdata->frames[i].sound.sound = fr.ReadInt32();
qavdata->frames[i].sound.priority = fr.ReadUInt8();
qavdata->frames[i].sound.sndFlags = fr.ReadUInt8();
qavdata->frames[i].sound.sndRange = fr.ReadUInt8();
for (int i = 0; i < 1; i++) fr.ReadUInt8();
// Read TILE_FRAME data.
for (int j = 0; j < 8; j++)
{
qavdata->frames[i].tiles[j].picnum = fr.ReadInt32();
qavdata->frames[i].tiles[j].x = fr.ReadInt32();
qavdata->frames[i].tiles[j].y = fr.ReadInt32();
qavdata->frames[i].tiles[j].z = fr.ReadInt32();
qavdata->frames[i].tiles[j].stat = fr.ReadInt32();
qavdata->frames[i].tiles[j].shade = fr.ReadInt8();
qavdata->frames[i].tiles[j].palnum = fr.ReadUInt8();
qavdata->frames[i].tiles[j].angle = fr.ReadUInt16();
}
}
// Write out additions.
qavdata->res_id = res_id;
qavdata->ticrate = 120. / qavdata->ticksPerFrame;
qavcache.Insert(res_id, qavdata);
ByteSwapQAV(qavdata);
return qavdata;
}

View file

@ -29,7 +29,159 @@ BEGIN_BLD_NS
enum { kQavOrientationLeft = 4096 };
#pragma pack(push, 1)
enum
{
kQAVNone = -1,
kQAVFORKUP = 0,
kQAVFORKIDLE = 1,
kQAVPFORK = 2,
kQAVFORKDOWN = 3,
kQAVLITEOPEN = 4,
kQAVLITEFLAM = 5,
kQAVLITEIDLE = 6,
kQAVLITECLO2 = 7,
kQAVCANPREF = 8,
kQAVCANIDLE = 9,
kQAVCANFIRE = 10,
kQAVCANDOWN = 11,
kQAVCANFIRE2 = 12,
kQAVCANDROP = 13,
kQAVCANTHRO = 14,
kQAVCANBOOM = 15,
kQAVBUNUP = 16,
kQAVBUNDOWN = 17,
kQAVBUNUP2 = 18,
kQAVBUNDOWN2 = 19,
kQAVBUNIDLE = 20,
kQAVBUNFUSE = 21,
kQAVBUNDROP = 22,
kQAVBUNTHRO = 23,
kQAVDYNEXPLO = 24,
kQAVPROXUP = 25,
kQAVPROXDOWN = 26,
kQAVPROXIDLE = 27,
kQAVPROXDROP = 28,
kQAVPROXTHRO = 29,
kQAVREMUP1 = 30,
kQAVREMUP2 = 31,
kQAVREMUP3 = 32,
kQAVREMDOWN1 = 33,
kQAVREMDOWN2 = 34,
kQAVREMDOWN3 = 35,
kQAVREMIDLE1 = 36,
kQAVREMIDLE2 = 37,
kQAVREMDROP = 38,
kQAVREMTHRO = 39,
kQAVREMFIRE = 40,
kQAVFLARUP = 41,
kQAVFLARIDLE = 42,
kQAVFLARFIR2 = 43,
kQAVFLARDOWN = 44,
kQAVFLAR2UP = 45,
kQAVFLAR2I = 46,
kQAVFLAR2F = 47,
kQAVFLAR2FIR = 48,
kQAVFLAR2DWN = 49,
kQAVSHOTUP = 50,
kQAVSHOTI3 = 51,
kQAVSHOTI2 = 52,
kQAVSHOTI1 = 53,
kQAVSHOTF1 = 54,
kQAVSHOTF2 = 55,
kQAVSHOTF3 = 56,
kQAVSHOTL1 = 57,
kQAVSHOTDOWN = 58,
kQAV2SHOTUP = 59,
kQAV2SHOTI = 60,
kQAV2SHOTF2 = 61,
kQAV2SHOTFIR = 62,
kQAV2SHOTDWN = 63,
kQAVTOMUP = 64,
kQAVTOMIDLE = 65,
kQAVTOMFIRE = 66,
kQAVTOMSPRED = 67,
kQAVTOMDOWN = 68,
kQAV2TOMUP = 69,
kQAV2TOMIDLE = 70,
kQAV2TOMFIRE = 71,
kQAV2TOMDOWN = 72,
kQAV2TOMALT = 73,
kQAVSGUNUP = 74,
kQAVSGUNIDL1 = 75,
kQAVSGUNIDL2 = 76,
kQAVSGUNFIR1 = 77,
kQAVSGUNFIR4 = 78,
kQAVSGUNPRE = 79,
kQAVSGUNPOST = 80,
kQAVSGUNDOWN = 81,
kQAV2SGUNUP = 82,
kQAV2SGUNIDL = 83,
kQAV2SGUNFIR = 84,
kQAV2SGUNALT = 85,
kQAV2SGUNPRE = 86,
kQAV2SGUNPST = 87,
kQAV2SGUNDWN = 88,
kQAVNAPUP = 89,
kQAVNAPIDLE = 90,
kQAVNAPFIRE = 91,
kQAVNAPDOWN = 92,
kQAVBSTUP = 93,
kQAVBSTIDLE = 94,
kQAVBSTATAK1 = 95,
kQAVBSTATAK2 = 96,
kQAVBSTATAK3 = 97,
kQAVBSTATAK4 = 98,
kQAVBSTDOWN = 99,
kQAVVDUP = 100,
kQAVVDIDLE1 = 101,
kQAVVDIDLE2 = 102,
kQAVVDFIRE1 = 103,
kQAVVDFIRE2 = 104,
kQAVVDFIRE3 = 105,
kQAVVDFIRE4 = 106,
kQAVVDFIRE5 = 107,
kQAVVDFIRE6 = 108,
kQAVVDDOWN = 109,
kQAVVDSPEL1 = 110,
kQAVSTAFUP = 111,
kQAVSTAFIDL1 = 112,
kQAVSTAFIDL3 = 113,
kQAVSTAFIRE1 = 114,
kQAVSTAFIRE2 = 115,
kQAVSTAFIRE4 = 116,
kQAVSTAFPRE = 117,
kQAVSTAFPOST = 118,
kQAVSTAFDOWN = 119,
kQAV2NAPUP = 120,
kQAV2NAPIDLE = 121,
kQAV2NAPFIRE = 122,
kQAV2NAPFIR2 = 123,
kQAV2NAPDOWN = 124,
kQAVEnd = 125,
kQAVBDRIP = 256,
};
// by NoOne: add sound flags
enum
@ -69,7 +221,7 @@ struct FRAMEINFO
struct QAV
{
char pad1[8]; // 0
double ticrate; // 0
int nFrames; // 8
int ticksPerFrame; // C
int duration; // 10
@ -77,17 +229,44 @@ struct QAV
int y; // 18
int nSprite; // 1c
//SPRITE *pSprite; // 1c
char pad3[3]; // 20
char lastframetic;
char pad3[2]; // 20
unsigned short res_id;
FRAMEINFO frames[1]; // 24
void Draw(double x, double y, int ticks, int stat, int shade, int palnum, bool to3dview, double const smoothratio = 65536, bool const menudrip = false);
void Draw(int ticks, int stat, int shade, int palnum, bool to3dview, double const smoothratio = 65536, bool const menudrip = false) { Draw(x, y, ticks, stat, shade, palnum, to3dview, smoothratio, menudrip); }
void Draw(double x, double y, int ticks, int stat, int shade, int palnum, bool to3dview, double const smoothratio = 65536);
void Draw(int ticks, int stat, int shade, int palnum, bool to3dview, double const smoothratio = 65536) { Draw(x, y, ticks, stat, shade, palnum, to3dview, smoothratio); }
void Play(int, int, int, void *);
void Precache(int palette = 0);
};
#pragma pack(pop)
using QAVPrevTileFinder = TILE_FRAME* (*)(FRAMEINFO* const thisFrame, FRAMEINFO* const prevFrame, const int& i);
struct QAVInterpProps
{
int flags;
QAVPrevTileFinder PrevTileFinder;
TMap<int, TArray<int>> IgnoreData;
bool CanInterpFrameTile(const int& nFrame, const int& i)
{
// Check whether the current frame's tile is skippable.
auto thisFrame = IgnoreData.CheckKey(nFrame);
return thisFrame ? !thisFrame->Contains(i) : true;
}
};
QAV* getQAV(int res_id);
void qavProcessTicker(QAV* const pQAV, int* duration, int* lastTick);
void qavProcessTimer(PLAYER* const pPlayer, QAV* const pQAV, int* duration, double* smoothratio, bool const fixedduration = false);
inline bool qavIsOriginal(const int& res_id)
{
auto const lump = fileSystem.FindResource(res_id, "QAV");
return lump >= 0 && fileSystem.GetFileContainer(lump) < fileSystem.GetMaxIwadNum();
}
inline int qavGetCorrectID(const int& res_id)
{
return cl_bloodweapinterp && qavIsOriginal(res_id) && fileSystem.FindResource(res_id + 10000, "QAV") != -1 ? res_id + 10000 : res_id;
}
END_BLD_NS

View file

@ -208,7 +208,7 @@ void LifeLeechOperate(spritetype *pSprite, XSPRITE *pXSprite, EVENT event)
{
pPlayer->ammoCount[8] = ClipHigh(pPlayer->ammoCount[8]+pXSprite->data3, gAmmoInfo[8].max);
pPlayer->hasWeapon[9] = 1;
if (pPlayer->curWeapon != 9)
if (pPlayer->curWeapon != kWeapLifeLeech)
{
pPlayer->weaponState = 0;
pPlayer->nextWeapon = 9;

File diff suppressed because it is too large Load diff

View file

@ -59,3 +59,812 @@ tilefromtexture 9277 { file "tiles/9277.png" }
tilefromtexture 9278 { file "tiles/9278.png" }
tilefromtexture 9279 { file "tiles/9279.png" }
tilefromtexture 9280 { file "tiles/9280.png" }
// Patched tiles for QAV interpolation, thanks to Phredreeke for supplying these.
tilefromtexture 9300 { file "tiles/9300(3227+3228).png" }
tilefromtexture 9301 { file "tiles/9301(3227+3229).png" }
tilefromtexture 9302 { file "tiles/9302(3227+3230).png" }
tilefromtexture 9303 { file "tiles/9303(3227+3231).png" }
tilefromtexture 9304 { file "tiles/9304(3227+3232).png" }
tilefromtexture 9305 { file "tiles/9305(3240+3228).png" }
tilefromtexture 9306 { file "tiles/9306(3240+3229).png" }
tilefromtexture 9307 { file "tiles/9307(3240+3230).png" }
tilefromtexture 9308 { file "tiles/9308(3240+3231).png" }
tilefromtexture 9309 { file "tiles/9309(3240+3232).png" }
// Interpolatable QAV files.
defineqav 10000 {
file "qavs/FORKUP.QAV"
interpolate {
type "index"
}
}
defineqav 10001 {
file "qavs/FORKIDLE.QAV"
interpolate {
type "index"
}
}
defineqav 10002 {
file "qavs/PFORK.QAV"
interpolate {
type "index"
loopable
}
}
defineqav 10003 {
file "qavs/FORKDOWN.QAV"
interpolate {
type "index"
}
}
defineqav 10004 {
file "qavs/LITEOPEN.QAV"
interpolate {
type "index"
}
}
defineqav 10005 {
file "qavs/LITEFLAM.QAV"
interpolate {
type "index"
ignore {
frames 3-6 tiles 1
}
}
}
defineqav 10006 {
file "qavs/LITEIDLE.QAV"
interpolate {
type "index"
}
}
defineqav 10007 {
file "qavs/LITECLO2.QAV"
interpolate {
type "index"
}
}
defineqav 10008 {
file "qavs/CANPREF.QAV"
interpolate {
type "index"
}
}
defineqav 10009 {
file "qavs/CANIDLE.QAV"
interpolate {
type "index"
}
}
defineqav 10010 {
file "qavs/CANFIRE.QAV"
interpolate {
type "index"
}
}
defineqav 10011 {
file "qavs/CANDOWN.QAV"
interpolate {
type "index"
}
}
defineqav 10012 {
file "qavs/CANFIRE2.QAV"
interpolate {
type "index"
ignore {
frames 14-99 tiles 2-3
}
}
}
defineqav 10013 {
file "qavs/CANDROP.QAV"
interpolate {
type "index"
}
}
defineqav 10014 {
file "qavs/CANTHRO.QAV"
interpolate {
type "index"
}
}
defineqav 10015 {
file "qavs/CANBOOM.QAV"
interpolate {
type "index"
}
}
defineqav 10016 {
file "qavs/BUNUP.QAV"
interpolate {
type "index"
}
}
defineqav 10017 {
file "qavs/BUNDOWN.QAV"
interpolate {
type "index"
}
}
defineqav 10018 {
file "qavs/BUNUP2.QAV"
interpolate {
type "index"
}
}
defineqav 10019 {
file "qavs/BUNDOWN2.QAV"
interpolate {
type "index"
}
}
defineqav 10020 {
file "qavs/BUNIDLE.QAV"
interpolate {
type "index"
}
}
defineqav 10021 {
file "qavs/BUNFUSE.QAV"
interpolate {
type "index"
ignore {
frames 6-65 tiles 0-7
}
}
}
defineqav 10022 {
file "qavs/BUNDROP.QAV"
interpolate {
type "index"
}
}
defineqav 10023 {
file "qavs/BUNTHRO.QAV"
interpolate {
type "index"
}
}
defineqav 10024 {
file "qavs/DYNEXPLO.QAV"
interpolate {
type "index"
}
}
defineqav 10025 {
file "qavs/PROXUP.QAV"
interpolate {
type "index"
}
}
defineqav 10026 {
file "qavs/PROXDOWN.QAV"
interpolate {
type "index"
}
}
defineqav 10027 {
file "qavs/PROXIDLE.QAV"
interpolate {
type "index"
}
}
defineqav 10028 {
file "qavs/PROXDROP.QAV"
interpolate {
type "index"
}
}
defineqav 10029 {
file "qavs/PROXTHRO.QAV"
interpolate {
type "index"
}
}
defineqav 10030 {
file "qavs/REMUP1.QAV"
interpolate {
type "index"
}
}
defineqav 10031 {
file "qavs/REMUP2.QAV"
interpolate {
type "index"
}
}
defineqav 10032 {
file "qavs/REMUP3.QAV"
interpolate {
type "index"
}
}
defineqav 10033 {
file "qavs/REMDOWN1.QAV"
interpolate {
type "index"
}
}
defineqav 10034 {
file "qavs/REMDOWN2.QAV"
interpolate {
type "index"
}
}
defineqav 10035 {
file "qavs/REMDOWN3.QAV"
interpolate {
type "index"
}
}
defineqav 10036 {
file "qavs/REMIDLE1.QAV"
interpolate {
type "index"
loopable
}
}
defineqav 10037 {
file "qavs/REMIDLE2.QAV"
interpolate {
type "index"
loopable
}
}
defineqav 10038 {
file "qavs/REMDROP.QAV"
interpolate {
type "index"
}
}
defineqav 10039 {
file "qavs/REMTHRO.QAV"
interpolate {
type "index"
}
}
defineqav 10040 {
file "qavs/REMFIRE.QAV"
interpolate {
type "index"
}
}
defineqav 10041 {
file "qavs/FLARUP.QAV"
interpolate {
type "index"
}
}
defineqav 10042 {
file "qavs/FLARIDLE.QAV"
interpolate {
type "index"
}
}
defineqav 10043 {
file "qavs/FLARFIR2.QAV"
interpolate {
type "index"
loopable
}
}
defineqav 10044 {
file "qavs/FLARDOWN.QAV"
interpolate {
type "index"
}
}
defineqav 10045 {
file "qavs/FLAR2UP.QAV"
interpolate {
type "index"
}
}
defineqav 10046 {
file "qavs/FLAR2I.QAV"
interpolate {
type "index"
}
}
defineqav 10047 {
file "qavs/FLAR2F.QAV"
interpolate {
type "index"
}
}
defineqav 10048 {
file "qavs/FLAR2FIR.QAV"
interpolate {
type "index"
}
}
defineqav 10049 {
file "qavs/FLAR2DWN.QAV"
interpolate {
type "index"
}
}
defineqav 10050 {
file "qavs/SHOTUP.QAV"
interpolate {
type "index"
}
}
defineqav 10051 {
file "qavs/SHOTI3.QAV"
interpolate {
type "index"
}
}
defineqav 10052 {
file "qavs/SHOTI2.QAV"
interpolate {
type "index"
}
}
defineqav 10053 {
file "qavs/SHOTI1.QAV"
interpolate {
type "index"
}
}
defineqav 10054 {
file "qavs/SHOTF1.QAV"
interpolate {
type "index"
}
}
defineqav 10055 {
file "qavs/SHOTF2.QAV"
interpolate {
type "index"
}
}
defineqav 10056 {
file "qavs/SHOTF3.QAV"
interpolate {
type "index"
}
}
defineqav 10057 {
file "qavs/SHOTL1.QAV"
interpolate {
type "picnum"
}
}
defineqav 10058 {
file "qavs/SHOTDOWN.QAV"
interpolate {
type "index"
}
}
defineqav 10059 {
file "qavs/2SHOTUP.QAV"
interpolate {
type "index"
}
}
defineqav 10060 {
file "qavs/2SHOTI.QAV"
interpolate {
type "index"
}
}
defineqav 10061 {
file "qavs/2SHOTF2.QAV"
interpolate {
type "index"
}
}
defineqav 10062 {
file "qavs/2SHOTFIR.QAV"
interpolate {
type "index"
}
}
defineqav 10063 {
file "qavs/2SHOTDWN.QAV"
interpolate {
type "index"
}
}
defineqav 10064 {
file "qavs/TOMUP.QAV"
interpolate {
type "index"
}
}
defineqav 10065 {
file "qavs/TOMIDLE.QAV"
interpolate {
type "index"
}
}
defineqav 10066 {
file "qavs/TOMFIRE.QAV"
interpolate {
type "index"
loopable
ignore {
frames 0-7 tiles 0
}
}
}
defineqav 10067 {
file "qavs/TOMSPRED.QAV"
interpolate {
type "index"
loopable
}
}
defineqav 10068 {
file "qavs/TOMDOWN.QAV"
interpolate {
type "index"
}
}
defineqav 10069 {
file "qavs/2TOMUP.QAV"
interpolate {
type "index"
}
}
defineqav 10070 {
file "qavs/2TOMIDLE.QAV"
interpolate {
type "index"
}
}
defineqav 10071 {
file "qavs/2TOMFIRE.QAV"
interpolate {
type "index"
loopable
ignore {
frames 0-7 tiles 0
}
ignore {
frames 0-7 tiles 2
}
}
}
defineqav 10072 {
file "qavs/2TOMDOWN.QAV"
interpolate {
type "index"
}
}
defineqav 10073 {
file "qavs/2TOMALT.QAV"
interpolate {
type "index"
loopable
}
}
defineqav 10074 {
file "qavs/SGUNUP.QAV"
interpolate {
type "index"
}
}
defineqav 10075 {
file "qavs/SGUNIDL1.QAV"
interpolate {
type "index"
}
}
defineqav 10076 {
file "qavs/SGUNIDL2.QAV"
interpolate {
type "index"
}
}
defineqav 10077 {
file "qavs/SGUNFIR1.QAV"
interpolate {
type "index"
loopable
}
}
defineqav 10078 {
file "qavs/SGUNFIR4.QAV"
interpolate {
type "index"
}
}
defineqav 10079 {
file "qavs/SGUNPRE.QAV"
interpolate {
type "index"
}
}
defineqav 10080 {
file "qavs/SGUNPOST.QAV"
interpolate {
type "index"
}
}
defineqav 10081 {
file "qavs/SGUNDOWN.QAV"
interpolate {
type "index"
}
}
defineqav 10082 {
file "qavs/2SGUNUP.QAV"
interpolate {
type "index"
}
}
defineqav 10083 {
file "qavs/2SGUNIDL.QAV"
interpolate {
type "index"
}
}
defineqav 10084 {
file "qavs/2SGUNFIR.QAV"
interpolate {
type "index"
loopable
}
}
defineqav 10085 {
file "qavs/2SGUNALT.QAV"
interpolate {
type "index"
}
}
defineqav 10086 {
file "qavs/2SGUNPRE.QAV"
interpolate {
type "index"
}
}
defineqav 10087 {
file "qavs/2SGUNPST.QAV"
interpolate {
type "index"
}
}
defineqav 10088 {
file "qavs/2SGUNDWN.QAV"
interpolate {
type "index"
}
}
defineqav 10089 {
file "qavs/NAPUP.QAV"
interpolate {
type "index"
}
}
defineqav 10090 {
file "qavs/NAPIDLE.QAV"
interpolate {
type "index"
}
}
defineqav 10091 {
file "qavs/NAPFIRE.QAV"
interpolate {
type "index"
loopable
}
}
defineqav 10092 {
file "qavs/NAPDOWN.QAV"
interpolate {
type "index"
}
}
defineqav 10093 {
file "qavs/BSTUP.QAV"
interpolate {
type "index"
}
}
defineqav 10094 {
file "qavs/BSTIDLE.QAV"
interpolate {
type "index"
}
}
defineqav 10095 {
file "qavs/BSTATAK1.QAV"
interpolate {
type "index"
}
}
defineqav 10096 {
file "qavs/BSTATAK2.QAV"
interpolate {
type "index"
}
}
defineqav 10097 {
file "qavs/BSTATAK3.QAV"
interpolate {
type "index"
}
}
defineqav 10098 {
file "qavs/BSTATAK4.QAV"
interpolate {
type "index"
}
}
defineqav 10099 {
file "qavs/BSTDOWN.QAV"
interpolate {
type "index"
}
}
defineqav 10100 {
file "qavs/VDUP.QAV"
interpolate {
type "index"
}
}
defineqav 10101 {
file "qavs/VDIDLE1.QAV"
interpolate {
type "index"
}
}
defineqav 10102 {
file "qavs/VDIDLE2.QAV"
interpolate {
type "index"
loopable
}
}
defineqav 10103 {
file "qavs/VDFIRE1.QAV"
interpolate {
type "index"
}
}
defineqav 10104 {
file "qavs/VDFIRE2.QAV"
interpolate {
type "index"
}
}
defineqav 10105 {
file "qavs/VDFIRE3.QAV"
interpolate {
type "index"
}
}
defineqav 10106 {
file "qavs/VDFIRE4.QAV"
interpolate {
type "index"
}
}
defineqav 10107 {
file "qavs/VDFIRE5.QAV"
interpolate {
type "index"
}
}
defineqav 10108 {
file "qavs/VDFIRE6.QAV"
interpolate {
type "index"
}
}
defineqav 10109 {
file "qavs/VDDOWN.QAV"
interpolate {
type "index"
}
}
defineqav 10110 {
file "qavs/VDSPEL1.QAV"
interpolate {
type "index"
}
}
defineqav 10111 {
file "qavs/STAFUP.QAV"
interpolate {
type "index"
}
}
defineqav 10112 {
file "qavs/STAFIDL1.QAV"
interpolate {
type "index"
}
}
defineqav 10113 {
file "qavs/STAFIDL3.QAV"
interpolate {
type "index"
}
}
defineqav 10114 {
file "qavs/STAFIRE1.QAV"
interpolate {
type "index"
}
}
defineqav 10115 {
file "qavs/STAFIRE2.QAV"
interpolate {
type "index"
}
}
defineqav 10116 {
file "qavs/STAFIRE4.QAV"
interpolate {
type "index"
}
}
defineqav 10117 {
file "qavs/STAFPRE.QAV"
interpolate {
type "index"
}
}
defineqav 10118 {
file "qavs/STAFPOST.QAV"
interpolate {
type "index"
}
}
defineqav 10119 {
file "qavs/STAFDOWN.QAV"
interpolate {
type "index"
}
}
defineqav 10120 {
file "qavs/2NAPUP.QAV"
interpolate {
type "index"
}
}
defineqav 10121 {
file "qavs/2NAPIDLE.QAV"
interpolate {
type "index"
}
}
defineqav 10122 {
file "qavs/2NAPFIRE.QAV"
interpolate {
type "index"
}
}
defineqav 10123 {
file "qavs/2NAPFIR2.QAV"
interpolate {
type "index"
}
}
defineqav 10124 {
file "qavs/2NAPDOWN.QAV"
interpolate {
type "index"
}
}
defineqav 10256 {
file "qavs/BDRIP.QAV"
interpolate {
type "x"
ignore {
frames 0-23 tiles 0
}
}
}
defineqav 10257 {
file "qavs/CREDITS.QAV"
interpolate {
type "index"
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show more