Merge remote-tracking branch 'public/master'

This commit is contained in:
Mitchell Richters 2021-08-29 21:26:08 +10:00
commit 65d4919e5e
48 changed files with 2216 additions and 2126 deletions

View file

@ -24,13 +24,13 @@ jobs:
}
- {
name: "macOS",
os: macos-10.15,
os: macos-11,
deps_cmdline: "brew install libvpx",
build_type: "Release"
}
- {
name: "macOS",
os: macos-10.15,
os: macos-11,
extra_options: "-DDYN_FLUIDSYNTH=OFF -DDYN_OPENAL=OFF -DDYN_SNDFILE=OFF -DDYN_MPG123=OFF",
deps_cmdline: "brew install libvpx fluidsynth mpg123 libsndfile",
build_type: "Debug"
@ -54,14 +54,14 @@ jobs:
os: ubuntu-20.04,
extra_options: "-DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 \
-DDYN_FLUIDSYNTH=OFF -DDYN_OPENAL=OFF -DDYN_SNDFILE=OFF -DDYN_MPG123=OFF",
deps_cmdline: "sudo apt update && sudo apt remove gcc-11 libgcc-11-dev g++-11 libstdc++-11-dev && sudo apt install clang-6.0 libstdc++-9-dev libsdl2-dev libvpx-dev libopenal-dev libfluidsynth-dev libmpg123-dev libsndfile1-dev",
deps_cmdline: "sudo apt update && sudo apt install clang-6.0 libsdl2-dev libvpx-dev libopenal-dev libfluidsynth-dev libmpg123-dev libsndfile1-dev",
build_type: "Debug"
}
- {
name: "Linux Clang 11",
name: "Linux Clang 12",
os: ubuntu-20.04,
extra_options: "-DCMAKE_C_COMPILER=clang-11 -DCMAKE_CXX_COMPILER=clang++-11",
deps_cmdline: "sudo apt update && sudo apt install clang-11 libsdl2-dev libvpx-dev",
extra_options: "-DCMAKE_C_COMPILER=clang-12 -DCMAKE_CXX_COMPILER=clang++-12",
deps_cmdline: "sudo apt update && sudo apt install clang-12 libsdl2-dev libvpx-dev",
build_type: "Release"
}

View file

@ -837,6 +837,18 @@ public:
CopyNodes(o.Nodes, o.Size);
}
TMap(TMap &&o)
{
Nodes = o.Nodes;
LastFree = o.LastFree; /* any free position is before this position */
Size = o.Size; /* must be a power of 2 */
NumUsed = o.NumUsed;
o.Size = 0;
o.NumUsed = 0;
o.SetNodeVector(1);
}
TMap &operator= (const TMap &o)
{
NumUsed = 0;
@ -846,6 +858,12 @@ public:
return *this;
}
TMap &operator= (TMap &&o)
{
TransferFrom(o);
return *this;
}
//=======================================================================
//
// TransferFrom

View file

@ -2026,7 +2026,7 @@ static bool parseDefineQAVInterpolateIgnoreBlock(FScanner& sc, const int& res_id
if (sc.StartBraces(&blockend))
{
pos.Message(MSG_ERROR, "defineqav (%d): interpolate: malformed syntax, unable to continue", res_id);
pos.Message(MSG_ERROR, "defineqav (%d): interpolate: ignore: malformed syntax, unable to continue", res_id);
return false;
}
while (!sc.FoundEndBrace(blockend))
@ -2039,7 +2039,7 @@ static bool parseDefineQAVInterpolateIgnoreBlock(FScanner& sc, const int& res_id
// 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);
pos.Message(MSG_ERROR, "defineqav (%d): interpolate: ignore: unable to get any values for 'frames' or 'tiles', unable to continue", res_id);
return false;
}
@ -2102,7 +2102,7 @@ static bool parseDefineQAVInterpolateBlock(FScanner& sc, const int& res_id, cons
if (sc.StartBraces(&blockend))
{
pos.Message(MSG_ERROR, "defineqav (%d): interpolate (%s): malformed syntax, unable to continue", res_id, interptype.GetChars());
pos.Message(MSG_ERROR, "defineqav (%d): interpolate: malformed syntax, unable to continue", res_id);
return false;
}
while (!sc.FoundEndBrace(blockend))
@ -2112,13 +2112,13 @@ static bool parseDefineQAVInterpolateBlock(FScanner& sc, const int& res_id, cons
{
if (interptype.IsNotEmpty())
{
pos.Message(MSG_ERROR, "defineqav (%d): interpolate (%s): more than one interpolation type defined, unable to continue", res_id, interptype.GetChars());
pos.Message(MSG_ERROR, "defineqav (%d): interpolate: more than one interpolation type defined, unable to continue", res_id);
return false;
}
sc.GetString(interptype);
if (!gi->IsQAVInterpTypeValid(interptype))
{
pos.Message(MSG_ERROR, "defineqav (%d): interpolate (%s): interpolation type not found", res_id, interptype.GetChars());
pos.Message(MSG_ERROR, "defineqav (%d): interpolate: interpolation type not found", res_id);
return false;
}
}

View file

@ -87,8 +87,10 @@ CVARD(Bool, cl_bloodvanillabobbing, true, CVAR_ARCHIVE, "enable/disable Blood's
CVARD(Bool, cl_bloodvanillaexplosions, false, CVAR_ARCHIVE, "enable/disable Blood's vanilla explosion behavior")
CVARD(Bool, cl_bloodvanillaenemies, false, CVAR_ARCHIVE, "enable/disable Blood's vanilla enemy behavior")
CVARD(Bool, cl_bloodqavinterp, true, CVAR_ARCHIVE, "enable/disable Blood's QAV interpolation")
CVARD(Bool, cl_bloodqavforcedinterp, false, CVAR_ARCHIVE, "enable/disable Blood's QAV interpolation forcefully for QAVs that aren't defined as interpolatable")
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")
CVARD(Bool, cl_loadingscreens, true, CVAR_ARCHIVE, "enable/disable loading screens for games")
CUSTOM_CVARD(Int, cl_autoaim, 1, CVAR_ARCHIVE|CVAR_USERINFO, "enable/disable weapon autoaim")

View file

@ -32,8 +32,10 @@ EXTERN_CVAR(Bool, cl_bloodvanillabobbing)
EXTERN_CVAR(Bool, cl_bloodvanillaexplosions)
EXTERN_CVAR(Bool, cl_bloodvanillaenemies)
EXTERN_CVAR(Bool, cl_bloodqavinterp)
EXTERN_CVAR(Bool, cl_bloodqavforcedinterp)
EXTERN_CVAR(Bool, cl_bloodweapinterp)
EXTERN_CVAR(Bool, cl_bloodoldweapbalance)
EXTERN_CVAR(Bool, cl_loadingscreens)
EXTERN_CVAR(Bool, demorec_seeds_cvar)
EXTERN_CVAR(Bool, demoplay_diffs)

View file

@ -222,10 +222,10 @@ void ShowIntermission(MapRecord* fromMap, MapRecord* toMap, SummaryInfo* info, C
if (tocluster == nullptr || !CreateCutscene(&tocluster->intro, runner, toMap, !!fromMap))
CreateCutscene(&globalCutscenes.DefaultMapIntro, runner, toMap, !!fromMap);
}
// Skip the load screen if the level is started from the console.
// Skip the load screen if the level is started from the console or loading screens are disabled.
// In this case the load screen is not helpful as it blocks the actual level start,
// requiring closing and reopening the console first before entering any commands that need the level.
if (ConsoleState == c_up || ConsoleState == c_rising)
if ((ConsoleState == c_up || ConsoleState == c_rising) && cl_loadingscreens)
CreateCutscene(&globalCutscenes.LoadingScreen, runner, toMap, true);
}
else if (isShareware())

View file

@ -840,9 +840,6 @@ TArray<GrpEntry> GrpScan()
sortedFileList.Delete(0, findex + 1);
sortedGroupList.Delete(0, gindex + 1);
if (sortedGroupList.Size() == 0 || sortedFileList.Size() == 0)
return foundGames;
for (auto entry : sortedFileList)
{
GetCRC(entry, cachedCRCs);

File diff suppressed because it is too large Load diff

View file

@ -228,15 +228,10 @@ void actKillDude(int a1, spritetype *pSprite, DAMAGE_TYPE a3, int a4);
int actDamageSprite(int nSource, spritetype *pSprite, DAMAGE_TYPE a3, int a4);
int actDamageSprite(DBloodActor* pSource, DBloodActor* pTarget, DAMAGE_TYPE damageType, int damage);
void actHitcodeToData(int a1, HITINFO *pHitInfo, DBloodActor **actor, walltype **a7 = nullptr);
void actAirDrag(spritetype *pSprite, int a2);
int MoveThing(spritetype *pSprite);
void MoveDude(spritetype *pSprite);
int MoveMissile(spritetype *pSprite);
void actExplodeSprite(spritetype *pSprite);
void actAirDrag(DBloodActor *pSprite, int a2);
void actExplodeSprite(DBloodActor *pSprite);
void actActivateGibObject(DBloodActor *actor);
bool IsUnderWater(spritetype *pSprite);
void actProcessSprites(void);
spritetype * actSpawnSprite_(int nSector, int x, int y, int z, int nStat, char a6);
DBloodActor* actSpawnSprite(int nSector, int x, int y, int z, int nStat, bool a6);
spritetype *actSpawnDude(spritetype *pSource, short nType, int a3, int a4);
spritetype * actSpawnSprite(spritetype *pSource, int nStat);

View file

@ -33,7 +33,6 @@ BEGIN_BLD_NS
void RecoilDude(DBloodActor* actor);
int cumulDamage[kMaxXSprites];
DUDEEXTRA gDudeExtra[kMaxXSprites];
AISTATE genIdle = {kAiStateGenIdle, 0, -1, 0, NULL, NULL, NULL, NULL };
AISTATE genRecoil = {kAiStateRecoil, 5, -1, 20, NULL, NULL, NULL, &genIdle };
@ -53,7 +52,8 @@ bool dudeIsPlayingSeq(spritetype *pSprite, int nSeq)
void aiPlay3DSound(spritetype *pSprite, int a2, AI_SFX_PRIORITY a3, int a4)
{
DUDEEXTRA *pDudeExtra = &gDudeExtra[pSprite->extra];
auto actor = &bloodActors[pSprite->index];
DUDEEXTRA *pDudeExtra = &actor->dudeExtra;
if (a3 == AI_SFX_PRIORITY_0)
sfxPlay3DSound(pSprite, a2, a4, 2);
else if (a3 > pDudeExtra->prio || pDudeExtra->time <= PlayClock)
@ -321,7 +321,7 @@ void aiActivateDude(DBloodActor* actor)
switch (pSprite->type) {
case kDudePhantasm:
{
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
pDudeExtraE->xval2 = 0;
pDudeExtraE->xval3 = 1;
pDudeExtraE->xval1 = 0;
@ -340,7 +340,7 @@ void aiActivateDude(DBloodActor* actor)
case kDudeCultistTNT:
case kDudeCultistBeast:
{
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
pDudeExtraE->xval3 = 1;
pDudeExtraE->xval1 = 0;
if (pXSprite->target == -1) {
@ -378,7 +378,7 @@ void aiActivateDude(DBloodActor* actor)
#ifdef NOONE_EXTENSIONS
case kDudeModernCustom:
{
DUDEEXTRA_at6_u1* pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
DUDEEXTRA_at6_u1* pDudeExtraE = &actor->dudeExtra.at6.u1;
pDudeExtraE->xval3 = 1;
pDudeExtraE->xval1 = 0;
if (pXSprite->target == -1) {
@ -397,7 +397,7 @@ void aiActivateDude(DBloodActor* actor)
break;
#endif
case kDudeCultistTommyProne: {
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
pDudeExtraE->xval3 = 1; pDudeExtraE->xval1 = 0;
pSprite->type = kDudeCultistTommy;
if (pXSprite->target == -1) {
@ -430,7 +430,7 @@ void aiActivateDude(DBloodActor* actor)
}
case kDudeCultistShotgunProne:
{
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
pDudeExtraE->xval3 = 1;
pDudeExtraE->xval1 = 0;
pSprite->type = kDudeCultistShotgun;
@ -474,7 +474,7 @@ void aiActivateDude(DBloodActor* actor)
break;
case kDudeBat:
{
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
pDudeExtraE->xval2 = 0;
pDudeExtraE->xval3 = 1;
pDudeExtraE->xval1 = 0;
@ -492,7 +492,7 @@ void aiActivateDude(DBloodActor* actor)
}
case kDudeBoneEel:
{
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
pDudeExtraE->xval2 = 0;
pDudeExtraE->xval3 = 1;
pDudeExtraE->xval1 = 0;
@ -509,7 +509,7 @@ void aiActivateDude(DBloodActor* actor)
break;
}
case kDudeGillBeast: {
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
XSECTOR *pXSector = NULL;
if (sector[pSprite->sectnum].extra > 0)
pXSector = &xsector[sector[pSprite->sectnum].extra];
@ -537,7 +537,7 @@ void aiActivateDude(DBloodActor* actor)
break;
}
case kDudeZombieAxeNormal: {
DUDEEXTRA_at6_u2 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u2;
DUDEEXTRA_at6_u2 *pDudeExtraE = &actor->dudeExtra.at6.u2;
pDudeExtraE->xval2 = 1;
pDudeExtraE->xval1 = 0;
if (pXSprite->target == -1)
@ -567,7 +567,7 @@ void aiActivateDude(DBloodActor* actor)
}
case kDudeZombieAxeBuried:
{
DUDEEXTRA_at6_u2 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u2;
DUDEEXTRA_at6_u2 *pDudeExtraE = &actor->dudeExtra.at6.u2;
pDudeExtraE->xval2 = 1;
pDudeExtraE->xval1 = 0;
if (pXSprite->aiState == &zombieEIdle)
@ -576,7 +576,7 @@ void aiActivateDude(DBloodActor* actor)
}
case kDudeZombieAxeLaying:
{
DUDEEXTRA_at6_u2 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u2;
DUDEEXTRA_at6_u2 *pDudeExtraE = &actor->dudeExtra.at6.u2;
pDudeExtraE->xval2 = 1;
pDudeExtraE->xval1 = 0;
if (pXSprite->aiState == &zombieSIdle)
@ -584,7 +584,7 @@ void aiActivateDude(DBloodActor* actor)
break;
}
case kDudeZombieButcher: {
DUDEEXTRA_at6_u2 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u2;
DUDEEXTRA_at6_u2 *pDudeExtraE = &actor->dudeExtra.at6.u2;
pDudeExtraE->xval2 = 1;
pDudeExtraE->xval1 = 0;
if (pXSprite->target == -1)
@ -612,7 +612,7 @@ void aiActivateDude(DBloodActor* actor)
aiNewState(actor, &zombieFBurnChase);
break;
case kDudeGargoyleFlesh: {
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
pDudeExtraE->xval2 = 0;
pDudeExtraE->xval3 = 1;
pDudeExtraE->xval1 = 0;
@ -630,7 +630,7 @@ void aiActivateDude(DBloodActor* actor)
}
case kDudeGargoyleStone:
{
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
pDudeExtraE->xval2 = 0;
pDudeExtraE->xval3 = 1;
pDudeExtraE->xval1 = 0;
@ -747,7 +747,7 @@ void aiActivateDude(DBloodActor* actor)
}
break;
case kDudeSpiderMother: {
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
pDudeExtraE->xval3 = 1;
pDudeExtraE->xval1 = 0;
pSprite->flags |= 2;
@ -763,7 +763,7 @@ void aiActivateDude(DBloodActor* actor)
}
case kDudeTinyCaleb:
{
DUDEEXTRA_at6_u2 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u2;
DUDEEXTRA_at6_u2 *pDudeExtraE = &actor->dudeExtra.at6.u2;
pDudeExtraE->xval2 = 1;
pDudeExtraE->xval1 = 0;
if (pXSprite->target == -1)
@ -796,7 +796,7 @@ void aiActivateDude(DBloodActor* actor)
}
case kDudeBeast:
{
DUDEEXTRA_at6_u2 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u2;
DUDEEXTRA_at6_u2 *pDudeExtraE = &actor->dudeExtra.at6.u2;
pDudeExtraE->xval2 = 1;
pDudeExtraE->xval1 = 0;
if (pXSprite->target == -1)
@ -944,9 +944,9 @@ int aiDamageSprite(DBloodActor* source, DBloodActor* actor, DAMAGE_TYPE nDmgType
if (pSprite->type == kDudeModernCustomBurning) {
if (Chance(0x2000) && gDudeExtra[pSprite->extra].time < PlayClock) {
if (Chance(0x2000) && actor->dudeExtra.time < PlayClock) {
playGenDudeSound(pSprite, kGenDudeSndBurning);
gDudeExtra[pSprite->extra].time = PlayClock + 360;
actor->dudeExtra.time = PlayClock + 360;
}
if (pXSprite->burnTime == 0) pXSprite->burnTime = 2400;
@ -992,7 +992,7 @@ int aiDamageSprite(DBloodActor* source, DBloodActor* actor, DAMAGE_TYPE nDmgType
aiGenDudeNewState(pSprite, &genDudeBurnGoto);
actHealDude(pXSprite, dudeInfo[55].startHealth, dudeInfo[55].startHealth);
gDudeExtra[pSprite->extra].time = PlayClock + 360;
actor->dudeExtra.time = PlayClock + 360;
evKill(nSprite, 3, kCallbackFXFlameLick);
}
@ -1030,7 +1030,7 @@ int aiDamageSprite(DBloodActor* source, DBloodActor* actor, DAMAGE_TYPE nDmgType
if (nDmgType == kDamageTesla)
{
DUDEEXTRA *pDudeExtra = &gDudeExtra[pSprite->extra];
DUDEEXTRA *pDudeExtra = &actor->dudeExtra;
pDudeExtra->recoil = 1;
}
const bool fixRandomCultist = !cl_bloodvanillaenemies && (pSprite->inittype >= kDudeBase) && (pSprite->inittype < kDudeMax) && !VanillaMode(); // fix burning cultists randomly switching types underwater
@ -1055,7 +1055,7 @@ int aiDamageSprite(DBloodActor* source, DBloodActor* actor, DAMAGE_TYPE nDmgType
aiNewState(actor, &cultistBurnGoto);
aiPlay3DSound(pSprite, 361, AI_SFX_PRIORITY_0, -1);
aiPlay3DSound(pSprite, 1031+Random(2), AI_SFX_PRIORITY_2, -1);
gDudeExtra[pSprite->extra].time = PlayClock+360;
actor->dudeExtra.time = PlayClock+360;
actHealDude(pXSprite, dudeInfo[40].startHealth, dudeInfo[40].startHealth);
evKill(nSprite, 3, kCallbackFXFlameLick);
}
@ -1066,16 +1066,16 @@ int aiDamageSprite(DBloodActor* source, DBloodActor* actor, DAMAGE_TYPE nDmgType
pSprite->type = kDudeBurningInnocent;
aiNewState(actor, &cultistBurnGoto);
aiPlay3DSound(pSprite, 361, AI_SFX_PRIORITY_0, -1);
gDudeExtra[pSprite->extra].time = PlayClock+360;
actor->dudeExtra.time = PlayClock+360;
actHealDude(pXSprite, dudeInfo[39].startHealth, dudeInfo[39].startHealth);
evKill(nSprite, 3, kCallbackFXFlameLick);
}
break;
case kDudeBurningCultist:
if (Chance(0x4000) && gDudeExtra[pSprite->extra].time < PlayClock)
if (Chance(0x4000) && actor->dudeExtra.time < PlayClock)
{
aiPlay3DSound(pSprite, 1031+Random(2), AI_SFX_PRIORITY_2, -1);
gDudeExtra[pSprite->extra].time = PlayClock+360;
actor->dudeExtra.time = PlayClock+360;
}
if (Chance(0x600) && (pXSprite->medium == kMediumWater || pXSprite->medium == kMediumGoo))
{
@ -1121,7 +1121,7 @@ int aiDamageSprite(DBloodActor* source, DBloodActor* actor, DAMAGE_TYPE nDmgType
aiNewState(actor, &cultistBurnGoto);
}
aiPlay3DSound(pSprite, 361, AI_SFX_PRIORITY_0, -1);
gDudeExtra[pSprite->extra].time = PlayClock+360;
actor->dudeExtra.time = PlayClock+360;
actHealDude(pXSprite, dudeInfo[39].startHealth, dudeInfo[39].startHealth);
evKill(nSprite, 3, kCallbackFXFlameLick);
}
@ -1157,7 +1157,7 @@ void RecoilDude(DBloodActor* actor)
auto pXSprite = &actor->x();
auto pSprite = &actor->s();
char v4 = Chance(0x8000);
DUDEEXTRA *pDudeExtra = &gDudeExtra[pSprite->extra];
DUDEEXTRA *pDudeExtra = &actor->dudeExtra;
if (pSprite->statnum == kStatDude && (pSprite->type >= kDudeBase && pSprite->type < kDudeMax)) {
DUDEINFO *pDudeInfo = getDudeInfo(pSprite->type);
switch (pSprite->type) {
@ -1573,15 +1573,15 @@ void aiInit(void)
void aiInitSprite(spritetype *pSprite)
{
auto actor = &bloodActors[pSprite->index];
int nXSprite = pSprite->extra;
XSPRITE *pXSprite = &xsprite[nXSprite];
auto actor = &bloodActors[pXSprite->reference];
int nSector = pSprite->sectnum;
int nXSector = sector[nSector].extra;
XSECTOR *pXSector = NULL;
if (nXSector > 0)
pXSector = &xsector[nXSector];
DUDEEXTRA *pDudeExtra = &gDudeExtra[pSprite->extra];
DUDEEXTRA *pDudeExtra = &actor->dudeExtra;
pDudeExtra->recoil = 0;
pDudeExtra->time = 0;
@ -1609,7 +1609,7 @@ void aiInitSprite(spritetype *pSprite)
case kDudeCultistTNT:
case kDudeCultistBeast:
{
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[nXSprite].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
pDudeExtraE->xval3 = 0;
pDudeExtraE->xval1 = 0;
aiNewState(actor, &cultistIdle);
@ -1617,7 +1617,7 @@ void aiInitSprite(spritetype *pSprite)
}
case kDudeCultistTommyProne:
{
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[nXSprite].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
pDudeExtraE->xval3 = 0;
pDudeExtraE->xval1 = 0;
aiNewState(actor, &fanaticProneIdle);
@ -1625,21 +1625,21 @@ void aiInitSprite(spritetype *pSprite)
}
case kDudeCultistShotgunProne:
{
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[nXSprite].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
pDudeExtraE->xval3 = 0;
pDudeExtraE->xval1 = 0;
aiNewState(actor, &cultistProneIdle);
break;
}
case kDudeZombieButcher: {
DUDEEXTRA_at6_u2 *pDudeExtraE = &gDudeExtra[nXSprite].at6.u2;
DUDEEXTRA_at6_u2 *pDudeExtraE = &actor->dudeExtra.at6.u2;
pDudeExtraE->xval2 = 0;
pDudeExtraE->xval1 = 0;
aiNewState(actor, &zombieFIdle);
break;
}
case kDudeZombieAxeNormal: {
DUDEEXTRA_at6_u2 *pDudeExtraE = &gDudeExtra[nXSprite].at6.u2;
DUDEEXTRA_at6_u2 *pDudeExtraE = &actor->dudeExtra.at6.u2;
pDudeExtraE->xval2 = 0;
pDudeExtraE->xval1 = 0;
aiNewState(actor, &zombieAIdle);
@ -1647,7 +1647,7 @@ void aiInitSprite(spritetype *pSprite)
}
case kDudeZombieAxeLaying:
{
DUDEEXTRA_at6_u2 *pDudeExtraE = &gDudeExtra[nXSprite].at6.u2;
DUDEEXTRA_at6_u2 *pDudeExtraE = &actor->dudeExtra.at6.u2;
pDudeExtraE->xval2 = 0;
pDudeExtraE->xval1 = 0;
aiNewState(actor, &zombieSIdle);
@ -1655,7 +1655,7 @@ void aiInitSprite(spritetype *pSprite)
break;
}
case kDudeZombieAxeBuried: {
DUDEEXTRA_at6_u2 *pDudeExtraE = &gDudeExtra[nXSprite].at6.u2;
DUDEEXTRA_at6_u2 *pDudeExtraE = &actor->dudeExtra.at6.u2;
pDudeExtraE->xval2 = 0;
pDudeExtraE->xval1 = 0;
aiNewState(actor, &zombieEIdle);
@ -1663,7 +1663,7 @@ void aiInitSprite(spritetype *pSprite)
}
case kDudeGargoyleFlesh:
case kDudeGargoyleStone: {
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[nXSprite].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
pDudeExtraE->xval2 = 0;
pDudeExtraE->xval3 = 0;
pDudeExtraE->xval1 = 0;
@ -1675,7 +1675,7 @@ void aiInitSprite(spritetype *pSprite)
aiNewState(actor, &gargoyleStatueIdle);
break;
case kDudeCerberusTwoHead: {
DUDEEXTRA_at6_u2 *pDudeExtraE = &gDudeExtra[nXSprite].at6.u2;
DUDEEXTRA_at6_u2 *pDudeExtraE = &actor->dudeExtra.at6.u2;
pDudeExtraE->xval2 = 0;
pDudeExtraE->xval1 = 0;
aiNewState(actor, &cerberusIdle);
@ -1689,7 +1689,7 @@ void aiInitSprite(spritetype *pSprite)
break;
case kDudePhantasm:
{
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[nXSprite].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
pDudeExtraE->xval2 = 0;
pDudeExtraE->xval3 = 0;
pDudeExtraE->xval1 = 0;
@ -1704,7 +1704,7 @@ void aiInitSprite(spritetype *pSprite)
break;
case kDudeBoneEel:
{
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[nXSprite].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
pDudeExtraE->xval2 = 0;
pDudeExtraE->xval3 = 0;
pDudeExtraE->xval1 = 0;
@ -1716,7 +1716,7 @@ void aiInitSprite(spritetype *pSprite)
break;
case kDudeBat:
{
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[nXSprite].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
pDudeExtraE->xval2 = 0;
pDudeExtraE->xval3 = 0;
pDudeExtraE->xval1 = 0;
@ -1727,7 +1727,7 @@ void aiInitSprite(spritetype *pSprite)
case kDudeSpiderRed:
case kDudeSpiderBlack:
{
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[nXSprite].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
pDudeExtraE->xval3 = 0;
pDudeExtraE->xval2 = 0;
pDudeExtraE->xval1 = 0;
@ -1736,7 +1736,7 @@ void aiInitSprite(spritetype *pSprite)
}
case kDudeSpiderMother:
{
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[nXSprite].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
pDudeExtraE->xval3 = 0;
pDudeExtraE->xval2 = 0;
pDudeExtraE->xval1 = 0;
@ -1745,7 +1745,7 @@ void aiInitSprite(spritetype *pSprite)
}
case kDudeTchernobog:
{
DUDEEXTRA_at6_u2 *pDudeExtraE = &gDudeExtra[nXSprite].at6.u2;
DUDEEXTRA_at6_u2 *pDudeExtraE = &actor->dudeExtra.at6.u2;
pDudeExtraE->xval2 = 0;
pDudeExtraE->xval1 = 0;
aiNewState(actor, &tchernobogIdle);
@ -1861,45 +1861,4 @@ void aiInitSprite(spritetype *pSprite)
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
FSerializer& Serialize(FSerializer& arc, const char* keyname, DUDEEXTRA& w, DUDEEXTRA* def)
{
int empty = 0;
char empty2 = 0;
if (arc.isReading()) w = {};
if (arc.BeginObject(keyname))
{
arc("time", w.time, &empty)
("recoil", w.recoil, &empty)
("prio", w.prio, &empty)
("x1", w.at6.u1.xval1, &empty)
("x2", w.at6.u1.xval2, &empty)
("x3", w.at6.u1.xval3, &empty2)
.EndObject();
}
return arc;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void SerializeAI(FSerializer& arc)
{
if (arc.BeginObject("ai"))
{
arc.SparseArray("dudeextra", gDudeExtra, kMaxSprites, activeXSprites)
.EndObject();
}
}
END_BLD_NS

View file

@ -87,7 +87,6 @@ struct TARGETTRACK {
};
extern const int dword_138BB0[5];
extern DUDEEXTRA gDudeExtra[];
bool dudeIsPlayingSeq(spritetype *pSprite, int nSeq);
void aiPlay3DSound(spritetype *pSprite, int a2, AI_SFX_PRIORITY a3, int a4);

View file

@ -84,7 +84,7 @@ static void batThinkTarget(DBloodActor* actor)
auto pSprite = &actor->s();
assert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = getDudeInfo(pSprite->type);
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
if (pDudeExtraE->xval3 && pDudeExtraE->xval2 < 10)
pDudeExtraE->xval2++;
else if (pDudeExtraE->xval2 >= 10 && pDudeExtraE->xval3)
@ -433,7 +433,7 @@ void batMoveToCeil(DBloodActor* actor)
int nSector = pSprite->sectnum;
if (z - pXSprite->targetZ < 0x1000)
{
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
pDudeExtraE->xval3 = 0;
pSprite->flags = 0;
aiNewState(actor, &batIdle);

View file

@ -95,7 +95,7 @@ static void eelThinkTarget(DBloodActor* actor)
auto pSprite = &actor->s();
assert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
DUDEINFO *pDudeInfo = getDudeInfo(pSprite->type);
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
if (pDudeExtraE->xval3 && pDudeExtraE->xval2 < 10)
pDudeExtraE->xval2++;
else if (pDudeExtraE->xval2 >= 10 && pDudeExtraE->xval3)
@ -436,7 +436,7 @@ void eelMoveToCeil(DBloodActor* actor)
int nSector = pSprite->sectnum;
if (z - pXSprite->targetZ < 0x1000)
{
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
pDudeExtraE->xval3 = 0;
pSprite->flags = 0;
aiNewState(actor, &eelIdle);

View file

@ -266,7 +266,7 @@ static void cerberusThinkTarget(DBloodActor* actor)
return;
}
DUDEINFO *pDudeInfo = getDudeInfo(pSprite->type);
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
if (pDudeExtraE->xval3 && pDudeExtraE->xval2 < 10)
pDudeExtraE->xval2++;
else if (pDudeExtraE->xval2 >= 10 && pDudeExtraE->xval3)

View file

@ -215,7 +215,7 @@ static void gargThinkTarget(DBloodActor* actor)
return;
}
DUDEINFO *pDudeInfo = getDudeInfo(pSprite->type);
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
if (pDudeExtraE->xval3 && pDudeExtraE->xval2 < 10)
pDudeExtraE->xval2++;
else if (pDudeExtraE->xval2 >= 10 && pDudeExtraE->xval3)

View file

@ -191,7 +191,7 @@ static void ghostThinkTarget(DBloodActor* actor)
return;
}
DUDEINFO *pDudeInfo = getDudeInfo(pSprite->type);
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
if (pDudeExtraE->xval3 && pDudeExtraE->xval2 < 10)
pDudeExtraE->xval2++;
else if (pDudeExtraE->xval2 >= 10 && pDudeExtraE->xval3)

View file

@ -146,7 +146,7 @@ void SpidBirthSeqCallback(int, DBloodActor* actor)
DUDEINFO *pDudeInfo = getDudeInfo(pSprite->type);
assert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
spritetype *pTarget = &sprite[pXSprite->target];
DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
DUDEEXTRA_at6_u1 *pDudeExtraE = &actor->dudeExtra.at6.u1;
int dx = pXSprite->targetX-pSprite->x;
int dy = pXSprite->targetY-pSprite->y;
int nAngle = getangle(dx, dy);

View file

@ -233,7 +233,7 @@ static void sub_725A4(DBloodActor* actor)
return;
}
DUDEINFO *pDudeInfo = getDudeInfo(pSprite->type);
DUDEEXTRA_at6_u2 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u2;
DUDEEXTRA_at6_u2 *pDudeExtraE = &actor->dudeExtra.at6.u2;
if (pDudeExtraE->xval2 && pDudeExtraE->xval1 < 10)
pDudeExtraE->xval1++;
else if (pDudeExtraE->xval1 >= 10 && pDudeExtraE->xval2)

View file

@ -1593,8 +1593,10 @@ void dudeLeechOperate(spritetype* pSprite, XSPRITE* pXSprite, EVENT event)
}
}
bool doExplosion(spritetype* pSprite, int nType) {
spritetype* pExplosion = actSpawnSprite_(pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, kStatExplosion, true);
bool doExplosion(spritetype* pSprite, int nType)
{
auto actor = actSpawnSprite(pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, kStatExplosion, true);
spritetype* pExplosion = &actor->s();
if (pExplosion->extra < 0 || pExplosion->extra >= kMaxXSprites)
return false;
@ -2215,10 +2217,12 @@ void genDudePostDeath(spritetype* pSprite, DAMAGE_TYPE damageType, int damage) {
actPostSprite(pSprite->index, kStatThing);
}
void aiGenDudeInitSprite(spritetype* pSprite, XSPRITE* pXSprite) {
void aiGenDudeInitSprite(spritetype* pSprite, XSPRITE* pXSprite)
{
auto actor = &bloodActors[pSprite->index];
switch (pSprite->type) {
case kDudeModernCustom: {
DUDEEXTRA_at6_u1* pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1;
DUDEEXTRA_at6_u1* pDudeExtraE = &actor->dudeExtra.at6.u1;
pDudeExtraE->xval3 = pDudeExtraE->xval1 = 0;
aiGenDudeNewState(pSprite, &genDudeIdleL);
break;

View file

@ -4,6 +4,8 @@ BEGIN_BLD_NS
extern int cumulDamage[kMaxXSprites];
// Due to the messed up array storage of all the game data we cannot do any direct references here yet. We have to access everything via wrapper functions for now.
// Note that the indexing is very inconsistent - partially by sprite index, partially by xsprite index.
class DBloodActor
@ -13,6 +15,7 @@ class DBloodActor
public:
int dudeSlope;
DUDEEXTRA dudeExtra;
DBloodActor() :index(int(this - base())) { /*assert(index >= 0 && index < kMaxSprites);*/ }
DBloodActor& operator=(const DBloodActor& other) = default;
@ -20,6 +23,7 @@ public:
void Clear()
{
dudeSlope = 0;
dudeExtra = {};
}
bool hasX() { return sprite[index].extra > 0; }
void addX()
@ -34,7 +38,6 @@ public:
int& zvel() { return Blood::zvel[index]; }
int& cumulDamage() { return Blood::cumulDamage[sprite[index].extra]; }
DUDEEXTRA& dudeExtra() { return gDudeExtra[sprite[index].extra]; }
SPRITEMASS& spriteMass() { return gSpriteMass[sprite[index].extra]; }
GENDUDEEXTRA& genDudeExtra() { return Blood::gGenDudeExtra[index]; }
POINT3D& basePoint() { return Blood::baseSprite[index]; }
@ -125,6 +128,11 @@ public:
}
}
void addExtra()
{
if (s().extra <= 0) s().extra = dbInsertXSprite(index);
}
};
extern DBloodActor bloodActors[kMaxSprites];
@ -258,4 +266,21 @@ struct Collision
};
inline DBloodActor* getUpperLink(int sect)
{
auto l = gUpperLink[sect];
return l == -1 ? nullptr : &bloodActors[l];
}
inline DBloodActor* getLowerLink(int sect)
{
auto l = gLowerLink[sect];
return l == -1 ? nullptr : &bloodActors[l];
}
inline void viewBackupSpriteLoc(DBloodActor* actor)
{
viewBackupSpriteLoc(actor->s().index, &actor->s());
}
END_BLD_NS

View file

@ -561,6 +561,11 @@ inline int QRandom2(int a1)
return MulScale(qrand(), a1, 14)-a1;
}
inline double QRandom2F(double a1)
{
return MulScaleF(qrand(), a1, 14)-a1;
}
template<class T>
inline void SetBitString(T *pArray, int nIndex)
{

View file

@ -165,7 +165,8 @@ spritetype * CFX::fxSpawn(FX_ID nFx, int nSector, int x, int y, int z, unsigned
return NULL;
destroy(nSprite);
}
spritetype *pSprite = actSpawnSprite_(nSector, x, y, z, 1, 0);
auto actor = actSpawnSprite(nSector, x, y, z, 1, 0);
spritetype* pSprite = &actor->s();
pSprite->type = nFx;
pSprite->picnum = pFX->picnum;
pSprite->cstat |= pFX->cstat;
@ -204,7 +205,7 @@ void CFX::fxProcess(void)
assert(nSector >= 0 && nSector < kMaxSectors);
assert(pSprite->type < kFXMax);
FXDATA *pFXData = &gFXData[pSprite->type];
actAirDrag(pSprite, pFXData->drag);
actAirDrag(&bloodActors[pSprite->index], pFXData->drag);
if (xvel[nSprite])
pSprite->x += xvel[nSprite]>>12;
if (yvel[nSprite])

View file

@ -869,8 +869,12 @@ int GetClosestSpriteSectors(int nSector, int x, int y, int nDist, uint8_t *pSect
if (TestBitString(sectbits, nNextSector)) // if we've already checked this sector, skip
continue;
bool setSectBit = true;
bool withinRange = CheckProximityWall(pWall->point2, x, y, nDist);
if (newSectCheckMethod && !withinRange) // if range check failed, try comparing midpoints/subdivides of wall span
bool withinRange = false;
if (!newSectCheckMethod) // original method
{
withinRange = CheckProximityWall(pWall->point2, x, y, nDist);
}
else // new method - first test edges and then wall span midpoints
{
for (int k = (j+1); k < nEndWall; k++) // scan through the rest of the sector's walls
{
@ -884,27 +888,34 @@ int GetClosestSpriteSectors(int nSector, int x, int y, int nDist, uint8_t *pSect
const int nWallB = wall[nWallA].point2;
int x1 = wall[nWallA].x, y1 = wall[nWallA].y;
int x2 = wall[nWallB].x, y2 = wall[nWallB].y;
int point1Dist = approxDist(x-x1, y-y1); // setup edge distance needed for below loop (determines which point to shift closer to center)
int point2Dist = approxDist(x-x2, y-y2);
int nLength = approxDist(x1-x2, y1-y2);
const int nDist2 = (nDist+(nDist>>1))<<4;
nLength = ClipRange(nLength / nDist2, 1, 4); // never split more than 4 times
for (int k = 0; true; k++) // subdivide span into smaller chunks towards direction
const int nDist4 = nDist<<4;
nLength = ClipRange(nLength / (nDist4+(nDist4>>1)), 1, 4); // always test midpoint at least once, and never split more than 4 times
for (int k = 0; true; k++) // check both points of wall and subdivide span into smaller chunks towards target
{
const int xcenter = (x1+x2)>>1, ycenter = (y1+y2)>>1;
withinRange = CheckProximityPoint(xcenter, ycenter, 0, x, y, 0, nDist);
withinRange = (point1Dist < nDist4) || (point2Dist < nDist4); // check if both points of span is within radius
if (withinRange)
break;
if (k == (nLength-1)) // reached end
if (k == nLength) // reached end
break;
const bool bDir = approxDist(x-x1, y-y1) < approxDist(x-x2, y-y2);
if (bDir) // step closer and check again
const int xcenter = (x1+x2)>>1, ycenter = (y1+y2)>>1;
if (point1Dist < point2Dist) // shift closest side of wall towards target point, and refresh point distance values
{
x2 = xcenter, y2 = ycenter;
point2Dist = approxDist(x-x2, y-y2);
}
else
{
x1 = xcenter, y1 = ycenter;
point1Dist = approxDist(x-x1, y-y1);
}
}
}
if (withinRange) // if new sector is within range, set to current sector and test walls
{
setSectBit = true; // sector is within range, set as checked
setSectBit = true; // sector is within range, set the sector as checked
if (pSectBit)
SetBitString(pSectBit, nNextSector);
pSectors[n++] = nNextSector;

View file

@ -120,7 +120,7 @@ static const char* DefFile(void)
for (int i = numlumps - 1; i >= 0; i--)
{
int fileno = fileSystem.GetFileContainer(i);
if (fileno != -1 && fileno <= fileSystem.GetMaxIwadNum()) break;
if (fileno != -1 && fileno <= fileSystem.GetMaxIwadNum()) continue;
FString fn = fileSystem.GetFileFullName(i, false);
FString ext = fn.Right(4);
if (ext.CompareNoCase(".ini") == 0)

View file

@ -423,6 +423,32 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, AISTATE*& w, AISTA
return arc;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
FSerializer& Serialize(FSerializer& arc, const char* keyname, DUDEEXTRA& w, DUDEEXTRA* def)
{
int empty = 0;
char empty2 = 0;
if (arc.isReading()) w = {};
if (arc.BeginObject(keyname))
{
arc("time", w.time, &empty)
("recoil", w.recoil, &empty)
("prio", w.prio, &empty)
("x1", w.at6.u1.xval1, &empty)
("x2", w.at6.u1.xval2, &empty)
("x3", w.at6.u1.xval3, &empty2)
.EndObject();
}
return arc;
}
FSerializer& Serialize(FSerializer& arc, const char* keyname, DBloodActor& w, DBloodActor* def)
{
static DBloodActor nul;
@ -437,7 +463,8 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, DBloodActor& w, DB
// The rest is only relevant if the actor has an xsprite.
if (w.s().extra > 0)
{
arc("dudeslope", w.dudeSlope, def->dudeSlope);
arc("dudeslope", w.dudeSlope, def->dudeSlope)
("dudeextra", w.dudeExtra, def->dudeExtra);
}
arc.EndObject();
}
@ -668,7 +695,6 @@ void SerializeSequences(FSerializer& arc);
void SerializeWarp(FSerializer& arc);
void SerializeTriggers(FSerializer& arc);
void SerializeActor(FSerializer& arc);
void SerializeAI(FSerializer& arc);
void SerializeGameStats(FSerializer& arc);
void SerializePlayers(FSerializer& arc);
void SerializeView(FSerializer& arc);
@ -700,7 +726,6 @@ void GameInterface::SerializeGameState(FSerializer& arc)
SerializeState(arc);
InitFreeList(nextXSprite, kMaxXSprites, activeXSprites);
SerializeActor(arc);
SerializeAI(arc);
SerializePlayers(arc);
SerializeEvents(arc);
SerializeGameStats(arc);

View file

@ -43,6 +43,7 @@ void HookReplaceFunctions();
struct PLAYER;
bool checkFired6or7(PLAYER *pPlayer);
void WeaponInit(void);
void WeaponDraw(PLAYER *pPlayer, int a2, double a3, double a4, int a5);
void WeaponRaise(PLAYER *pPlayer);

View file

@ -1286,7 +1286,7 @@ void nnExtProcessSuperSprites() {
}
actAirDrag(pDebris, airVel);
actAirDrag(&bloodActors[pDebris->index], airVel);
if (pXDebris->physAttr & kPhysDebrisTouch) {
PLAYER* pPlayer = NULL;
@ -1919,7 +1919,7 @@ void trPlayerCtrlLink(XSPRITE* pXSource, PLAYER* pPlayer, bool checkCondition) {
for (unsigned k = 0; k < pCond->length; k++) {
if (pCond->obj[k].type != OBJ_SPRITE || pCond->obj[k].index != pXSource->reference) continue;
pCond->obj[k].index = pPlayer->nSprite;
pCond->obj[k].cmd = pPlayer->pXSprite->command;
pCond->obj[k].cmd = (uint8_t)pPlayer->pXSprite->command;
break;
}
@ -2985,6 +2985,7 @@ void useSpriteDamager(XSPRITE* pXSource, int objType, int objIndex) {
}
void damageSprites(XSPRITE* pXSource, spritetype* pSprite) {
auto actor = &bloodActors[pSprite->index];
spritetype* pSource = &sprite[pXSource->reference];
if (!IsDudeSprite(pSprite) || !xspriRangeIsFine(pSprite->extra) || xsprite[pSprite->extra].health <= 0 || pXSource->data3 < 0)
return;
@ -3078,7 +3079,7 @@ void damageSprites(XSPRITE* pXSource, spritetype* pSprite) {
if (forceRecoil && !pPlayer) {
pXSprite->data3 = 32767;
gDudeExtra[pSprite->extra].recoil = (dmgType == kDmgElectric) ? 1 : 0;
actor->dudeExtra.recoil = (dmgType == kDmgElectric) ? 1 : 0;
if (pXSprite->aiState->stateType != kAiStateRecoil)
RecoilDude(&bloodActors[pXSprite->reference]);
}
@ -3569,8 +3570,8 @@ bool condCheckSector(XSPRITE* pXCond, int cmpOp, bool PUSH) {
SectIterator it(objIndex);
while ((nSprite = it.NextIndex()) >= 0)
{
if (!condCmp(sprite[var].type, arg1, arg2, cmpOp)) continue;
else if (PUSH) condPush(pXCond, OBJ_SPRITE, var);
if (!condCmp(sprite[nSprite].type, arg1, arg2, cmpOp)) continue;
else if (PUSH) condPush(pXCond, OBJ_SPRITE, nSprite);
return true;
}
return false;
@ -5041,7 +5042,7 @@ bool modernTypeOperateSprite(int nSprite, spritetype* pSprite, XSPRITE* pXSprite
pXSprite->Proximity = 1;
break;
default:
actExplodeSprite(pSprite);
actExplodeSprite(&bloodActors[pSprite->index]);
break;
}
}
@ -7911,6 +7912,34 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, SPRITEMASS& w, SPR
return arc;
}
FSerializer& Serialize(FSerializer& arc, const char* keyname, OBJECTS_TO_TRACK& w, OBJECTS_TO_TRACK* def)
{
static OBJECTS_TO_TRACK nul;
if (arc.isReading()) w = {};
if (arc.BeginObject(keyname))
{
arc("type", w.type, &nul.type)
("index", w.index, &nul.index)
("xrepeat", w.cmd, &nul.cmd)
.EndObject();
}
return arc;
}
FSerializer& Serialize(FSerializer& arc, const char* keyname, TRCONDITION& w, TRCONDITION* def)
{
static TRCONDITION nul;
if (arc.isReading()) w = {};
if (arc.BeginObject(keyname))
{
arc("length", w.length, &nul.length)
("xindex", w.xindex, &nul.xindex)
.Array("obj", w.obj, w.length)
.EndObject();
}
return arc;
}
void SerializeNNExts(FSerializer& arc)
{
if (arc.BeginObject("nnexts"))
@ -7937,6 +7966,8 @@ void SerializeNNExts(FSerializer& arc)
("impactspritescount", gImpactSpritesCount)
.Array("impactspriteslist", gImpactSpritesList, gImpactSpritesCount)
("eventredirects", gEventRedirectsUsed)
("trconditioncount", gTrackingCondsCount)
.Array("trcondition", gCondition, gTrackingCondsCount)
.EndObject();
}
}

View file

@ -235,14 +235,14 @@ struct TRPLAYERCTRL { // this one for controlling the player using triggers (mov
};
struct OBJECTS_TO_TRACK {
signed int type: 3;
unsigned int index: 16;
unsigned int cmd: 8;
int8_t type;
uint8_t cmd;
int index;
};
struct TRCONDITION {
signed int xindex: 16;
unsigned int length: 8;
signed int xindex;
unsigned int length;
OBJECTS_TO_TRACK obj[kMaxTracedObjects];
};

View file

@ -660,7 +660,8 @@ void playerStart(int nPlayer, int bNewLevel)
pStartZone = &gStartZone[Random(8)];
}
spritetype *pSprite = actSpawnSprite_(pStartZone->sectnum, pStartZone->x, pStartZone->y, pStartZone->z, 6, 1);
auto actor = actSpawnSprite(pStartZone->sectnum, pStartZone->x, pStartZone->y, pStartZone->z, 6, 1);
spritetype* pSprite = &actor->s();
assert(pSprite->extra > 0 && pSprite->extra < kMaxXSprites);
XSPRITE *pXSprite = &xsprite[pSprite->extra];
pPlayer->pSprite = pSprite;
@ -977,20 +978,56 @@ char PickupItem(PLAYER *pPlayer, spritetype *pItem) {
}
}
return 0;
case kItemFlagA:
case kItemFlagA: {
if (gGameOptions.nGameType != 3) return 0;
evKill(pItem->index, 3, kCallbackReturnFlag);
pPlayer->hasFlag |= 1;
pPlayer->used2[0] = pItem->index;
gBlueFlagDropped = false;
const bool enemyTeam = (pPlayer->teamId&1) == 1;
if (!enemyTeam && (pItem->owner >= 0) && (pItem->owner < kMaxSprites)) {
pPlayer->hasFlag &= ~1;
pPlayer->used2[0] = -1;
spritetype* pOwner = &sprite[pItem->owner];
XSPRITE* pXOwner = &xsprite[pOwner->extra];
trTriggerSprite(pOwner->index, pXOwner, kCmdOn);
sprintf(buffer, "%s returned Blue Flag", PlayerName(pPlayer->nPlayer));
sndStartSample(8003, 255, 2, 0);
viewSetMessage(buffer);
break;
case kItemFlagB:
}
pPlayer->hasFlag |= 1;
pPlayer->used2[0] = pItem->owner;
if (enemyTeam)
{
sprintf(buffer, "%s stole Blue Flag", PlayerName(pPlayer->nPlayer));
sndStartSample(8007, 255, 2, 0);
viewSetMessage(buffer);
}
break;
}
case kItemFlagB: {
if (gGameOptions.nGameType != 3) return 0;
evKill(pItem->index, 3, kCallbackReturnFlag);
pPlayer->hasFlag |= 2;
pPlayer->used2[1] = pItem->index;
gRedFlagDropped = false;
const bool enemyTeam = (pPlayer->teamId&1) == 0;
if (!enemyTeam && (pItem->owner >= 0) && (pItem->owner < kMaxSprites)) {
pPlayer->hasFlag &= ~2;
pPlayer->used2[1] = -1;
spritetype* pOwner = &sprite[pItem->owner];
XSPRITE* pXOwner = &xsprite[pOwner->extra];
trTriggerSprite(pOwner->index, pXOwner, kCmdOn);
sprintf(buffer, "%s returned Red Flag", PlayerName(pPlayer->nPlayer));
sndStartSample(8002, 255, 2, 0);
viewSetMessage(buffer);
break;
}
pPlayer->hasFlag |= 2;
pPlayer->used2[1] = pItem->owner;
if (enemyTeam)
{
sprintf(buffer, "%s stole Red Flag", PlayerName(pPlayer->nPlayer));
sndStartSample(8006, 255, 2, 0);
viewSetMessage(buffer);
}
break;
}
case kItemArmorBasic:
case kItemArmorBody:
case kItemArmorFire:

View file

@ -40,9 +40,20 @@ extern void (*qavClientCallback[])(int, void *);
//
//==========================================================================
enum
using QAVPrevTileFinder = TILE_FRAME* (*)(FRAMEINFO* const thisFrame, FRAMEINFO* const prevFrame, const int& i);
struct QAVInterpProps
{
kQAVIsLoopable = 1 << 0,
QAVPrevTileFinder PrevTileFinder;
bool loopable;
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;
}
};
static TMap<FString, QAVPrevTileFinder> qavPrevTileFinders;
@ -79,7 +90,7 @@ static void qavInitTileFinderMap()
});
}
QAVPrevTileFinder qavGetInterpType(const FString& type)
static QAVPrevTileFinder qavGetInterpType(const FString& type)
{
if (!qavPrevTileFinders.CountUsed()) qavInitTileFinderMap();
return *qavPrevTileFinders.CheckKey(type);
@ -92,7 +103,7 @@ bool GameInterface::IsQAVInterpTypeValid(const FString& type)
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 : 0, qavGetInterpType(interptype), ignoredata });
qavInterpProps.Insert(res_id, { qavGetInterpType(interptype), loopable, ignoredata });
}
void GameInterface::RemoveQAVInterpProps(const int& res_id)
@ -101,25 +112,21 @@ void GameInterface::RemoveQAVInterpProps(const int& res_id)
}
void DrawFrame(double x, double y, double z, double a, TILE_FRAME *pTile, int stat, int shade, int palnum, bool to3dview)
void DrawFrame(double x, double y, double z, double a, double alpha, int picnum, int stat, int shade, int palnum, bool to3dview)
{
stat |= pTile->stat;
if (palnum <= 0) palnum = pTile->palnum;
if (!to3dview)
{
auto tex = tileGetTexture(pTile->picnum);
auto tex = tileGetTexture(picnum);
double scale = z * (1. / 65536.);
double angle = a * BAngToDegree;
int renderstyle = (stat & RS_NOMASK)? STYLE_Normal : STYLE_Translucent;
double alpha = (stat & RS_TRANS1)? glblend[0].def[!!(stat & RS_TRANS2)].alpha : 1.;
int pin = (stat & kQavOrientationLeft)? -1 : (stat & RS_ALIGN_R)? 1:0;
auto translation = TRANSLATION(Translation_Remap, palnum);
bool topleft = !!(stat & RS_TOPLEFT);
bool xflip = !!(stat & 0x100); // repurposed flag
bool yflip = !!(stat & RS_YFLIP);
auto color = shadeToLight(pTile->shade + shade);
auto color = shadeToLight(shade);
DrawTexture(twod, tex, x, y, DTA_ScaleX, scale, DTA_ScaleY, scale, DTA_Rotate, angle, DTA_LegacyRenderStyle, renderstyle, DTA_Alpha, alpha, DTA_Pin, pin, DTA_TranslationIndex, translation,
DTA_TopLeft, topleft, DTA_CenterOffsetRel, !topleft, DTA_FullscreenScale, FSMode_Fit320x200, DTA_FlipOffsets, true, DTA_Color, color,
@ -135,20 +142,24 @@ void DrawFrame(double x, double y, double z, double a, TILE_FRAME *pTile, int st
if ((stat & kQavOrientationLeft)) stat |= RS_ALIGN_L;
stat &= ~kQavOrientationLeft;
hud_drawsprite(x, y, z, a, pTile->picnum, pTile->shade + shade, palnum, stat);
hud_drawsprite(x, y, z, a, picnum, shade, palnum, stat, alpha);
}
}
static QAVInterpProps forcedinterpdata{qavGetInterpType("picnum")};
void QAV::Draw(double x, double y, int ticks, int stat, int shade, int palnum, bool to3dview, double const smoothratio)
{
assert(ticksPerFrame > 0);
auto const interpdata = qavInterpProps.CheckKey(res_id);
QAVInterpProps* interpdata = qavInterpProps.CheckKey(res_id);
if (!interpdata && cl_bloodqavforcedinterp) interpdata = &forcedinterpdata;
auto const nFrame = clamp(ticks / ticksPerFrame, 0, nFrames - 1);
FRAMEINFO* const thisFrame = &frames[nFrame];
auto const oFrame = clamp((nFrame == 0 && (interpdata && (interpdata->flags & kQAVIsLoopable)) ? nFrames : nFrame) - 1, 0, nFrames - 1);
auto const oFrame = clamp((nFrame == 0 && interpdata && interpdata->loopable ? nFrames : nFrame) - 1, 0, nFrames - 1);
FRAMEINFO* const prevFrame = &frames[oFrame];
bool const interpolate = interpdata && cl_hudinterpolation && cl_bloodqavinterp && (nFrames > 1) && (nFrame != oFrame) && (smoothratio != MaxSmoothRatio);
@ -164,6 +175,9 @@ void QAV::Draw(double x, double y, int ticks, int stat, int shade, int palnum, b
double tileY = y;
double tileZ;
double tileA;
double tileAlpha;
int tileShade;
auto const tileStat = stat | thisTile->stat;
if (prevTile)
{
@ -171,6 +185,10 @@ void QAV::Draw(double x, double y, int ticks, int stat, int shade, int palnum, b
tileY += interpolatedvaluef(prevTile->y, thisTile->y, smoothratio);
tileZ = interpolatedvaluef(prevTile->z, thisTile->z, smoothratio);
tileA = interpolatedangle(buildang(prevTile->angle), buildang(thisTile->angle), smoothratio).asbuildf();
tileShade = interpolatedvalue(prevTile->shade, thisTile->shade, smoothratio) + shade;
auto prevAlpha = ((stat | prevTile->stat) & RS_TRANS1) ? glblend[0].def[!!((stat | prevTile->stat) & RS_TRANS2)].alpha : 1.;
auto thisAlpha = (tileStat & RS_TRANS1) ? glblend[0].def[!!(tileStat & RS_TRANS2)].alpha : 1.;
tileAlpha = interpolatedvaluef(prevAlpha, thisAlpha, smoothratio);
}
else
{
@ -178,9 +196,11 @@ void QAV::Draw(double x, double y, int ticks, int stat, int shade, int palnum, b
tileY += thisTile->y;
tileZ = thisTile->z;
tileA = thisTile->angle;
tileShade = thisTile->shade + shade;
tileAlpha = (tileStat & RS_TRANS1) ? glblend[0].def[!!(tileStat & RS_TRANS2)].alpha : 1.;
}
DrawFrame(tileX, tileY, tileZ, tileA, thisTile, stat, shade, palnum, to3dview);
DrawFrame(tileX, tileY, tileZ, tileA, tileAlpha, thisTile->picnum, tileStat, tileShade, (palnum <= 0 ? thisTile->palnum : palnum), to3dview);
}
}
}
@ -266,7 +286,7 @@ void qavProcessTicker(QAV* const pQAV, int* duration, int* lastTick)
*duration = ClipLow(*duration, 0);
}
void qavProcessTimer(PLAYER* const pPlayer, QAV* const pQAV, int* duration, double* smoothratio, bool const fixedduration)
void qavProcessTimer(PLAYER* const pPlayer, QAV* const pQAV, int* duration, double* smoothratio, bool const fixedduration, bool const ignoreWeaponTimer)
{
// Process if not paused.
if (!paused)
@ -274,7 +294,7 @@ void qavProcessTimer(PLAYER* const pPlayer, QAV* const pQAV, int* duration, doub
// Process clock based on QAV's ticrate and last tick value.
qavProcessTicker(pQAV, &pPlayer->qavTimer, &pPlayer->qavLastTick);
if (pPlayer->weaponTimer == 0)
if (pPlayer->weaponTimer == 0 && pPlayer->qavTimer == 0 && !ignoreWeaponTimer)
{
// Check if we're playing an idle QAV as per the ticker's weapon timer.
*duration = fixedduration ? pQAV->duration - 1 : I_GetBuildTime() % pQAV->duration;

View file

@ -238,25 +238,9 @@ struct QAV
void Precache(int palette = 0);
};
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);
void qavProcessTimer(PLAYER* const pPlayer, QAV* const pQAV, int* duration, double* smoothratio, bool const fixedduration = false, bool const ignoreWeaponTimer = false);
inline bool qavIsOriginal(const int& res_id)
{

View file

@ -482,6 +482,11 @@ SEQINST* GetInstance(DBloodActor* actor)
return activeList.get(3, actor->s().index);
}
int seqGetStatus(DBloodActor* actor)
{
return seqGetStatus(3, actor->s().index);
}
void seqKill(int type, int nXIndex)
{
activeList.remove(type, nXIndex);

View file

@ -107,6 +107,7 @@ void seqKill(int a1, int a2);
void seqKill(DBloodActor* actor);
void seqKillAll(void);
int seqGetStatus(int a1, int a2);
int seqGetStatus(DBloodActor*);
int seqGetID(int a1, int a2);
void seqProcess(int a1);

View file

@ -169,14 +169,7 @@ void sfxPlay3DSound(int x, int y, int z, int soundId, int nSector)
if (chan) chan->UserData = nSector;
}
enum EPlayFlags
{
FX_GlobalChannel = 1,
FX_SoundMatch = 2,
FX_ChannelMatch = 4,
};
void sfxPlay3DSoundCP(spritetype* pSprite, int soundId, int a3, int a4, int pitch, int volume)
void sfxPlay3DSoundCP(spritetype* pSprite, int soundId, int playchannel, int playflags, int pitch, int volume)
{
if (!SoundEnabled() || soundId < 0 || !pSprite) return;
auto sid = soundEngine->FindSoundByResID(soundId);
@ -188,17 +181,17 @@ void sfxPlay3DSoundCP(spritetype* pSprite, int soundId, int a3, int a4, int pitc
sid = getSfx(sid, attenuation, pitch, volume);
if (volume == -1) volume = 80;
if (a3 >= 0)
if (playchannel >= 0)
{
a3++; // This is to make 0 a valid channel value.
playchannel++; // This is to make 0 a valid channel value.
if (soundEngine->EnumerateChannels([=](FSoundChan* chan) -> int
{
if (chan->SourceType != SOURCE_Actor) return false; // other source types are not our business.
if (chan->EntChannel == a3 && (chan->Source == pSprite || (a4 & FX_GlobalChannel) != 0))
if (chan->EntChannel == playchannel && (chan->Source == pSprite || (playflags & FX_GlobalChannel) != 0))
{
if ((a4 & FX_ChannelMatch) != 0 && chan->EntChannel == a3)
if ((playflags & FX_ChannelMatch) != 0 && chan->EntChannel == playchannel)
return true;
if ((a4 & FX_SoundMatch) != 0 && chan->OrgID == sid)
if ((playflags & FX_SoundMatch) != 0 && chan->OrgID == sid)
return true;
soundEngine->StopChannel(chan);
return -1;
@ -209,10 +202,10 @@ void sfxPlay3DSoundCP(spritetype* pSprite, int soundId, int a3, int a4, int pitc
}
auto sfx = soundEngine->GetSfx(sid);
EChanFlags flags = a3 == -1 ? CHANF_OVERLAP : CHANF_NONE;
EChanFlags flags = playchannel == -1 ? CHANF_OVERLAP : CHANF_NONE;
if (sfx && sfx->LoopStart >= 0) flags |= CHANF_LOOP;
soundEngine->StartSound(SOURCE_Actor, pSprite, &svec, a3, flags, sid, volume * (0.8f / 80.f), attenuation, nullptr, pitch / 65536.f);
soundEngine->StartSound(SOURCE_Actor, pSprite, &svec, playchannel, flags, sid, volume * (0.8f / 80.f), attenuation, nullptr, pitch / 65536.f);
}
void sfxPlay3DSound(spritetype* pSprite, int soundId, int a3, int a4)

View file

@ -62,4 +62,12 @@ void ambProcess(void);
void ambKillAll(void);
void ambInit(void);
enum EPlayFlags
{
FX_GlobalChannel = 1,
FX_SoundMatch = 2,
FX_ChannelMatch = 4,
};
END_BLD_NS

View file

@ -28,6 +28,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "compat.h"
#include "blood.h"
#include "misc.h"
#include "d_net.h"
BEGIN_BLD_NS
@ -206,14 +207,16 @@ void LifeLeechOperate(spritetype *pSprite, XSPRITE *pXSprite, EVENT event)
PLAYER *pPlayer = &gPlayer[nPlayer];
if (pPlayer->pXSprite->health > 0)
{
evKill(pSprite->index, 3);
pPlayer->ammoCount[8] = ClipHigh(pPlayer->ammoCount[8]+pXSprite->data3, gAmmoInfo[8].max);
pPlayer->hasWeapon[9] = 1;
if (pPlayer->curWeapon != kWeapLifeLeech)
{
if (!VanillaMode() && checkFired6or7(pPlayer)) // if tnt/spray is actively used, do not switch weapon
break;
pPlayer->weaponState = 0;
pPlayer->nextWeapon = 9;
}
evKill(pSprite->index, 3);
}
}
break;
@ -495,7 +498,7 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event)
case kThingArmedTNTStick:
case kThingArmedTNTBundle:
case kThingArmedSpray:
actExplodeSprite(pSprite);
actExplodeSprite(&bloodActors[pSprite->index]);
break;
case kTrapExploder:
switch (event.cmd) {
@ -504,13 +507,13 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event)
break;
default:
pSprite->cstat &= (unsigned short)~CSTAT_SPRITE_INVISIBLE;
actExplodeSprite(pSprite);
actExplodeSprite(&bloodActors[pSprite->index]);
break;
}
break;
case kThingArmedRemoteBomb:
if (pSprite->statnum != kStatRespawn) {
if (event.cmd != kCmdOn) actExplodeSprite(pSprite);
if (event.cmd != kCmdOn) actExplodeSprite(&bloodActors[pSprite->index]);
else {
sfxPlay3DSound(pSprite, 454, 0, 0);
evPost(nSprite, 3, 18, kCmdOff);
@ -531,7 +534,7 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event)
pXSprite->Proximity = 1;
break;
default:
actExplodeSprite(pSprite);
actExplodeSprite(&bloodActors[pSprite->index]);
break;
}
}

View file

@ -359,43 +359,23 @@ void viewUpdateDelirium(void)
void viewUpdateShake(int& cX, int& cY, int& cZ, binangle& cA, fixedhoriz& cH, double& pshakeX, double& pshakeY)
{
int shakeHoriz = 0;
int shakeAngle = 0;
int shakeX = 0;
int shakeY = 0;
int shakeZ = 0;
int shakeBobX = 0;
int shakeBobY = 0;
if (gView->flickerEffect)
auto doEffect = [&](const int& effectType)
{
int nValue = ClipHigh(gView->flickerEffect * 8, 2000);
shakeHoriz += QRandom2(nValue >> 8);
shakeAngle += QRandom2(nValue >> 8);
shakeX += QRandom2(nValue >> 4);
shakeY += QRandom2(nValue >> 4);
shakeZ += QRandom2(nValue);
shakeBobX += QRandom2(nValue);
shakeBobY += QRandom2(nValue);
}
if (gView->quakeEffect)
if (effectType)
{
int nValue = ClipHigh(gView->quakeEffect * 8, 2000);
shakeHoriz += QRandom2(nValue >> 8);
shakeAngle += QRandom2(nValue >> 8);
shakeX += QRandom2(nValue >> 4);
shakeY += QRandom2(nValue >> 4);
shakeZ += QRandom2(nValue);
shakeBobX += QRandom2(nValue);
shakeBobY += QRandom2(nValue);
int nValue = ClipHigh(effectType * 8, 2000);
cH += buildfhoriz(QRandom2F(nValue * (1. / 256.)));
cA += buildfang(QRandom2F(nValue * (1. / 256.)));
cX += QRandom2(nValue >> 4);
cY += QRandom2(nValue >> 4);
cZ += QRandom2(nValue);
pshakeX += QRandom2F(nValue);
pshakeY += QRandom2F(nValue);
}
cH += buildhoriz(shakeHoriz);
cA += buildang(shakeAngle);
cX += shakeX;
cY += shakeY;
cZ += shakeZ;
pshakeX += shakeBobX;
pshakeY += shakeBobY;
};
doEffect(gView->flickerEffect);
doEffect(gView->quakeEffect);
}
@ -483,7 +463,7 @@ void SetupView(int &cX, int& cY, int& cZ, binangle& cA, fixedhoriz& cH, int& nSe
}
viewUpdateShake(cX, cY, cZ, cA, cH, shakeX, shakeY);
cH += buildhoriz(MulScale(0x40000000 - Cos(gView->tiltEffect << 2), 30, 30));
cH += q16horiz(xs_CRoundToInt(MulScaleF(double(0x40000000) - bcosf(gView->tiltEffect << 2, 16), 30, 14)));
if (gViewPos == 0)
{
if (cl_viewhbob)
@ -495,7 +475,7 @@ void SetupView(int &cX, int& cY, int& cZ, binangle& cA, fixedhoriz& cH, int& nSe
{
cZ += bobHeight;
}
cZ += xs_CRoundToInt(cH.asq16() / 6553.6);
cZ += xs_CRoundToInt(cH.asq16() * (1. / 6553.6));
cameradist = -1;
cameraclock = PlayClock + MulScale(4, (int)gInterpolate, 16);
}

View file

@ -177,4 +177,6 @@ inline void viewBackupSpriteLoc(int nSprite, spritetype *pSprite)
}
}
void viewBackupSpriteLoc(DBloodActor* actor);
END_BLD_NS

View file

@ -140,7 +140,7 @@ enum
nClientAltFireNapalm,
};
static bool checkFired6or7(PLAYER *pPlayer)
bool checkFired6or7(PLAYER *pPlayer)
{
switch (pPlayer->curWeapon)
{
@ -228,23 +228,35 @@ void SpawnShellEject(PLAYER *pPlayer, int a2, int a3)
void WeaponInit(void)
{
for (int i = 0; i < kQAVEnd; i++)
auto doInit = [](const int base)
{
for (int i = base; i < (kQAVEnd + base); i++)
{
auto pQAV = getQAV(i);
if (!pQAV)
I_Error("Could not load QAV %d\n", i);
pQAV->nSprite = -1;
}
};
doInit(0);
doInit(10000);
}
void WeaponPrecache()
{
for (int i = 0; i < kQAVEnd; i++)
auto doPrecache = [](const int base)
{
for (int i = base; i < (kQAVEnd + base); i++)
{
auto pQAV = getQAV(i);
if (pQAV)
pQAV->Precache();
}
};
doPrecache(0);
doPrecache(10000);
}
void WeaponDraw(PLAYER *pPlayer, int shade, double xpos, double ypos, int palnum)
@ -256,7 +268,7 @@ void WeaponDraw(PLAYER *pPlayer, int shade, double xpos, double ypos, int palnum
int duration;
double smoothratio;
qavProcessTimer(pPlayer, pQAV, &duration, &smoothratio, pPlayer->weaponState == -1 || (pPlayer->curWeapon == kWeapShotgun && pPlayer->weaponState == 7));
qavProcessTimer(pPlayer, pQAV, &duration, &smoothratio, pPlayer->weaponState == -1, pPlayer->curWeapon == kWeapShotgun && pPlayer->weaponState == 7);
pQAV->x = int(xpos);
pQAV->y = int(ypos);
@ -297,6 +309,14 @@ static void StartQAV(PLAYER *pPlayer, int nWeaponQAV, int callback = -1, bool lo
pPlayer->weaponTimer -= 4;
}
static void SetQAV(PLAYER *pPlayer, int nWeaponQAV)
{
assert(nWeaponQAV < kQAVEnd);
pPlayer->weaponQav = qavGetCorrectID(nWeaponQAV);
pPlayer->qavTimer = 0;
pPlayer->qavLastTick = 0;
}
struct WEAPONTRACK
{
int aimSpeedHorz;
@ -833,7 +853,7 @@ void WeaponUpdateState(PLAYER *pPlayer)
switch (lastWeapon)
{
case kWeapPitchFork:
pPlayer->weaponQav = qavGetCorrectID(kQAVFORKIDLE);
SetQAV(pPlayer, kQAVFORKIDLE);
break;
case kWeapSpraycan:
switch (vb)
@ -849,15 +869,15 @@ void WeaponUpdateState(PLAYER *pPlayer)
StartQAV(pPlayer, kQAVCANPREF);
}
else
pPlayer->weaponQav = qavGetCorrectID(kQAVLITEIDLE);
SetQAV(pPlayer, kQAVLITEIDLE);
break;
case 3:
pPlayer->weaponQav = qavGetCorrectID(kQAVCANIDLE);
SetQAV(pPlayer, kQAVCANIDLE);
break;
case 4:
if (CheckAmmo(pPlayer, 6, 1))
{
pPlayer->weaponQav = qavGetCorrectID(kQAVCANIDLE);
SetQAV(pPlayer, kQAVCANIDLE);
pPlayer->weaponState = 3;
}
else
@ -890,10 +910,10 @@ void WeaponUpdateState(PLAYER *pPlayer)
StartQAV(pPlayer, kQAVBUNUP);
}
else
pPlayer->weaponQav = qavGetCorrectID(kQAVLITEIDLE);
SetQAV(pPlayer, kQAVLITEIDLE);
break;
case 3:
pPlayer->weaponQav = qavGetCorrectID(kQAVBUNIDLE);
SetQAV(pPlayer, kQAVBUNIDLE);
break;
}
break;
@ -901,7 +921,7 @@ void WeaponUpdateState(PLAYER *pPlayer)
switch (vb)
{
case 7:
pPlayer->weaponQav = qavGetCorrectID(kQAVPROXIDLE);
SetQAV(pPlayer, kQAVPROXIDLE);
break;
case 8:
pPlayer->weaponState = 7;
@ -913,10 +933,10 @@ void WeaponUpdateState(PLAYER *pPlayer)
switch (vb)
{
case 10:
pPlayer->weaponQav = qavGetCorrectID(kQAVREMIDLE1);
SetQAV(pPlayer, kQAVREMIDLE1);
break;
case 11:
pPlayer->weaponQav = qavGetCorrectID(kQAVREMIDLE2);
SetQAV(pPlayer, kQAVREMIDLE2);
break;
case 12:
if (pPlayer->ammoCount[11] > 0)
@ -939,7 +959,7 @@ void WeaponUpdateState(PLAYER *pPlayer)
pPlayer->weaponState = 1;
break;
case 7:
pPlayer->weaponQav = qavGetCorrectID(kQAV2SHOTI);
SetQAV(pPlayer, kQAV2SHOTI);
break;
case 1:
if (CheckAmmo(pPlayer, 2, 1))
@ -952,25 +972,25 @@ void WeaponUpdateState(PLAYER *pPlayer)
pPlayer->weaponState = 2;
}
else
pPlayer->weaponQav = qavGetCorrectID(kQAVSHOTI3);
SetQAV(pPlayer, kQAVSHOTI3);
break;
case 2:
pPlayer->weaponQav = qavGetCorrectID(kQAVSHOTI2);
SetQAV(pPlayer, kQAVSHOTI2);
break;
case 3:
pPlayer->weaponQav = qavGetCorrectID(kQAVSHOTI1);
SetQAV(pPlayer, kQAVSHOTI1);
break;
}
break;
case kWeapTommyGun:
if (powerupCheck(pPlayer, kPwUpTwoGuns) && checkAmmo2(pPlayer, 3, 2))
{
pPlayer->weaponQav = qavGetCorrectID(kQAV2TOMIDLE);
SetQAV(pPlayer, kQAV2TOMIDLE);
pPlayer->weaponState = 1;
}
else
{
pPlayer->weaponQav = qavGetCorrectID(kQAVTOMIDLE);
SetQAV(pPlayer, kQAVTOMIDLE);
pPlayer->weaponState = 0;
}
break;
@ -978,33 +998,33 @@ void WeaponUpdateState(PLAYER *pPlayer)
if (powerupCheck(pPlayer, kPwUpTwoGuns))
{
if (vb == 3 && checkAmmo2(pPlayer, 1, 2))
pPlayer->weaponQav = qavGetCorrectID(kQAVFLAR2I);
SetQAV(pPlayer, kQAVFLAR2I);
else
{
pPlayer->weaponQav = qavGetCorrectID(kQAVFLARIDLE);
SetQAV(pPlayer, kQAVFLARIDLE);
pPlayer->weaponState = 2;
}
}
else
pPlayer->weaponQav = qavGetCorrectID(kQAVFLARIDLE);
SetQAV(pPlayer, kQAVFLARIDLE);
break;
case kWeapVoodooDoll:
if (pXSprite->height < 256 && pPlayer->swayHeight != 0)
StartQAV(pPlayer, kQAVVDIDLE2);
else
pPlayer->weaponQav = qavGetCorrectID(kQAVVDIDLE1);
SetQAV(pPlayer, kQAVVDIDLE1);
break;
case kWeapTeslaCannon:
switch (vb)
{
case 2:
if (checkAmmo2(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns))
pPlayer->weaponQav = qavGetCorrectID(kQAV2SGUNIDL);
SetQAV(pPlayer, kQAV2SGUNIDL);
else
pPlayer->weaponQav = qavGetCorrectID(kQAVSGUNIDL1);
SetQAV(pPlayer, kQAVSGUNIDL1);
break;
case 3:
pPlayer->weaponQav = qavGetCorrectID(kQAVSGUNIDL2);
SetQAV(pPlayer, kQAVSGUNIDL2);
break;
}
break;
@ -1013,12 +1033,12 @@ void WeaponUpdateState(PLAYER *pPlayer)
{
case 3:
if (powerupCheck(pPlayer, kPwUpTwoGuns) && (gInfiniteAmmo || CheckAmmo(pPlayer,4, 4)))
pPlayer->weaponQav = qavGetCorrectID(kQAV2NAPIDLE);
SetQAV(pPlayer, kQAV2NAPIDLE);
else
pPlayer->weaponQav = qavGetCorrectID(kQAVNAPIDLE);
SetQAV(pPlayer, kQAVNAPIDLE);
break;
case 2:
pPlayer->weaponQav = qavGetCorrectID(kQAVNAPIDLE);
SetQAV(pPlayer, kQAVNAPIDLE);
break;
}
break;
@ -1026,12 +1046,12 @@ void WeaponUpdateState(PLAYER *pPlayer)
switch (vb)
{
case 2:
pPlayer->weaponQav = qavGetCorrectID(kQAVSTAFIDL1);
SetQAV(pPlayer, kQAVSTAFIDL1);
break;
}
break;
case kWeapBeast:
pPlayer->weaponQav = qavGetCorrectID(kQAVBSTIDLE);
SetQAV(pPlayer, kQAVBSTIDLE);
break;
}
}
@ -1586,7 +1606,7 @@ void FireTesla(int nTrigger, PLAYER *pPlayer)
if (!checkAmmo2(pPlayer, 7, pMissile->ammouse))
{
pPlayer->weaponState = -1;
pPlayer->weaponQav = qavGetCorrectID(kQAVSGUNIDL2);
SetQAV(pPlayer, kQAVSGUNIDL2);
pPlayer->flashEffect = 0;
return;
}
@ -2029,7 +2049,8 @@ void WeaponProcess(PLAYER *pPlayer) {
pPlayer->weaponTimer -= 4;
bool bShoot = pPlayer->input.actions & SB_FIRE;
bool bShoot2 = pPlayer->input.actions & SB_ALTFIRE;
if ((bShoot || bShoot2) && pPlayer->weaponQav == qavGetCorrectID(kQAVVDIDLE2)) pPlayer->weaponTimer = 0;
const int prevNewWeaponVal = pPlayer->input.getNewWeapon(); // used to fix scroll issue for banned weapons
if ((bShoot || bShoot2 || prevNewWeaponVal) && pPlayer->weaponQav == qavGetCorrectID(kQAVVDIDLE2)) pPlayer->weaponTimer = 0;
if (pPlayer->qavLoop && pPlayer->pXSprite->health > 0)
{
if (bShoot && CheckAmmo(pPlayer, pPlayer->weaponAmmo, 1))
@ -2084,7 +2105,6 @@ void WeaponProcess(PLAYER *pPlayer) {
return;
break;
}
const int prevNewWeaponVal = pPlayer->input.getNewWeapon(); // used to fix scroll issue for banned weapons
if (VanillaMode())
{
if (pPlayer->nextWeapon)
@ -2355,7 +2375,7 @@ void WeaponProcess(PLAYER *pPlayer) {
switch (pPlayer->weaponState)
{
case 7:
pPlayer->weaponQav = qavGetCorrectID(kQAVPROXIDLE);
SetQAV(pPlayer, kQAVPROXIDLE);
pPlayer->weaponState = 9;
pPlayer->throwTime = PlayClock;
return;
@ -2365,7 +2385,7 @@ void WeaponProcess(PLAYER *pPlayer) {
switch (pPlayer->weaponState)
{
case 10:
pPlayer->weaponQav = qavGetCorrectID(kQAVREMIDLE1);
SetQAV(pPlayer, kQAVREMIDLE1);
pPlayer->weaponState = 13;
pPlayer->throwTime = PlayClock;
return;

View file

@ -509,7 +509,7 @@ void LoadCustomInfoFromScript(const char *filename)
curep = sc.Number;
if (sc.ParseError) curep = -1;
else if ((unsigned)--curep >= 2u)
else if ((unsigned)curep > 2u)
{
sc.ScriptMessage("Episode number %d not in range 1-2\n", curep + 1);
curep = -1;
@ -808,8 +808,8 @@ void LoadCustomInfoFromScript(const char *filename)
break;
}
}
auto vol0 = MustFindVolume(0);
auto vol1 = MustFindVolume(1);
auto vol0 = MustFindVolume(1);
auto vol1 = MustFindVolume(2);
auto map1 = FindMapByLevelNum(1);
auto map5 = FindMapByLevelNum(5);
if (vol0 && map1) vol0->startmap = map1->labelName;

View file

@ -376,6 +376,7 @@ grpinfo
{
name "Duke: Alien World Order"
dependency DUKE15_CRC
flags GAMEFLAG_DUKE|GAMEFLAG_ADDON
mustcontain "FIREFLYTROOPER.CON", "FLAMETHROWER.CON", "music/E5L1_BulletDam.ogg", "sound/VO_E5L1_Duke_CreamAndSugar.ogg"
gamefilter "Duke.Worldtour"
GameID "DukeWorldTour"
@ -462,22 +463,6 @@ grpinfo
GameID "Blood"
}
grpinfo
{
name "BLOOD: One Unit Whole Blood"
size 9570681
crc BLOOD_CRC
defname "blood.def"
scriptname "BLOOD.INI"
flags GAMEFLAG_BLOOD
dependency 0
loadgrp "SOUNDS.RFF", "GUI.RFF"
gamefilter "Blood.Blood"
FgColor 0
BkColor 0x7f002f
GameID "Blood"
}
grpinfo
{
// This is for identifying older Blood versions. Since I have no information, all I can do is testing for a few known files.

View file

@ -662,45 +662,24 @@ defineqav 10092 {
}
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"

View file

@ -63,7 +63,6 @@ map { 2, 2 }
{
interbackground = "LEVELMAP09"
rr_startsound = 176
clearweapons
}
map { 2, 3 }

View file

@ -260,7 +260,7 @@ class ListMenu : Menu
{
for(int i=0;i<mDesc.mItems.Size(); i++)
{
if (mDesc.mItems[i].CheckCoordinate(x, y))
if (mDesc.mItems[i].Selectable() && mDesc.mItems[i].CheckCoordinate(x, y))
{
if (i != mDesc.mSelectedItem)
{