From 5061d5b37c1760564919c9d787a618e380525591 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 29 Dec 2021 22:56:21 +0100 Subject: [PATCH] - tabified the rest of Blood's code. --- source/games/blood/src/levels.cpp | 374 +- source/games/blood/src/levels.h | 30 +- source/games/blood/src/loadsave.cpp | 74 +- source/games/blood/src/mapstructs.h | 440 +- source/games/blood/src/messages.cpp | 812 +- source/games/blood/src/messages.h | 10 +- source/games/blood/src/mirrors.cpp | 230 +- source/games/blood/src/misc.cpp | 16 +- source/games/blood/src/misc.h | 62 +- source/games/blood/src/nnexts.cpp | 13758 ++++++++++++------------ source/games/blood/src/nnexts.h | 306 +- source/games/blood/src/osdcmd.cpp | 82 +- source/games/blood/src/player.cpp | 4396 ++++---- source/games/blood/src/player.h | 314 +- source/games/blood/src/prediction.cpp | 960 +- source/games/blood/src/preload.cpp | 524 +- source/games/blood/src/qav.cpp | 530 +- source/games/blood/src/qav.h | 322 +- source/games/blood/src/sbar.cpp | 74 +- source/games/blood/src/sectorfx.cpp | 580 +- source/games/blood/src/seq.cpp | 8 +- source/games/blood/src/sfx.cpp | 359 +- source/games/blood/src/sound.cpp | 243 +- source/games/blood/src/sound.h | 26 +- source/games/blood/src/tile.cpp | 18 + source/games/blood/src/trig.cpp | 24 +- source/games/blood/src/triggers.cpp | 4038 +++---- source/games/blood/src/triggers.h | 26 +- source/games/blood/src/view.cpp | 1229 ++- source/games/blood/src/view.h | 184 +- source/games/blood/src/warp.cpp | 509 +- source/games/blood/src/weapon.cpp | 5154 ++++----- 32 files changed, 18547 insertions(+), 17165 deletions(-) diff --git a/source/games/blood/src/levels.cpp b/source/games/blood/src/levels.cpp index 935d197b6..0c11d1517 100644 --- a/source/games/blood/src/levels.cpp +++ b/source/games/blood/src/levels.cpp @@ -34,7 +34,7 @@ BEGIN_BLD_NS GAMEOPTIONS gGameOptions; GAMEOPTIONS gSingleGameOptions = { - 0, 2, 0, 0, 0, 0, 0, 0, 2, 3600, 1800, 1800, 7200 + 0, 2, 0, 0, 0, 0, 0, 0, 2, 3600, 1800, 1800, 7200 }; int gSkill = 2; @@ -42,216 +42,256 @@ MapRecord* gNextLevel; char BloodIniFile[BMAX_PATH] = "BLOOD.INI"; bool bINIOverride = false; -IniFile *BloodINI; +IniFile* BloodINI; -void levelInitINI(const char *pzIni) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void levelInitINI(const char* pzIni) { if (!fileSystem.FileExists(pzIni)) - I_Error("Initialization: %s does not exist", pzIni); - BloodINI = new IniFile(pzIni); - strncpy(BloodIniFile, pzIni, BMAX_PATH-1); + I_Error("Initialization: %s does not exist", pzIni); + BloodINI = new IniFile(pzIni); + strncpy(BloodIniFile, pzIni, BMAX_PATH - 1); } -void CheckSectionAbend(const char *pzSection) +void CheckSectionAbend(const char* pzSection) { - if (!pzSection || !BloodINI->SectionExists(pzSection)) - I_Error("Section [%s] expected in BLOOD.INI", pzSection); + if (!pzSection || !BloodINI->SectionExists(pzSection)) + I_Error("Section [%s] expected in BLOOD.INI", pzSection); } -void CheckKeyAbend(const char *pzSection, const char *pzKey) +void CheckKeyAbend(const char* pzSection, const char* pzKey) { - assert(pzSection != NULL); + assert(pzSection != NULL); - if (!pzKey || !BloodINI->KeyExists(pzSection, pzKey)) - I_Error("Key %s expected in section [%s] of BLOOD.INI", pzKey, pzSection); + if (!pzKey || !BloodINI->KeyExists(pzSection, pzKey)) + I_Error("Key %s expected in section [%s] of BLOOD.INI", pzKey, pzSection); } - +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- void levelLoadMapInfo(IniFile* pIni, MapRecord* pLevelInfo, const char* pzSection, int epinum, int mapnum, int* nextmap, int* nextsecret) { - char buffer[16]; - pLevelInfo->SetName(pIni->GetKeyString(pzSection, "Title", pLevelInfo->labelName)); - pLevelInfo->Author = pIni->GetKeyString(pzSection, "Author", ""); - pLevelInfo->music = pIni->GetKeyString(pzSection, "Song", ""); if (pLevelInfo->music.IsNotEmpty()) DefaultExtension(pLevelInfo->music, ".mid"); - pLevelInfo->cdSongId = pIni->GetKeyInt(pzSection, "Track", -1); - *nextmap = pIni->GetKeyInt(pzSection, "EndingA", 0); - *nextsecret = pIni->GetKeyInt(pzSection, "EndingB", 0); - pLevelInfo->fog = pIni->GetKeyInt(pzSection, "Fog", -0); - pLevelInfo->weather = pIni->GetKeyInt(pzSection, "Weather", -0); - for (int i = 0; i < kMaxMessages; i++) - { - sprintf(buffer, "Message%d", i + 1); - auto msg = pIni->GetKeyString(pzSection, buffer, ""); - pLevelInfo->AddMessage(i, msg); - } + char buffer[16]; + pLevelInfo->SetName(pIni->GetKeyString(pzSection, "Title", pLevelInfo->labelName)); + pLevelInfo->Author = pIni->GetKeyString(pzSection, "Author", ""); + pLevelInfo->music = pIni->GetKeyString(pzSection, "Song", ""); if (pLevelInfo->music.IsNotEmpty()) DefaultExtension(pLevelInfo->music, ".mid"); + pLevelInfo->cdSongId = pIni->GetKeyInt(pzSection, "Track", -1); + *nextmap = pIni->GetKeyInt(pzSection, "EndingA", 0); + *nextsecret = pIni->GetKeyInt(pzSection, "EndingB", 0); + pLevelInfo->fog = pIni->GetKeyInt(pzSection, "Fog", -0); + pLevelInfo->weather = pIni->GetKeyInt(pzSection, "Weather", -0); + for (int i = 0; i < kMaxMessages; i++) + { + sprintf(buffer, "Message%d", i + 1); + auto msg = pIni->GetKeyString(pzSection, buffer, ""); + pLevelInfo->AddMessage(i, msg); + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + static const char* DefFile(void) { - int found = -1; - if (userConfig.DefaultCon.IsEmpty() || userConfig.DefaultCon.CompareNoCase("blood.ini") == 0) - { - int numlumps = fileSystem.GetNumEntries(); - for (int i = numlumps - 1; i >= 0; i--) - { - int fileno = fileSystem.GetFileContainer(i); - if (fileno != -1 && fileno <= fileSystem.GetMaxIwadNum()) continue; - FString fn = fileSystem.GetFileFullName(i, false); - FString ext = fn.Right(4); - if (ext.CompareNoCase(".ini") == 0) - { - if (fileSystem.CheckNumForFullName(fn) != i) continue; - if (found == -1) - { - IniFile inif(fn); - for (int j = 1; j <= 6; j++) - { - FStringf key("Episode%d", j); - if (inif.SectionExists(key)) - { - found = i; - break; - } - } - } - else - { - found = -1; - break; - } - } - } - } - if (found >= 0) return fileSystem.GetFileFullName(found); - // The command line parser stores this in the CON field. - return userConfig.DefaultCon.IsNotEmpty() ? userConfig.DefaultCon.GetChars() : "blood.ini"; + int found = -1; + if (userConfig.DefaultCon.IsEmpty() || userConfig.DefaultCon.CompareNoCase("blood.ini") == 0) + { + int numlumps = fileSystem.GetNumEntries(); + for (int i = numlumps - 1; i >= 0; i--) + { + int fileno = fileSystem.GetFileContainer(i); + if (fileno != -1 && fileno <= fileSystem.GetMaxIwadNum()) continue; + FString fn = fileSystem.GetFileFullName(i, false); + FString ext = fn.Right(4); + if (ext.CompareNoCase(".ini") == 0) + { + if (fileSystem.CheckNumForFullName(fn) != i) continue; + if (found == -1) + { + IniFile inif(fn); + for (int j = 1; j <= 6; j++) + { + FStringf key("Episode%d", j); + if (inif.SectionExists(key)) + { + found = i; + break; + } + } + } + else + { + found = -1; + break; + } + } + } + } + if (found >= 0) return fileSystem.GetFileFullName(found); + // The command line parser stores this in the CON field. + return userConfig.DefaultCon.IsNotEmpty() ? userConfig.DefaultCon.GetChars() : "blood.ini"; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + static FString cleanPath(const char* pth) { - FString path = pth; - FixPathSeperator(path); - if (fileSystem.FileExists(path)) return path; - if (path.Len() > 3 && path[1] == ':' && isalpha(path[0]) && path[2] == '/') - { - path = path.Mid(3); - if (fileSystem.FileExists(path)) return path; - } - // optionally strip the first path component to account for poor logic of the DOS EXE. - auto pos = path.IndexOf("/"); - if (pos >= 0) - { - auto npath = path.Mid(pos + 1); - if (fileSystem.FileExists(npath)) return npath; - } - return path; + FString path = pth; + FixPathSeperator(path); + if (fileSystem.FileExists(path)) return path; + if (path.Len() > 3 && path[1] == ':' && isalpha(path[0]) && path[2] == '/') + { + path = path.Mid(3); + if (fileSystem.FileExists(path)) return path; + } + // optionally strip the first path component to account for poor logic of the DOS EXE. + auto pos = path.IndexOf("/"); + if (pos >= 0) + { + auto npath = path.Mid(pos + 1); + if (fileSystem.FileExists(npath)) return npath; + } + return path; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void levelLoadDefaults(void) { - char buffer[64]; - char buffer2[16]; + char buffer[64]; + char buffer2[16]; - int cutALevel = 0; + int cutALevel = 0; - levelInitINI(DefFile()); - int i; - for (i = 1; i <= kMaxEpisodes; i++) - { - sprintf(buffer, "Episode%d", i); - if (!BloodINI->SectionExists(buffer)) - break; - auto cluster = MustFindCluster(i); - auto volume = MustFindVolume(i); - CutsceneDef &csB = cluster->outro; - FString ep_str = BloodINI->GetKeyString(buffer, "Title", buffer); - ep_str.StripRight(); - cluster->name = volume->name = FStringTable::MakeMacro(ep_str); - if (i > 1) volume->flags |= VF_SHAREWARELOCK; - if (BloodINI->GetKeyInt(buffer, "BloodBathOnly", 0)) volume->flags |= VF_HIDEFROMSP; + levelInitINI(DefFile()); + int i; + for (i = 1; i <= kMaxEpisodes; i++) + { + sprintf(buffer, "Episode%d", i); + if (!BloodINI->SectionExists(buffer)) + break; + auto cluster = MustFindCluster(i); + auto volume = MustFindVolume(i); + CutsceneDef& csB = cluster->outro; + FString ep_str = BloodINI->GetKeyString(buffer, "Title", buffer); + ep_str.StripRight(); + cluster->name = volume->name = FStringTable::MakeMacro(ep_str); + if (i > 1) volume->flags |= VF_SHAREWARELOCK; + if (BloodINI->GetKeyInt(buffer, "BloodBathOnly", 0)) volume->flags |= VF_HIDEFROMSP; - csB.video = cleanPath(BloodINI->GetKeyString(buffer, "CutSceneB", "")); - int soundint = BloodINI->GetKeyInt(buffer, "CutWavB", -1); - if (soundint > 0) csB.soundID = soundint + 0x40000000; - else csB.soundName = cleanPath(BloodINI->GetKeyString(buffer, "CutWavB", "")); + csB.video = cleanPath(BloodINI->GetKeyString(buffer, "CutSceneB", "")); + int soundint = BloodINI->GetKeyInt(buffer, "CutWavB", -1); + if (soundint > 0) csB.soundID = soundint + 0x40000000; + else csB.soundName = cleanPath(BloodINI->GetKeyString(buffer, "CutWavB", "")); - //pEpisodeInfo->bloodbath = BloodINI->GetKeyInt(buffer, "BloodBathOnly", 0); - cutALevel = BloodINI->GetKeyInt(buffer, "CutSceneALevel", 0); - if (cutALevel < 1) cutALevel = 1; + //pEpisodeInfo->bloodbath = BloodINI->GetKeyInt(buffer, "BloodBathOnly", 0); + cutALevel = BloodINI->GetKeyInt(buffer, "CutSceneALevel", 0); + if (cutALevel < 1) cutALevel = 1; - int nextmaps[kMaxLevels]{}, nextsecrets[kMaxLevels]{}; - for (int j = 1; j <= kMaxLevels; j++) - { - sprintf(buffer2, "Map%d", j); - if (!BloodINI->KeyExists(buffer, buffer2)) - break; - auto pLevelInfo = AllocateMap(); - const char *pMap = BloodINI->GetKeyString(buffer, buffer2, NULL); - CheckSectionAbend(pMap); + int nextmaps[kMaxLevels]{}, nextsecrets[kMaxLevels]{}; + for (int j = 1; j <= kMaxLevels; j++) + { + sprintf(buffer2, "Map%d", j); + if (!BloodINI->KeyExists(buffer, buffer2)) + break; + auto pLevelInfo = AllocateMap(); + const char* pMap = BloodINI->GetKeyString(buffer, buffer2, NULL); + CheckSectionAbend(pMap); SetLevelNum(pLevelInfo, makelevelnum(i, j)); - pLevelInfo->cluster = i; - pLevelInfo->labelName = pMap; + pLevelInfo->cluster = i; + pLevelInfo->labelName = pMap; if (j == 1) volume->startmap = pLevelInfo->labelName; - pLevelInfo->fileName.Format("%s.map", pMap); - levelLoadMapInfo(BloodINI, pLevelInfo, pMap, i, j, &nextmaps[j - 1], &nextsecrets[j - 1]); - if (j == cutALevel) - { - CutsceneDef& csA = pLevelInfo->intro; - csA.video = cleanPath(BloodINI->GetKeyString(buffer, "CutSceneA", "")); - int soundfileint = BloodINI->GetKeyInt(buffer, "CutWavA", -1); - if (soundfileint > 0) csA.soundID = soundfileint + 0x40000000; - else csA.soundName = cleanPath(BloodINI->GetKeyString(buffer, "CutWavA", "")); - } - } - // Now resolve the level links - for (int j = 1; j <= kMaxLevels; j++) - { - auto map = FindMapByIndexOnly(i, j); - if (map) - { - if (nextmaps[j - 1] > 0) - { - auto nmap = FindMapByIndexOnly(i, nextmaps[j - 1]); - if (nmap) map->NextMap = nmap->labelName; - else map->NextMap = "-"; - } - else map->NextMap = "-"; - if (nextsecrets[j - 1] > 0) - { - auto nmap = FindMapByIndexOnly(i, nextsecrets[j - 1]); - if (nmap) map->NextSecret = nmap->labelName; - else map->NextSecret = "-"; - } - else map->NextSecret = "-"; - } - } - } + pLevelInfo->fileName.Format("%s.map", pMap); + levelLoadMapInfo(BloodINI, pLevelInfo, pMap, i, j, &nextmaps[j - 1], &nextsecrets[j - 1]); + if (j == cutALevel) + { + CutsceneDef& csA = pLevelInfo->intro; + csA.video = cleanPath(BloodINI->GetKeyString(buffer, "CutSceneA", "")); + int soundfileint = BloodINI->GetKeyInt(buffer, "CutWavA", -1); + if (soundfileint > 0) csA.soundID = soundfileint + 0x40000000; + else csA.soundName = cleanPath(BloodINI->GetKeyString(buffer, "CutWavA", "")); + } + } + // Now resolve the level links + for (int j = 1; j <= kMaxLevels; j++) + { + auto map = FindMapByIndexOnly(i, j); + if (map) + { + if (nextmaps[j - 1] > 0) + { + auto nmap = FindMapByIndexOnly(i, nextmaps[j - 1]); + if (nmap) map->NextMap = nmap->labelName; + else map->NextMap = "-"; + } + else map->NextMap = "-"; + if (nextsecrets[j - 1] > 0) + { + auto nmap = FindMapByIndexOnly(i, nextsecrets[j - 1]); + if (nmap) map->NextSecret = nmap->labelName; + else map->NextSecret = "-"; + } + else map->NextSecret = "-"; + } + } + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void levelEndLevel(int secret) { - gGameOptions.uGameFlags |= GF_AdvanceLevel; - if (!secret) gNextLevel = FindNextMap(currentLevel); - else gNextLevel = FindNextSecretMap(currentLevel); + gGameOptions.uGameFlags |= GF_AdvanceLevel; + if (!secret) gNextLevel = FindNextMap(currentLevel); + else gNextLevel = FindNextSecretMap(currentLevel); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void levelTryPlayMusic() { - FString buffer; - if (mus_redbook && currentLevel->cdSongId > 0) - buffer.Format("blood%02i.ogg", currentLevel->cdSongId); - else - { - buffer = currentLevel->music; + FString buffer; + if (mus_redbook && currentLevel->cdSongId > 0) + buffer.Format("blood%02i.ogg", currentLevel->cdSongId); + else + { + buffer = currentLevel->music; if (Mus_Play(buffer, true)) return; - if (buffer.IsNotEmpty()) DefaultExtension(buffer, ".mid"); - } - if (!Mus_Play(buffer, true)) - { - Mus_Play("", true); - } + if (buffer.IsNotEmpty()) DefaultExtension(buffer, ".mid"); + } + if (!Mus_Play(buffer, true)) + { + Mus_Play("", true); + } } diff --git a/source/games/blood/src/levels.h b/source/games/blood/src/levels.h index c10778547..e3a8d61ae 100644 --- a/source/games/blood/src/levels.h +++ b/source/games/blood/src/levels.h @@ -46,22 +46,22 @@ enum EGameFlag }; struct GAMEOPTIONS { - uint8_t nGameType; - uint8_t nDifficulty; - uint8_t nMonsterSettings; - int uGameFlags; - int uNetGameFlags; + uint8_t nGameType; + uint8_t nDifficulty; + uint8_t nMonsterSettings; + int uGameFlags; + int uNetGameFlags; uint8_t nWeaponSettings; uint8_t nItemSettings; uint8_t nRespawnSettings; uint8_t nTeamSettings; - int nMonsterRespawnTime; - int nWeaponRespawnTime; - int nItemRespawnTime; - int nSpecialRespawnTime; - int weaponsV10x; - bool bFriendlyFire; - bool bKeepKeysOnRespawn; + int nMonsterRespawnTime; + int nWeaponRespawnTime; + int nItemRespawnTime; + int nSpecialRespawnTime; + int weaponsV10x; + bool bFriendlyFire; + bool bKeepKeysOnRespawn; }; #pragma pack(pop) @@ -74,9 +74,9 @@ extern bool bINIOverride; extern MapRecord* gNextLevel; extern bool gGameStarted; -void levelInitINI(const char *pzIni); -void CheckSectionAbend(const char *pzSection); -void CheckKeyAbend(const char *pzSection, const char *pzKey); +void levelInitINI(const char* pzIni); +void CheckSectionAbend(const char* pzSection); +void CheckKeyAbend(const char* pzSection, const char* pzKey); void levelLoadDefaults(void); // arg: 0 is normal exit, 1 is secret level void levelEndLevel(int arg); diff --git a/source/games/blood/src/loadsave.cpp b/source/games/blood/src/loadsave.cpp index c456b89bc..79b1b4732 100644 --- a/source/games/blood/src/loadsave.cpp +++ b/source/games/blood/src/loadsave.cpp @@ -39,7 +39,7 @@ BEGIN_BLD_NS void validateLinks(); // All AI states for assigning an index. -static AISTATE* allAIStates[] = +static AISTATE* const allAIStates[] = { nullptr, &genIdle, @@ -391,6 +391,12 @@ static AISTATE* allAIStates[] = &zombieFTeslaRecoil, }; +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + FSerializer& Serialize(FSerializer& arc, const char* keyname, AISTATE*& w, AISTATE** def) { unsigned i = 0; @@ -456,6 +462,12 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, DUDEEXTRA& w, DUDE return arc; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void DBloodActor::Serialize(FSerializer& arc) { Super::Serialize(arc); @@ -464,9 +476,9 @@ void DBloodActor::Serialize(FSerializer& arc) ("zvel", zvel) ("hasx", hasx); - // The rest is only relevant if the actor has an xsprite. + // The rest is only relevant if the actor has an xsprite. if (hasX()) - { + { arc("xsprite", xspr) ("dudeslope", dudeSlope) ("dudeextra", dudeExtra) @@ -476,23 +488,29 @@ void DBloodActor::Serialize(FSerializer& arc) ("owneractor", ownerActor); #ifdef NOONE_EXTENSIONS - if (gModernMap) - { + if (gModernMap) + { arc("spritemass", spriteMass) ("prevmarker", prevmarker) .Array("conditions", condition, 2); - - // GenDudeExtra only contains valid info for kDudeModernCustom and kDudeModernCustomBurning so only save when needed as these are not small. - if (spr.type == kDudeModernCustom || spr.type == kDudeModernCustomBurning) - { + + // GenDudeExtra only contains valid info for kDudeModernCustom and kDudeModernCustomBurning so only save when needed as these are not small. + if (spr.type == kDudeModernCustom || spr.type == kDudeModernCustomBurning) + { arc("gendudeextra", genDudeExtra); - } } + } #endif - } + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + FSerializer& Serialize(FSerializer& arc, const char* keyname, XWALL& w, XWALL* def) { static XWALL nul; @@ -520,6 +538,12 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, XWALL& w, XWALL* d return arc; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + FSerializer& Serialize(FSerializer& arc, const char* keyname, XSECTOR& w, XSECTOR* def) { static XSECTOR nul; @@ -573,6 +597,12 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, XSECTOR& w, XSECTO return arc; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + FSerializer& Serialize(FSerializer& arc, const char* keyname, XSPRITE& w, XSPRITE* def) { static XSPRITE nul; @@ -623,6 +653,12 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, XSPRITE& w, XSPRIT return arc; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + FSerializer& Serialize(FSerializer& arc, const char* keyname, GAMEOPTIONS& w, GAMEOPTIONS* def) { if (arc.BeginObject(keyname)) @@ -647,6 +683,12 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, GAMEOPTIONS& w, GA return arc; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void SerializeState(FSerializer& arc) { if (arc.isReading()) @@ -690,18 +732,24 @@ void SerializeView(FSerializer& arc); void SerializeNNExts(FSerializer& arc); void SerializeMirrors(FSerializer& arc); +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void GameInterface::SerializeGameState(FSerializer& arc) { if (arc.isWriting()) { - } + } else { sndKillAllSounds(); sfxKillAllSounds(); ambKillAll(); seqKillAll(); - } + } SerializeState(arc); SerializeActor(arc); SerializePlayers(arc); diff --git a/source/games/blood/src/mapstructs.h b/source/games/blood/src/mapstructs.h index 007fc6706..1d29d3d92 100644 --- a/source/games/blood/src/mapstructs.h +++ b/source/games/blood/src/mapstructs.h @@ -7,259 +7,257 @@ // Keep it local so that the engine's sprite type is no longer limited by file format restrictions. struct spritetypedisk { - int32_t x, y, z; - uint16_t cstat; - int16_t picnum; - int8_t shade; - uint8_t pal, clipdist, detail; - uint8_t xrepeat, yrepeat; - int8_t xoffset, yoffset; - int16_t sectnum, statnum; - int16_t ang, owner; - int16_t index, yvel, inittype; - int16_t type; - int16_t hitag; - int16_t extra; + int32_t x, y, z; + uint16_t cstat; + int16_t picnum; + int8_t shade; + uint8_t pal, clipdist, detail; + uint8_t xrepeat, yrepeat; + int8_t xoffset, yoffset; + int16_t sectnum, statnum; + int16_t ang, owner; + int16_t index, yvel, inittype; + int16_t type; + int16_t hitag; + int16_t extra; }; struct sectortypedisk { - int16_t wallptr, wallnum; - int32_t ceilingz, floorz; - uint16_t ceilingstat, floorstat; - int16_t ceilingpicnum, ceilingheinum; - int8_t ceilingshade; - uint8_t ceilingpal, ceilingxpanning, ceilingypanning; - int16_t floorpicnum, floorheinum; - int8_t floorshade; - uint8_t floorpal, floorxpanning, floorypanning; - uint8_t visibility, fogpal; - int16_t type; - int16_t hitag; - int16_t extra; + int16_t wallptr, wallnum; + int32_t ceilingz, floorz; + uint16_t ceilingstat, floorstat; + int16_t ceilingpicnum, ceilingheinum; + int8_t ceilingshade; + uint8_t ceilingpal, ceilingxpanning, ceilingypanning; + int16_t floorpicnum, floorheinum; + int8_t floorshade; + uint8_t floorpal, floorxpanning, floorypanning; + uint8_t visibility, fogpal; + int16_t type; + int16_t hitag; + int16_t extra; }; struct walltypedisk { - int32_t x, y; - int16_t point2, nextwall, nextsector; - uint16_t cstat; - int16_t picnum, overpicnum; - int8_t shade; - uint8_t pal, xrepeat, yrepeat, xpanning, ypanning; - int16_t type; - int16_t hitag; - int16_t extra; + int32_t x, y; + int16_t point2, nextwall, nextsector; + uint16_t cstat; + int16_t picnum, overpicnum; + int8_t shade; + uint8_t pal, xrepeat, yrepeat, xpanning, ypanning; + int16_t type; + int16_t hitag; + int16_t extra; }; #pragma pack(pop) BEGIN_BLD_NS -TArray dbLoadMapWalls(const char* pPath); - class DBloodActor; struct AISTATE; struct XSPRITE { - - AISTATE* aiState; // ai - union - { - uint32_t flags; - struct { - unsigned int state : 1; // State 0 - unsigned int triggerOn : 1; // going ON - unsigned int triggerOff : 1; // going OFF - unsigned int restState : 1; // restState - unsigned int Interrutable : 1; // Interruptable - unsigned int Decoupled : 1; // Decoupled - unsigned int triggerOnce : 1; // 1-shot - unsigned int isTriggered : 1; // works in case if triggerOnce selected - unsigned int Push : 1; // Push - unsigned int Vector : 1; // Vector - unsigned int Impact : 1; // Impact - unsigned int Pickup : 1; // Pickup - unsigned int Touch : 1; // Touch - unsigned int Sight : 1; // Sight - unsigned int Proximity : 1; // Proximity - unsigned int lS : 1; // Single - unsigned int lB : 1; // Bloodbath - unsigned int lT : 1; // Launch Team - unsigned int lC : 1; // Coop - unsigned int DudeLockout : 1; // DudeLockout - unsigned int locked : 1; // Locked - unsigned int dudeDeaf : 1; // dudeDeaf - unsigned int dudeAmbush : 1; // dudeAmbush - unsigned int dudeGuard : 1; // dudeGuard - unsigned int dudeFlag4 : 1; // unused - unsigned int wave : 2; // Wave - unsigned int medium : 2; // medium - unsigned int respawn : 2; // Respawn option - unsigned int unused2 : 1; // (new) patrol state - }; - }; - TObjPtr target; // target sprite - TObjPtr burnSource; + AISTATE* aiState; // ai + union + { + uint32_t flags; + struct { + unsigned int state : 1; // State 0 + unsigned int triggerOn : 1; // going ON + unsigned int triggerOff : 1; // going OFF + unsigned int restState : 1; // restState + unsigned int Interrutable : 1; // Interruptable + unsigned int Decoupled : 1; // Decoupled + unsigned int triggerOnce : 1; // 1-shot + unsigned int isTriggered : 1; // works in case if triggerOnce selected + unsigned int Push : 1; // Push + unsigned int Vector : 1; // Vector + unsigned int Impact : 1; // Impact + unsigned int Pickup : 1; // Pickup + unsigned int Touch : 1; // Touch + unsigned int Sight : 1; // Sight + unsigned int Proximity : 1; // Proximity + unsigned int lS : 1; // Single + unsigned int lB : 1; // Bloodbath + unsigned int lT : 1; // Launch Team + unsigned int lC : 1; // Coop + unsigned int DudeLockout : 1; // DudeLockout + unsigned int locked : 1; // Locked + unsigned int dudeDeaf : 1; // dudeDeaf + unsigned int dudeAmbush : 1; // dudeAmbush + unsigned int dudeGuard : 1; // dudeGuard + unsigned int dudeFlag4 : 1; // unused + unsigned int wave : 2; // Wave + unsigned int medium : 2; // medium + unsigned int respawn : 2; // Respawn option + unsigned int unused2 : 1; // (new) patrol state + }; + }; - int32_t targetX; // target x - int32_t targetY; // target y - int32_t targetZ; // target z - int32_t sysData1; // used to keep here various system data, so user can't change it in map editor - int32_t sysData2; // - int32_t scale; // used for scaling SEQ size on sprites - uint32_t physAttr; // currently used by additional physics sprites to keep its attributes. - uint32_t health; - uint32_t busy; + TObjPtr target; // target sprite + TObjPtr burnSource; - int16_t data1; // Data 1 - int16_t data2; // Data 2 - int16_t data3; // Data 3 - uint16_t txID; // TX ID - uint16_t rxID; // RX ID - uint16_t command; // Cmd - uint16_t busyTime; // busyTime - uint16_t waitTime; // waitTime - uint16_t data4; // Data 4 - uint16_t goalAng; // Dude goal ang - uint16_t burnTime; - uint16_t height; - uint16_t stateTimer; // ai timer + int32_t targetX; // target x + int32_t targetY; // target y + int32_t targetZ; // target z + int32_t sysData1; // used to keep here various system data, so user can't change it in map editor + int32_t sysData2; // + int32_t scale; // used for scaling SEQ size on sprites + uint32_t physAttr; // currently used by additional physics sprites to keep its attributes. + uint32_t health; + uint32_t busy; - uint8_t respawnPending; // respawnPending - uint8_t dropMsg; // Drop Item - uint8_t key; // Key - uint8_t lSkill; // Launch 12345 - uint8_t lockMsg; // Lock msg - int8_t dodgeDir; // Dude dodge direction - uint8_t unused1; // modern flags - uint8_t unused3; // something about sight checks - uint8_t unused4; // patrol turn delay + int16_t data1; // Data 1 + int16_t data2; // Data 2 + int16_t data3; // Data 3 + uint16_t txID; // TX ID + uint16_t rxID; // RX ID + uint16_t command; // Cmd + uint16_t busyTime; // busyTime + uint16_t waitTime; // waitTime + uint16_t data4; // Data 4 + uint16_t goalAng; // Dude goal ang + uint16_t burnTime; + uint16_t height; + uint16_t stateTimer; // ai timer + + uint8_t respawnPending; // respawnPending + uint8_t dropMsg; // Drop Item + uint8_t key; // Key + uint8_t lSkill; // Launch 12345 + uint8_t lockMsg; // Lock msg + int8_t dodgeDir; // Dude dodge direction + uint8_t unused1; // modern flags + uint8_t unused3; // something about sight checks + uint8_t unused4; // patrol turn delay }; struct XSECTOR { - - union - { - uint64_t flags; - struct { - unsigned int state : 1; // State - unsigned int triggerOn : 1; // Send at ON - unsigned int triggerOff : 1; // Send at OFF - unsigned int restState : 1; - unsigned int interruptable : 1; // Interruptable - unsigned int reTriggerA : 1; // OFF->ON wait - unsigned int reTriggerB : 1; // ON->OFF wait - unsigned int shadeAlways : 1; // Lighting shadeAlways - unsigned int shadeFloor : 1; // Lighting floor - unsigned int shadeCeiling : 1; // Lighting ceiling - unsigned int shadeWalls : 1; // Lighting walls - unsigned int panAlways : 1; // Pan always - unsigned int panFloor : 1; // Pan floor - unsigned int panCeiling : 1; // Pan ceiling - unsigned int Drag : 1; // Pan drag - unsigned int Underwater : 1; // Underwater - unsigned int decoupled : 1; // Decoupled - unsigned int triggerOnce : 1; // 1-shot - unsigned int isTriggered : 1; - unsigned int Push : 1; // Push - unsigned int Vector : 1; // Vector - unsigned int Reserved : 1; // Reserved - unsigned int Enter : 1; // Enter - unsigned int Exit : 1; // Exit - unsigned int Wallpush : 1; // WallPush - unsigned int color : 1; // Color Lights - unsigned int stopOn : 1; - unsigned int stopOff : 1; - unsigned int Crush : 1; // Crush - unsigned int locked : 1; // Locked - unsigned int windAlways : 1; // Wind always - unsigned int dudeLockout : 1; - unsigned int bobAlways : 1; // Motion always - unsigned int bobFloor : 1; // Motion bob floor - unsigned int bobCeiling : 1; // Motion bob ceiling - unsigned int bobRotate : 1; // Motion rotate - unsigned int unused1 : 1; // (new) pause motion - - }; - }; - DBloodActor* marker0; - DBloodActor* marker1; - DBloodActor* basePath; - DBloodActor* actordata; - - uint32_t busy; - int32_t offCeilZ; - int32_t onCeilZ; - int32_t offFloorZ; - int32_t onFloorZ; - uint32_t windVel; // Wind vel (changed from 10 bit to use higher velocity values) - uint16_t data; // Data - uint16_t txID; // TX ID - uint16_t rxID; // RX ID - uint16_t busyTimeA; // OFF->ON busyTime - uint16_t waitTimeA; // OFF->ON waitTime - uint16_t panAngle; // Motion angle - uint16_t busyTimeB; // ON->OFF busyTime - uint16_t waitTimeB; // ON->OFF waitTime - uint16_t windAng; // Wind ang - uint16_t bobTheta; // Motion Theta - int16_t bobSpeed; // Motion speed + union + { + uint64_t flags; + struct { + unsigned int state : 1; // State + unsigned int triggerOn : 1; // Send at ON + unsigned int triggerOff : 1; // Send at OFF + unsigned int restState : 1; + unsigned int interruptable : 1; // Interruptable + unsigned int reTriggerA : 1; // OFF->ON wait + unsigned int reTriggerB : 1; // ON->OFF wait + unsigned int shadeAlways : 1; // Lighting shadeAlways + unsigned int shadeFloor : 1; // Lighting floor + unsigned int shadeCeiling : 1; // Lighting ceiling + unsigned int shadeWalls : 1; // Lighting walls + unsigned int panAlways : 1; // Pan always + unsigned int panFloor : 1; // Pan floor + unsigned int panCeiling : 1; // Pan ceiling + unsigned int Drag : 1; // Pan drag + unsigned int Underwater : 1; // Underwater + unsigned int decoupled : 1; // Decoupled + unsigned int triggerOnce : 1; // 1-shot + unsigned int isTriggered : 1; + unsigned int Push : 1; // Push + unsigned int Vector : 1; // Vector + unsigned int Reserved : 1; // Reserved + unsigned int Enter : 1; // Enter + unsigned int Exit : 1; // Exit + unsigned int Wallpush : 1; // WallPush + unsigned int color : 1; // Color Lights + unsigned int stopOn : 1; + unsigned int stopOff : 1; + unsigned int Crush : 1; // Crush + unsigned int locked : 1; // Locked + unsigned int windAlways : 1; // Wind always + unsigned int dudeLockout : 1; + unsigned int bobAlways : 1; // Motion always + unsigned int bobFloor : 1; // Motion bob floor + unsigned int bobCeiling : 1; // Motion bob ceiling + unsigned int bobRotate : 1; // Motion rotate + unsigned int unused1 : 1; // (new) pause motion - uint8_t busyWaveA; // OFF->ON wave - uint8_t busyWaveB; // ON->OFF wave - uint8_t command; // Cmd - int8_t amplitude; // Lighting amplitude - uint8_t freq; // Lighting freq - uint8_t phase; // Lighting phase - uint8_t wave; // Lighting wave - int8_t shade; // Lighting value - uint8_t panVel; // Motion speed - uint8_t Depth; // Depth - uint8_t Key; // Key - uint8_t ceilpal; // Ceil pal2 - uint8_t damageType; // DamageType - uint8_t floorpal; // Floor pal2 - uint8_t bobZRange; // Motion Z range + }; + }; + DBloodActor* marker0; + DBloodActor* marker1; + DBloodActor* basePath; + DBloodActor* actordata; + + uint32_t busy; + int32_t offCeilZ; + int32_t onCeilZ; + int32_t offFloorZ; + int32_t onFloorZ; + uint32_t windVel; // Wind vel (changed from 10 bit to use higher velocity values) + + uint16_t data; // Data + uint16_t txID; // TX ID + uint16_t rxID; // RX ID + uint16_t busyTimeA; // OFF->ON busyTime + uint16_t waitTimeA; // OFF->ON waitTime + uint16_t panAngle; // Motion angle + uint16_t busyTimeB; // ON->OFF busyTime + uint16_t waitTimeB; // ON->OFF waitTime + uint16_t windAng; // Wind ang + uint16_t bobTheta; // Motion Theta + int16_t bobSpeed; // Motion speed + + uint8_t busyWaveA; // OFF->ON wave + uint8_t busyWaveB; // ON->OFF wave + uint8_t command; // Cmd + int8_t amplitude; // Lighting amplitude + uint8_t freq; // Lighting freq + uint8_t phase; // Lighting phase + uint8_t wave; // Lighting wave + int8_t shade; // Lighting value + uint8_t panVel; // Motion speed + uint8_t Depth; // Depth + uint8_t Key; // Key + uint8_t ceilpal; // Ceil pal2 + uint8_t damageType; // DamageType + uint8_t floorpal; // Floor pal2 + uint8_t bobZRange; // Motion Z range }; struct XWALL { - - union - { - uint32_t flags; - struct { - unsigned int state : 1; // State - unsigned int triggerOn : 1; // going ON - unsigned int triggerOff : 1; // going OFF - unsigned int restState : 1; // restState - unsigned int interruptable : 1; // Interruptable - unsigned int panAlways : 1; // panAlways - unsigned int decoupled : 1; // Decoupled - unsigned int triggerOnce : 1; // 1-shot - unsigned int isTriggered : 1; - unsigned int triggerPush : 1; // Push - unsigned int triggerVector : 1; // Vector - unsigned int triggerTouch : 1; // by NoOne: renamed from Reserved to Touch as it works with Touch now. - unsigned int locked : 1; // Locked - unsigned int dudeLockout : 1; // DudeLockout - }; - }; - uint32_t busy; - int16_t data; // Data - uint16_t txID; // TX ID - uint16_t rxID; // RX ID - uint16_t busyTime; // busyTime - uint16_t waitTime; // waitTime - - uint8_t command; // Cmd - int8_t panXVel; // panX - int8_t panYVel; // panY - uint8_t key; // Key + union + { + uint32_t flags; + struct { + unsigned int state : 1; // State + unsigned int triggerOn : 1; // going ON + unsigned int triggerOff : 1; // going OFF + unsigned int restState : 1; // restState + unsigned int interruptable : 1; // Interruptable + unsigned int panAlways : 1; // panAlways + unsigned int decoupled : 1; // Decoupled + unsigned int triggerOnce : 1; // 1-shot + unsigned int isTriggered : 1; + unsigned int triggerPush : 1; // Push + unsigned int triggerVector : 1; // Vector + unsigned int triggerTouch : 1; // by NoOne: renamed from Reserved to Touch as it works with Touch now. + unsigned int locked : 1; // Locked + unsigned int dudeLockout : 1; // DudeLockout + }; + }; + uint32_t busy; + + int16_t data; // Data + uint16_t txID; // TX ID + uint16_t rxID; // RX ID + uint16_t busyTime; // busyTime + uint16_t waitTime; // waitTime + + uint8_t command; // Cmd + int8_t panXVel; // panX + int8_t panYVel; // panY + uint8_t key; // Key }; END_BLD_NS \ No newline at end of file diff --git a/source/games/blood/src/messages.cpp b/source/games/blood/src/messages.cpp index d07c4b9a8..5fda4588b 100644 --- a/source/games/blood/src/messages.cpp +++ b/source/games/blood/src/messages.cpp @@ -34,517 +34,559 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. BEGIN_BLD_NS +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void sub_5A928(void) { - for (int i = 0; i < buttonMap.NumButtons(); i++) - buttonMap.ClearButton(i); + for (int i = 0; i < buttonMap.NumButtons(); i++) + buttonMap.ClearButton(i); } -const char *SetGodMode(bool god) +const char* SetGodMode(bool god) { - playerSetGodMode(gMe, god); - bPlayerCheated = true; - return gMe->godMode? GStrings("TXTB_GODMODE") : GStrings("TXTB_NOTGODMODE"); + playerSetGodMode(gMe, god); + bPlayerCheated = true; + return gMe->godMode ? GStrings("TXTB_GODMODE") : GStrings("TXTB_NOTGODMODE"); } -const char *SetClipMode(bool noclip) +const char* SetClipMode(bool noclip) { - gNoClip = noclip; - bPlayerCheated = true; - return gNoClip? GStrings("TXTB_NOCLIP") : GStrings("TXTB_NOCLIPOFF"); + gNoClip = noclip; + bPlayerCheated = true; + return gNoClip ? GStrings("TXTB_NOCLIP") : GStrings("TXTB_NOCLIPOFF"); } -void packStuff(PLAYER *pPlayer) +void packStuff(PLAYER* pPlayer) { - for (int i = 0; i < 5; i++) - packAddItem(pPlayer, i); + for (int i = 0; i < 5; i++) + packAddItem(pPlayer, i); } -void packClear(PLAYER *pPlayer) +void packClear(PLAYER* pPlayer) { - pPlayer->packItemId = 0; - for (int i = 0; i < 5; i++) - { - pPlayer->packSlots[i].isActive = 0; - pPlayer->packSlots[i].curAmount = 0; - } + pPlayer->packItemId = 0; + for (int i = 0; i < 5; i++) + { + pPlayer->packSlots[i].isActive = 0; + pPlayer->packSlots[i].curAmount = 0; + } } void SetAmmo(bool stat) { - if (stat) - { - for (int i = 0; i < 12; i++) - gMe->ammoCount[i] = gAmmoInfo[i].max; - viewSetMessage(GStrings("TXTB_FULLAMMO")); - } - else - { - for (int i = 0; i < 12; i++) - gMe->ammoCount[i] = 0; - viewSetMessage(GStrings("TXTB_NOAMMO")); - } + if (stat) + { + for (int i = 0; i < 12; i++) + gMe->ammoCount[i] = gAmmoInfo[i].max; + viewSetMessage(GStrings("TXTB_FULLAMMO")); + } + else + { + for (int i = 0; i < 12; i++) + gMe->ammoCount[i] = 0; + viewSetMessage(GStrings("TXTB_NOAMMO")); + } } void SetWeapons(bool stat) { - for (int i = 0; i < 14; i++) - { - gMe->hasWeapon[i] = stat; - } - SetAmmo(stat); - if (stat) - viewSetMessage(GStrings("TXTB_ALLWEAP")); - else - { - if (!VanillaMode()) - { - // Keep the pitchfork to avoid freeze - gMe->hasWeapon[1] = 1; - gMe->curWeapon = kWeapNone; - gMe->nextWeapon = kWeapPitchFork; - } - viewSetMessage(GStrings("TXTB_NOWEAP")); - } + for (int i = 0; i < 14; i++) + { + gMe->hasWeapon[i] = stat; + } + SetAmmo(stat); + if (stat) + viewSetMessage(GStrings("TXTB_ALLWEAP")); + else + { + if (!VanillaMode()) + { + // Keep the pitchfork to avoid freeze + gMe->hasWeapon[1] = 1; + gMe->curWeapon = kWeapNone; + gMe->nextWeapon = kWeapPitchFork; + } + viewSetMessage(GStrings("TXTB_NOWEAP")); + } } void SetToys(bool stat) { - if (stat) - { - packStuff(gMe); - viewSetMessage(GStrings("TXTB_FULLINV")); - } - else - { - packClear(gMe); - viewSetMessage(GStrings("TXTB_NOINV")); - } + if (stat) + { + packStuff(gMe); + viewSetMessage(GStrings("TXTB_FULLINV")); + } + else + { + packClear(gMe); + viewSetMessage(GStrings("TXTB_NOINV")); + } } void SetArmor(bool stat) { - int nAmount; - if (stat) - { - viewSetMessage(GStrings("TXTB_FULLARM")); - nAmount = 3200; - } - else - { - viewSetMessage(GStrings("TXTB_NOARM")); - nAmount = 0; - } - for (int i = 0; i < 3; i++) - gMe->armor[i] = nAmount; + int nAmount; + if (stat) + { + viewSetMessage(GStrings("TXTB_FULLARM")); + nAmount = 3200; + } + else + { + viewSetMessage(GStrings("TXTB_NOARM")); + nAmount = 0; + } + for (int i = 0; i < 3; i++) + gMe->armor[i] = nAmount; } void SetKeys(bool stat) { - for (int i = 1; i <= 6; i++) - gMe->hasKey[i] = stat; - if (stat) - viewSetMessage(GStrings("TXTB_ALLKEYS")); - else - viewSetMessage(GStrings("TXTB_NOKEYS")); + for (int i = 1; i <= 6; i++) + gMe->hasKey[i] = stat; + if (stat) + viewSetMessage(GStrings("TXTB_ALLKEYS")); + else + viewSetMessage(GStrings("TXTB_NOKEYS")); } void SetInfiniteAmmo(bool stat) { - gInfiniteAmmo = stat; - if (gInfiniteAmmo) - viewSetMessage(GStrings("TXTB_INFAMMO")); - else - viewSetMessage(GStrings("TXTB_LIMAMMO")); + gInfiniteAmmo = stat; + if (gInfiniteAmmo) + viewSetMessage(GStrings("TXTB_INFAMMO")); + else + viewSetMessage(GStrings("TXTB_LIMAMMO")); } void SetMap(bool stat) { - gFullMap = stat; - if (gFullMap) - viewSetMessage(GStrings("TXTB_ALLMAP")); - else - viewSetMessage(GStrings("TXTB_NOALLMAP")); + gFullMap = stat; + if (gFullMap) + viewSetMessage(GStrings("TXTB_ALLMAP")); + else + viewSetMessage(GStrings("TXTB_NOALLMAP")); } void SetWooMode(bool stat) { - if (stat) - { - if (!powerupCheck(gMe, kPwUpTwoGuns)) - powerupActivate(gMe, kPwUpTwoGuns); - } - else - { - if (powerupCheck(gMe, kPwUpTwoGuns)) - { - if (!VanillaMode()) - gMe->pwUpTime[kPwUpTwoGuns] = 0; - powerupDeactivate(gMe, kPwUpTwoGuns); - } - } + if (stat) + { + if (!powerupCheck(gMe, kPwUpTwoGuns)) + powerupActivate(gMe, kPwUpTwoGuns); + } + else + { + if (powerupCheck(gMe, kPwUpTwoGuns)) + { + if (!VanillaMode()) + gMe->pwUpTime[kPwUpTwoGuns] = 0; + powerupDeactivate(gMe, kPwUpTwoGuns); + } + } } void ToggleWooMode(void) { - SetWooMode(!(powerupCheck(gMe, kPwUpTwoGuns) != 0)); + SetWooMode(!(powerupCheck(gMe, kPwUpTwoGuns) != 0)); } void ToggleBoots(void) { - if (powerupCheck(gMe, kPwUpJumpBoots)) - { - viewSetMessage(GStrings("TXTB_NOJBOOTS")); - if (!VanillaMode()) - { - gMe->pwUpTime[kPwUpJumpBoots] = 0; - gMe->packSlots[4].curAmount = 0; - } - powerupDeactivate(gMe, kPwUpJumpBoots); - } - else - { - viewSetMessage(GStrings("TXTB_JBOOTS")); - if (!VanillaMode()) - gMe->pwUpTime[kPwUpJumpBoots] = gPowerUpInfo[kPwUpJumpBoots].bonusTime; - powerupActivate(gMe, kPwUpJumpBoots); - } + if (powerupCheck(gMe, kPwUpJumpBoots)) + { + viewSetMessage(GStrings("TXTB_NOJBOOTS")); + if (!VanillaMode()) + { + gMe->pwUpTime[kPwUpJumpBoots] = 0; + gMe->packSlots[4].curAmount = 0; + } + powerupDeactivate(gMe, kPwUpJumpBoots); + } + else + { + viewSetMessage(GStrings("TXTB_JBOOTS")); + if (!VanillaMode()) + gMe->pwUpTime[kPwUpJumpBoots] = gPowerUpInfo[kPwUpJumpBoots].bonusTime; + powerupActivate(gMe, kPwUpJumpBoots); + } } void ToggleInvisibility(void) { - if (powerupCheck(gMe, kPwUpShadowCloak)) - { - viewSetMessage(GStrings("TXTB_VISIBLE")); - if (!VanillaMode()) - gMe->pwUpTime[kPwUpShadowCloak] = 0; - powerupDeactivate(gMe, kPwUpShadowCloak); - } - else - { - viewSetMessage(GStrings("TXTB_INVISIBLE")); - powerupActivate(gMe, kPwUpShadowCloak); - } + if (powerupCheck(gMe, kPwUpShadowCloak)) + { + viewSetMessage(GStrings("TXTB_VISIBLE")); + if (!VanillaMode()) + gMe->pwUpTime[kPwUpShadowCloak] = 0; + powerupDeactivate(gMe, kPwUpShadowCloak); + } + else + { + viewSetMessage(GStrings("TXTB_INVISIBLE")); + powerupActivate(gMe, kPwUpShadowCloak); + } } void ToggleInvulnerability(void) { - if (powerupCheck(gMe, kPwUpDeathMask)) - { - viewSetMessage(GStrings("TXTB_VULN")); - if (!VanillaMode()) - gMe->pwUpTime[kPwUpDeathMask] = 0; - powerupDeactivate(gMe, kPwUpDeathMask); - } - else - { - viewSetMessage(GStrings("TXTB_INVULN")); - powerupActivate(gMe, kPwUpDeathMask); - } + if (powerupCheck(gMe, kPwUpDeathMask)) + { + viewSetMessage(GStrings("TXTB_VULN")); + if (!VanillaMode()) + gMe->pwUpTime[kPwUpDeathMask] = 0; + powerupDeactivate(gMe, kPwUpDeathMask); + } + else + { + viewSetMessage(GStrings("TXTB_INVULN")); + powerupActivate(gMe, kPwUpDeathMask); + } } void ToggleDelirium(void) { - if (powerupCheck(gMe, kPwUpDeliriumShroom)) - { - viewSetMessage(GStrings("TXTB_NODELIR")); - if (!VanillaMode()) - gMe->pwUpTime[kPwUpDeliriumShroom] = 0; - powerupDeactivate(gMe, kPwUpDeliriumShroom); - } - else - { - viewSetMessage(GStrings("TXTB_DELIR")); - powerupActivate(gMe, kPwUpDeliriumShroom); - } + if (powerupCheck(gMe, kPwUpDeliriumShroom)) + { + viewSetMessage(GStrings("TXTB_NODELIR")); + if (!VanillaMode()) + gMe->pwUpTime[kPwUpDeliriumShroom] = 0; + powerupDeactivate(gMe, kPwUpDeliriumShroom); + } + else + { + viewSetMessage(GStrings("TXTB_DELIR")); + powerupActivate(gMe, kPwUpDeliriumShroom); + } } bool bPlayerCheated = false; -static int parseArgs(char *pzArgs, int *nArg1, int *nArg2) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +static int parseArgs(char* pzArgs, int* nArg1, int* nArg2) { - if (!nArg1 || !nArg2 || strlen(pzArgs) < 3) - return -1; - *nArg1 = pzArgs[0] - '0'; - int a1 = pzArgs[1] == ' ' ? 0 : pzArgs[1] - '0'; - *nArg2 = a1 * 10 + (pzArgs[2] - '0'); - return 2; + if (!nArg1 || !nArg2 || strlen(pzArgs) < 3) + return -1; + *nArg1 = pzArgs[0] - '0'; + int a1 = pzArgs[1] == ' ' ? 0 : pzArgs[1] - '0'; + *nArg2 = a1 * 10 + (pzArgs[2] - '0'); + return 2; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + const char* GameInterface::GenericCheat(int player, int cheat) { - // message processing is not perfect because many cheats output multiple messages. + // message processing is not perfect because many cheats output multiple messages. - if (gGameOptions.nGameType != 0 || numplayers > 1) // sp only for now. - return nullptr; + if (gGameOptions.nGameType != 0 || numplayers > 1) // sp only for now. + return nullptr; - if (gamestate != GS_LEVEL || gMe->actor->xspr.health == 0) // must be alive and in a level to cheat. - return nullptr; + if (gamestate != GS_LEVEL || gMe->actor->xspr.health == 0) // must be alive and in a level to cheat. + return nullptr; - bPlayerCheated = true; - switch (cheat) - { - case CHT_GOD: - return SetGodMode(!gMe->godMode); + bPlayerCheated = true; + switch (cheat) + { + case CHT_GOD: + return SetGodMode(!gMe->godMode); - case CHT_GODOFF: - return SetGodMode(false); + case CHT_GODOFF: + return SetGodMode(false); - case CHT_GODON: - return SetGodMode(true); + case CHT_GODON: + return SetGodMode(true); - case CHT_NOCLIP: - return SetClipMode(!gNoClip); + case CHT_NOCLIP: + return SetClipMode(!gNoClip); - case kCheatSpielberg: - // demo record - break; - case kCheatSatchel: - SetToys(true); - break; - case kCheatKevorkian: - actDamageSprite(gMe->actor, gMe->actor, kDamageBullet, 8000); - return GStrings("TXTB_KEVORKIAN"); + case kCheatSpielberg: + // demo record + break; + case kCheatSatchel: + SetToys(true); + break; + case kCheatKevorkian: + actDamageSprite(gMe->actor, gMe->actor, kDamageBullet, 8000); + return GStrings("TXTB_KEVORKIAN"); - case kCheatMcGee: - { - if (!gMe->actor->xspr.burnTime) - evPostActor(gMe->actor, 0, kCallbackFXFlameLick); - actBurnSprite(gMe->actor, gMe->actor, 2400); - return GStrings("TXTB_FIRED"); - } - case kCheatEdmark: - actDamageSprite(gMe->actor, gMe->actor, kDamageExplode, 8000); - return GStrings("TXTB_THEDAYS"); + case kCheatMcGee: + { + if (!gMe->actor->xspr.burnTime) + evPostActor(gMe->actor, 0, kCallbackFXFlameLick); + actBurnSprite(gMe->actor, gMe->actor, 2400); + return GStrings("TXTB_FIRED"); + } + case kCheatEdmark: + actDamageSprite(gMe->actor, gMe->actor, kDamageExplode, 8000); + return GStrings("TXTB_THEDAYS"); - case kCheatKrueger: - { - actHealDude(gMe->actor, 200, 200); - gMe->armor[1] = VanillaMode() ? 200 : 3200; - if (!gMe->actor->xspr.burnTime) - evPostActor(gMe->actor, 0, kCallbackFXFlameLick); - actBurnSprite(gMe->actor, gMe->actor, 2400); - return GStrings("TXTB_RETARD"); - } - case kCheatSterno: - gMe->blindEffect = 250; - break; - case kCheat14: // quakeEffect (causing a little flickerEffect), not used by any cheat code (dead code) - gMe->flickerEffect = 360; - break; - case kCheatSpork: - actHealDude(gMe->actor, 200, 200); - break; - case kCheatClarice: - for (int i = 0; i < 3; i++) - gMe->armor[i] = 1600; - return GStrings("TXTB_HALFARMOR"); - case kCheatFrankenstein: - gMe->packSlots[0].curAmount = 100; - break; - case kCheatCheeseHead: - gMe->packSlots[1].curAmount = 100; - if (!VanillaMode()) - gMe->pwUpTime[kPwUpDivingSuit] = gPowerUpInfo[kPwUpDivingSuit].bonusTime; - break; - case kCheatTequila: - ToggleWooMode(); - break; - case kCheatFunkyShoes: - ToggleBoots(); - break; - case kCheatKeyMaster: - SetKeys(true); - break; - case kCheatOneRing: - ToggleInvisibility(); - break; - case kCheatVoorhees: - ToggleInvulnerability(); - break; - case kCheatJoJo: - ToggleDelirium(); - break; - case kCheatLaraCroft: - SetInfiniteAmmo(!gInfiniteAmmo); - SetWeapons(gInfiniteAmmo); - break; - case kCheatHongKong: - SetWeapons(true); - SetInfiniteAmmo(true); - break; - case kCheatMontana: - SetWeapons(true); - SetToys(true); - break; - case kCheatBunz: - SetWeapons(true); - SetWooMode(true); - break; - case kCheatCousteau: - actHealDude(gMe->actor, 200, 200); - gMe->packSlots[1].curAmount = 100; - if (!VanillaMode()) - gMe->pwUpTime[kPwUpDivingSuit] = gPowerUpInfo[kPwUpDivingSuit].bonusTime; - break; - case kCheatForkYou: - SetInfiniteAmmo(false); - SetMap(false); - SetWeapons(false); - SetAmmo(false); - SetArmor(false); - SetToys(false); - SetKeys(false); - SetWooMode(true); - powerupActivate(gMe, kPwUpDeliriumShroom); - gMe->actor->xspr.health = 16; - gMe->hasWeapon[1] = 1; - gMe->curWeapon = kWeapNone; - gMe->nextWeapon = kWeapPitchFork; - break; + case kCheatKrueger: + { + actHealDude(gMe->actor, 200, 200); + gMe->armor[1] = VanillaMode() ? 200 : 3200; + if (!gMe->actor->xspr.burnTime) + evPostActor(gMe->actor, 0, kCallbackFXFlameLick); + actBurnSprite(gMe->actor, gMe->actor, 2400); + return GStrings("TXTB_RETARD"); + } + case kCheatSterno: + gMe->blindEffect = 250; + break; + case kCheat14: // quakeEffect (causing a little flickerEffect), not used by any cheat code (dead code) + gMe->flickerEffect = 360; + break; + case kCheatSpork: + actHealDude(gMe->actor, 200, 200); + break; + case kCheatClarice: + for (int i = 0; i < 3; i++) + gMe->armor[i] = 1600; + return GStrings("TXTB_HALFARMOR"); + case kCheatFrankenstein: + gMe->packSlots[0].curAmount = 100; + break; + case kCheatCheeseHead: + gMe->packSlots[1].curAmount = 100; + if (!VanillaMode()) + gMe->pwUpTime[kPwUpDivingSuit] = gPowerUpInfo[kPwUpDivingSuit].bonusTime; + break; + case kCheatTequila: + ToggleWooMode(); + break; + case kCheatFunkyShoes: + ToggleBoots(); + break; + case kCheatKeyMaster: + SetKeys(true); + break; + case kCheatOneRing: + ToggleInvisibility(); + break; + case kCheatVoorhees: + ToggleInvulnerability(); + break; + case kCheatJoJo: + ToggleDelirium(); + break; + case kCheatLaraCroft: + SetInfiniteAmmo(!gInfiniteAmmo); + SetWeapons(gInfiniteAmmo); + break; + case kCheatHongKong: + SetWeapons(true); + SetInfiniteAmmo(true); + break; + case kCheatMontana: + SetWeapons(true); + SetToys(true); + break; + case kCheatBunz: + SetWeapons(true); + SetWooMode(true); + break; + case kCheatCousteau: + actHealDude(gMe->actor, 200, 200); + gMe->packSlots[1].curAmount = 100; + if (!VanillaMode()) + gMe->pwUpTime[kPwUpDivingSuit] = gPowerUpInfo[kPwUpDivingSuit].bonusTime; + break; + case kCheatForkYou: + SetInfiniteAmmo(false); + SetMap(false); + SetWeapons(false); + SetAmmo(false); + SetArmor(false); + SetToys(false); + SetKeys(false); + SetWooMode(true); + powerupActivate(gMe, kPwUpDeliriumShroom); + gMe->actor->xspr.health = 16; + gMe->hasWeapon[1] = 1; + gMe->curWeapon = kWeapNone; + gMe->nextWeapon = kWeapPitchFork; + break; - default: - return nullptr; - } - return nullptr; + default: + return nullptr; + } + return nullptr; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + static bool cheatGoonies(cheatseq_t*) { - SetMap(!gFullMap); - return true; + SetMap(!gFullMap); + return true; } static bool cheatMario(cheatseq_t* c) { - int nEpisode, nLevel; - if (parseArgs((char*)c->Args, &nEpisode, &nLevel) == 2) + int nEpisode, nLevel; + if (parseArgs((char*)c->Args, &nEpisode, &nLevel) == 2) { auto map = FindMapByIndex(nEpisode, nLevel); if (map) DeferredStartGame(map, g_nextskill); } - return true; + return true; } static bool cheatCalgon(cheatseq_t*) { - levelEndLevel(0); - return true; + levelEndLevel(0); + return true; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + static cheatseq_t s_CheatInfo[] = { - {"MPKFA", nullptr, SendGenericCheat, 0, CHT_GOD }, - {"CAPINMYASS", nullptr, SendGenericCheat, 0, CHT_GODOFF }, - {"NOCAPINMYASS", nullptr, SendGenericCheat, 0, CHT_GODON }, - {"I WANNA BE LIKE KEVIN", nullptr, SendGenericCheat, 0, CHT_GODON }, - {"IDAHO", "give weapons" }, - {"GRISWOLD", "give armor" }, - {"MONTANA", nullptr, SendGenericCheat, 0, kCheatMontana }, // MONTANA (All weapons, full ammo and all items) - {"EDMARK", nullptr, SendGenericCheat, 0, kCheatEdmark }, // EDMARK (Does a lot of fire damage to you (if you have 200HP and 200 fire armor then you can survive). Displays the message "THOSE WERE THE DAYS".) - {"TEQUILA", nullptr, SendGenericCheat, 0, kCheatTequila }, // TEQUILA (Guns akimbo power-up) - {"BUNZ", nullptr, SendGenericCheat, 0, kCheatBunz }, // BUNZ (All weapons, full ammo, and guns akimbo power-up) - {"FUNKY SHOES", nullptr, SendGenericCheat, 0, kCheatFunkyShoes }, // FUNKY SHOES (Gives jump boots item and activates it) - {"GATEKEEPER", nullptr, SendGenericCheat, 0, kCheatGateKeeper }, // GATEKEEPER (Sets the you cheated flag to true, at the end of the level you will see that you have cheated) - {"KEYMASTER", nullptr, SendGenericCheat, 0, kCheatKeyMaster }, // KEYMASTER (All keys) - {"JOJO", nullptr, SendGenericCheat, 0, kCheatJoJo }, // JOJO (Drunk mode (same effect as getting bitten by red spider)) - {"SATCHEL", nullptr, SendGenericCheat, 0, kCheatSatchel }, // SATCHEL (Full inventory) - {"SPORK", nullptr, SendGenericCheat, 0, kCheatSpork }, // SPORK (200% health (same effect as getting life seed)) - {"ONERING", nullptr, SendGenericCheat, 0, kCheatOneRing }, // ONERING (Cloak of invisibility power-up) - {"MARIO###", nullptr, cheatMario }, // MARIO (Warp to level E M, e.g.: MARIO 1 3 will take you to Phantom Express) - {"CALGON", nullptr, cheatCalgon }, // CALGON (Jumps to next level) - {"KEVORKIAN", nullptr, SendGenericCheat, 0, kCheatKevorkian }, // KEVORKIAN (Does a lot of physical damage to you (if you have 200HP and 200 fire armor then you can survive). Displays the message "KEVORKIAN APPROVES".) - {"MCGEE", nullptr, SendGenericCheat, 0, kCheatMcGee }, // MCGEE (Sets you on fire. Displays the message "YOU'RE FIRED".) - {"KRUEGER", nullptr, SendGenericCheat, 0, kCheatKrueger }, // KRUEGER (200% health, but sets you on fire. Displays the message "FLAME RETARDANT".) - {"CHEESEHEAD", nullptr, SendGenericCheat, 0, kCheatCheeseHead }, // CHEESEHEAD (100% diving suit) - {"COUSTEAU", nullptr, SendGenericCheat, 0, kCheatCousteau }, // COUSTEAU (200% health and diving suit) - {"VOORHEES", nullptr, SendGenericCheat, 0, kCheatVoorhees }, // VOORHEES (Death mask power-up) - {"LARA CROFT", nullptr, SendGenericCheat, 0, kCheatLaraCroft }, // LARA CROFT (All weapons and infinite ammo. Displays the message "LARA RULES". Typing it the second time will lose all weapons and ammo.) - {"HONGKONG", nullptr, SendGenericCheat, 0, kCheatHongKong }, // HONGKONG (All weapons and infinite ammo) - {"FRANKENSTEIN", nullptr, SendGenericCheat, 0, kCheatFrankenstein }, // FRANKENSTEIN (100% med-kit) - {"STERNO", nullptr, SendGenericCheat, 0, kCheatSterno }, // STERNO (Temporary blindness (same effect as getting bitten by green spider)) - {"CLARICE", nullptr, SendGenericCheat, 0, kCheatClarice }, // CLARICE (Gives 100% body armor, 100% fire armor, 100% spirit armor) - {"FORK YOU", nullptr, SendGenericCheat, 0, kCheatForkYou }, // FORK YOU (Drunk mode, 1HP, no armor, no weapons, no ammo, no items, no keys, no map, guns akimbo power-up) - {"LIEBERMAN", nullptr, SendGenericCheat, 0, kCheatLieberMan }, // LIEBERMAN (Sets the you cheated flag to true, at the end of the level you will see that you have cheated) - {"EVA GALLI", nullptr, SendGenericCheat, 0, CHT_NOCLIP }, - {"RATE", "toggle r_showfps", nullptr, 1 }, // RATE (Display frame rate (doesn't count as a cheat)) - {"GOONIES", nullptr, cheatGoonies, 0 }, // GOONIES (Enable full map. Displays the message "YOU HAVE THE MAP".) - //{"SPIELBERG", nullptr, doCheatactor->xspr.health == 0) - { - Printf("give: Cannot give while dead or not in a single-player game.\n"); - return; - } + if (numplayers != 1 || gamestate != GS_LEVEL || gMe->actor->xspr.health == 0) + { + Printf("give: Cannot give while dead or not in a single-player game.\n"); + return; + } - switch (type) - { - case GIVE_ALL: - SetWeapons(true); - SetAmmo(true); - SetToys(true); - SetArmor(true); - SetKeys(true); - bPlayerCheated = true; - break; + switch (type) + { + case GIVE_ALL: + SetWeapons(true); + SetAmmo(true); + SetToys(true); + SetArmor(true); + SetKeys(true); + bPlayerCheated = true; + break; - case GIVE_HEALTH: - actHealDude(gMe->actor, 200, 200); - bPlayerCheated = true; - break; + case GIVE_HEALTH: + actHealDude(gMe->actor, 200, 200); + bPlayerCheated = true; + break; - case GIVE_WEAPONS: - SetWeapons(true); - bPlayerCheated = true; - break; + case GIVE_WEAPONS: + SetWeapons(true); + bPlayerCheated = true; + break; - case GIVE_AMMO: - SetAmmo(true); - bPlayerCheated = true; - break; + case GIVE_AMMO: + SetAmmo(true); + bPlayerCheated = true; + break; - case GIVE_ARMOR: - SetArmor(true); - bPlayerCheated = true; - break; + case GIVE_ARMOR: + SetArmor(true); + bPlayerCheated = true; + break; - case GIVE_KEYS: - SetKeys(true); - bPlayerCheated = true; - break; + case GIVE_KEYS: + SetKeys(true); + bPlayerCheated = true; + break; - case GIVE_INVENTORY: - SetToys(true); - bPlayerCheated = true; - break; + case GIVE_INVENTORY: + SetToys(true); + bPlayerCheated = true; + break; - default: - break; - } + default: + break; + } } void InitCheats() { - SetCheats(s_CheatInfo, countof(s_CheatInfo)); - Net_SetCommandHandler(DEM_GIVE, cmd_Give); + SetCheats(s_CheatInfo, countof(s_CheatInfo)); + Net_SetCommandHandler(DEM_GIVE, cmd_Give); } END_BLD_NS diff --git a/source/games/blood/src/messages.h b/source/games/blood/src/messages.h index c032d2c54..0167fe9b2 100644 --- a/source/games/blood/src/messages.h +++ b/source/games/blood/src/messages.h @@ -28,11 +28,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. BEGIN_BLD_NS enum MESSAGE_PRIORITY { - MESSAGE_PRIORITY_PICKUP = -10, - MESSAGE_PRIORITY_NORMAL = 0, - MESSAGE_PRIORITY_SECRET = 10, - MESSAGE_PRIORITY_INI = 20, - MESSAGE_PRIORITY_SYSTEM = 100 + MESSAGE_PRIORITY_PICKUP = -10, + MESSAGE_PRIORITY_NORMAL = 0, + MESSAGE_PRIORITY_SECRET = 10, + MESSAGE_PRIORITY_INI = 20, + MESSAGE_PRIORITY_SYSTEM = 100 }; extern bool bPlayerCheated; diff --git a/source/games/blood/src/mirrors.cpp b/source/games/blood/src/mirrors.cpp index 805f05a62..60186aa86 100644 --- a/source/games/blood/src/mirrors.cpp +++ b/source/games/blood/src/mirrors.cpp @@ -35,120 +35,126 @@ int mirrorcnt, mirrorsector, mirrorwall[4]; MIRROR mirror[16]; // only needed by Polymost. +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void InitMirrors(void) { - r_rortexture = 4080; - r_rortexturerange = 16; + r_rortexture = 4080; + r_rortexturerange = 16; + + mirrorcnt = 0; + tileDelete(504); + portalClear(); - mirrorcnt = 0; - tileDelete(504); - portalClear(); - for (int i = 0; i < 16; i++) { tileDelete(4080 + i); } - for (int i = (int)wall.Size() - 1; i >= 0; i--) - { - auto pWalli = &wall[i]; - if (mirrorcnt == 16) - break; - int nTile = 4080+mirrorcnt; - if (pWalli->overpicnum == 504) - { - if (pWalli->extra > 0 && pWalli->type == kWallStack) - { - pWalli->overpicnum = nTile; + for (int i = (int)wall.Size() - 1; i >= 0; i--) + { + auto pWalli = &wall[i]; + if (mirrorcnt == 16) + break; + int nTile = 4080 + mirrorcnt; + if (pWalli->overpicnum == 504) + { + if (pWalli->extra > 0 && pWalli->type == kWallStack) + { + pWalli->overpicnum = nTile; - mirror[mirrorcnt].wallnum = i; - mirror[mirrorcnt].type = 0; - pWalli->cstat |= CSTAT_WALL_1WAY; - int tmp = pWalli->xw().data; - int j; - for (j = (int)wall.Size() - 1; j >= 0; j--) - { - if (j == i) - continue; - auto pWallj = &wall[j]; - if (pWallj->extra > 0 && pWallj->type == kWallStack) - { - if (tmp != pWallj->xw().data) - continue; - pWalli->hitag = j; // hitag is only used by Polymost, the new renderer uses external links. - pWallj->hitag = i; - mirror[mirrorcnt].link = j; - break; - } - } - if (j < 0) - { - Printf(PRINT_HIGH, "wall[%d] has no matching wall link! (data=%d)\n", i, tmp); - } - else - { - mirrorcnt++; - pWalli->portalflags = PORTAL_WALL_VIEW; - pWalli->portalnum = j; - } - } - continue; - } - if (pWalli->picnum == 504) - { - mirror[mirrorcnt].link = i; - mirror[mirrorcnt].wallnum = i; - pWalli->picnum = nTile; - mirror[mirrorcnt].type = 0; - pWalli->cstat |= CSTAT_WALL_1WAY; - pWalli->portalflags = PORTAL_WALL_MIRROR; - mirrorcnt++; - continue; - } - } - for (int i = (int)sector.Size() - 1; i >= 0; i--) - { - if (mirrorcnt >= 15) - break; + mirror[mirrorcnt].wallnum = i; + mirror[mirrorcnt].type = 0; + pWalli->cstat |= CSTAT_WALL_1WAY; + int tmp = pWalli->xw().data; + int j; + for (j = (int)wall.Size() - 1; j >= 0; j--) + { + if (j == i) + continue; + auto pWallj = &wall[j]; + if (pWallj->extra > 0 && pWallj->type == kWallStack) + { + if (tmp != pWallj->xw().data) + continue; + pWalli->hitag = j; // hitag is only used by Polymost, the new renderer uses external links. + pWallj->hitag = i; + mirror[mirrorcnt].link = j; + break; + } + } + if (j < 0) + { + Printf(PRINT_HIGH, "wall[%d] has no matching wall link! (data=%d)\n", i, tmp); + } + else + { + mirrorcnt++; + pWalli->portalflags = PORTAL_WALL_VIEW; + pWalli->portalnum = j; + } + } + continue; + } + if (pWalli->picnum == 504) + { + mirror[mirrorcnt].link = i; + mirror[mirrorcnt].wallnum = i; + pWalli->picnum = nTile; + mirror[mirrorcnt].type = 0; + pWalli->cstat |= CSTAT_WALL_1WAY; + pWalli->portalflags = PORTAL_WALL_MIRROR; + mirrorcnt++; + continue; + } + } + for (int i = (int)sector.Size() - 1; i >= 0; i--) + { + if (mirrorcnt >= 15) + break; - auto secti = §or[i]; - if (secti->floorpicnum == 504) - { - auto link = barrier_cast(secti->upperLink); - if (link == nullptr) - continue; - auto link2 = link->GetOwner(); - if (link2 == nullptr) - continue; + auto secti = §or[i]; + if (secti->floorpicnum == 504) + { + auto link = barrier_cast(secti->upperLink); + if (link == nullptr) + continue; + auto link2 = link->GetOwner(); + if (link2 == nullptr) + continue; - auto sectj = link2->spr.sector(); - int j = sectnum(sectj); - if (sectj->ceilingpicnum != 504) - I_Error("Lower link sector %d doesn't have mirror picnum\n", j); - mirror[mirrorcnt].type = 2; - mirror[mirrorcnt].dx = link2->spr.pos.X - link->spr.pos.X; - mirror[mirrorcnt].dy = link2->spr.pos.Y - link->spr.pos.Y; - mirror[mirrorcnt].dz = link2->spr.pos.Z - link->spr.pos.Z; - mirror[mirrorcnt].wallnum = i; - mirror[mirrorcnt].link = j; - secti->floorpicnum = 4080 + mirrorcnt; - secti->portalflags = PORTAL_SECTOR_FLOOR; - secti->portalnum = portalAdd(PORTAL_SECTOR_FLOOR, j, mirror[mirrorcnt].dx, mirror[mirrorcnt].dy, mirror[mirrorcnt].dz); - mirrorcnt++; - mirror[mirrorcnt].type = 1; - mirror[mirrorcnt].dx = link->spr.pos.X - link2->spr.pos.X; - mirror[mirrorcnt].dy = link->spr.pos.Y - link2->spr.pos.Y; - mirror[mirrorcnt].dz = link->spr.pos.Z - link2->spr.pos.Z; - mirror[mirrorcnt].wallnum = j; - mirror[mirrorcnt].link = i; - sectj->ceilingpicnum = 4080 + mirrorcnt; - sectj->portalflags = PORTAL_SECTOR_CEILING; - sectj->portalnum = portalAdd(PORTAL_SECTOR_CEILING, i, mirror[mirrorcnt].dx, mirror[mirrorcnt].dy, mirror[mirrorcnt].dz); - mirrorcnt++; - } - } - mirrorsector = sector.Size(); - mergePortals(); - InitPolymostMirrorHack(); + auto sectj = link2->spr.sector(); + int j = sectnum(sectj); + if (sectj->ceilingpicnum != 504) + I_Error("Lower link sector %d doesn't have mirror picnum\n", j); + mirror[mirrorcnt].type = 2; + mirror[mirrorcnt].dx = link2->spr.pos.X - link->spr.pos.X; + mirror[mirrorcnt].dy = link2->spr.pos.Y - link->spr.pos.Y; + mirror[mirrorcnt].dz = link2->spr.pos.Z - link->spr.pos.Z; + mirror[mirrorcnt].wallnum = i; + mirror[mirrorcnt].link = j; + secti->floorpicnum = 4080 + mirrorcnt; + secti->portalflags = PORTAL_SECTOR_FLOOR; + secti->portalnum = portalAdd(PORTAL_SECTOR_FLOOR, j, mirror[mirrorcnt].dx, mirror[mirrorcnt].dy, mirror[mirrorcnt].dz); + mirrorcnt++; + mirror[mirrorcnt].type = 1; + mirror[mirrorcnt].dx = link->spr.pos.X - link2->spr.pos.X; + mirror[mirrorcnt].dy = link->spr.pos.Y - link2->spr.pos.Y; + mirror[mirrorcnt].dz = link->spr.pos.Z - link2->spr.pos.Z; + mirror[mirrorcnt].wallnum = j; + mirror[mirrorcnt].link = i; + sectj->ceilingpicnum = 4080 + mirrorcnt; + sectj->portalflags = PORTAL_SECTOR_CEILING; + sectj->portalnum = portalAdd(PORTAL_SECTOR_CEILING, i, mirror[mirrorcnt].dx, mirror[mirrorcnt].dy, mirror[mirrorcnt].dz); + mirrorcnt++; + } + } + mirrorsector = sector.Size(); + mergePortals(); + InitPolymostMirrorHack(); } //--------------------------------------------------------------------------- @@ -161,7 +167,7 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, MIRROR& w, MIRROR* { if (arc.BeginObject(keyname)) { - arc ("type", w.type) + arc("type", w.type) ("link", w.link) ("dx", w.dx) ("dy", w.dy) @@ -172,12 +178,18 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, MIRROR& w, MIRROR* return arc; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void SerializeMirrors(FSerializer& arc) { if (arc.BeginObject("mirror")) { - arc("mirrorcnt", mirrorcnt) - .Array("mirror", mirror, countof(mirror)) + arc("mirrorcnt", mirrorcnt) + .Array("mirror", mirror, countof(mirror)) .EndObject(); } @@ -193,8 +205,8 @@ void SerializeMirrors(FSerializer& arc) { tileDelete(4080 + i); } - InitPolymostMirrorHack(); - } + InitPolymostMirrorHack(); + } } END_BLD_NS diff --git a/source/games/blood/src/misc.cpp b/source/games/blood/src/misc.cpp index 35e4b58b0..d335d3241 100644 --- a/source/games/blood/src/misc.cpp +++ b/source/games/blood/src/misc.cpp @@ -32,24 +32,24 @@ unsigned int randSeed = 1; unsigned int qrand(void) { - if (randSeed&0x80000000) - randSeed = ((randSeed<<1)^0x20000004)|0x1; - else - randSeed = randSeed<<1; - return randSeed&0x7fff; + if (randSeed & 0x80000000) + randSeed = ((randSeed << 1) ^ 0x20000004) | 0x1; + else + randSeed = randSeed << 1; + return randSeed & 0x7fff; } int wRandSeed = 1; int wrand(void) { - wRandSeed = (wRandSeed*1103515245)+12345; - return FixedToInt(wRandSeed)&0x7fff; + wRandSeed = (wRandSeed * 1103515245) + 12345; + return FixedToInt(wRandSeed) & 0x7fff; } void wsrand(int seed) { - wRandSeed = seed; + wRandSeed = seed; } diff --git a/source/games/blood/src/misc.h b/source/games/blood/src/misc.h index acced0fc8..2c0ff03c2 100644 --- a/source/games/blood/src/misc.h +++ b/source/games/blood/src/misc.h @@ -37,7 +37,7 @@ int wrand(void); void wsrand(int); void FireInit(void); void FireProcess(void); -void UpdateNetworkMenus(void); +void UpdateNetworkMenus(void); void InitMirrors(void); void setPortalFlags(int mode); void processSpritesOnOtherSideOfPortal(int x, int y, int interpolation); @@ -46,61 +46,61 @@ int qanimateoffs(int a1, int a2); struct PLAYER; -bool checkFired6or7(PLAYER *pPlayer); +bool checkFired6or7(PLAYER* pPlayer); void WeaponInit(void); -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); -void WeaponProcess(PLAYER *pPlayer); +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); +void WeaponProcess(PLAYER* pPlayer); void WeaponUpdateState(PLAYER* pPlayer); -void teslaHit(DBloodActor *pMissile, int a2); +void teslaHit(DBloodActor* pMissile, int a2); void WeaponPrecache(); struct ZONE { - int x, y, z; + int x, y, z; sectortype* sector; short ang; }; extern ZONE gStartZone[8]; void warpInit(TArray& actors); -int CheckLink(DBloodActor *pSprite); -int CheckLink(int *x, int *y, int *z, sectortype** pSector); +int CheckLink(DBloodActor* pSprite); +int CheckLink(int* x, int* y, int* z, sectortype** pSector); int GetOctant(int x, int y); -void RotateVector(int *dx, int *dy, int nAngle); -void RotatePoint(int *x, int *y, int nAngle, int ox, int oy); +void RotateVector(int* dx, int* dy, int nAngle); +void RotatePoint(int* x, int* y, int nAngle, int ox, int oy); #include "m_fixed.h" inline int Sin(int ang) { - return sintable[ang & 2047]; + return sintable[ang & 2047]; } inline int Cos(int ang) { - return sintable[(ang + 512) & 2047]; + return sintable[(ang + 512) & 2047]; } enum SurfaceType { - kSurfNone = 0, - kSurfStone, - kSurfMetal, - kSurfWood, - kSurfFlesh, - kSurfWater, - kSurfDirt, - kSurfClay, - kSurfSnow, - kSurfIce, - kSurfLeaves, - kSurfCloth, - kSurfPlant, - kSurfGoo, - kSurfLava, - kSurfMax + kSurfNone = 0, + kSurfStone, + kSurfMetal, + kSurfWood, + kSurfFlesh, + kSurfWater, + kSurfDirt, + kSurfClay, + kSurfSnow, + kSurfIce, + kSurfLeaves, + kSurfCloth, + kSurfPlant, + kSurfGoo, + kSurfLava, + kSurfMax }; extern uint8_t surfType[MAXTILES]; diff --git a/source/games/blood/src/nnexts.cpp b/source/games/blood/src/nnexts.cpp index 99b020df8..a01bbe3fd 100644 --- a/source/games/blood/src/nnexts.cpp +++ b/source/games/blood/src/nnexts.cpp @@ -45,14 +45,14 @@ bool gEventRedirectsUsed = false; short gEffectGenCallbacks[] = { - - kCallbackFXFlameLick, - kCallbackFXFlareSpark, - kCallbackFXFlareSparkLite, - kCallbackFXZombieSpurt, - kCallbackFXBloodSpurt, - kCallbackFXArcSpark, - kCallbackFXTeslaAlt, + + kCallbackFXFlameLick, + kCallbackFXFlareSpark, + kCallbackFXFlareSparkLite, + kCallbackFXZombieSpurt, + kCallbackFXBloodSpurt, + kCallbackFXArcSpark, + kCallbackFXTeslaAlt, }; @@ -65,182 +65,182 @@ int gTrackingCondsCount; std::default_random_engine gStdRandom; const VECTORINFO_EXTRA gVectorInfoExtra[] = { - 1207,1207, 1001,1001, 4001,4002, - 431,431, 1002,1002, 359,359, - 521,521, 513,513, 499,499, - 9012,9014, 1101,1101, 1207,1207, - 499,495, 495,496, 9013,499, - 1307,1308, 499,499, 499,499, - 499,499, 499,499, 351,351, - 0,0, 357,499 + 1207,1207, 1001,1001, 4001,4002, + 431,431, 1002,1002, 359,359, + 521,521, 513,513, 499,499, + 9012,9014, 1101,1101, 1207,1207, + 499,495, 495,496, 9013,499, + 1307,1308, 499,499, 499,499, + 499,499, 499,499, 351,351, + 0,0, 357,499 }; const MISSILEINFO_EXTRA gMissileInfoExtra[] = { - 1207, 1207, false, false, false, false, false, true, false, true, - 420, 420, false, true, true, false, false, false, false, true, - 471, 471, false, false, false, false, false, false, true, false, - 421, 421, false, true, false, true, false, false, false, false, - 1309, 351, false, true, false, false, false, false, false, true, - 480, 480, false, true, false, true, false, false, false, false, - 470, 470, false, false, false, false, false, false, true, true, - 489, 490, false, false, false, false, false, true, false, true, - 462, 351, false, true, false, false, false, false, false, true, - 1203, 172, false, false, true, false, false, false, false, true, - 0,0, false, false, true, false, false, false, false, true, - 1457, 249, false, false, false, false, false, true, false, true, - 480, 489, false, true, false, true, false, false, false, false, - 480, 489, false, false, false, true, false, false, false, false, - 480, 489, false, false, false, true, false, false, false, false, - 491, 491, true, true, true, true, true, true, true, true, - 520, 520, false, false, false, false, false, true, false, true, - 520, 520, false, false, false, false, false, true, false, true, + 1207, 1207, false, false, false, false, false, true, false, true, + 420, 420, false, true, true, false, false, false, false, true, + 471, 471, false, false, false, false, false, false, true, false, + 421, 421, false, true, false, true, false, false, false, false, + 1309, 351, false, true, false, false, false, false, false, true, + 480, 480, false, true, false, true, false, false, false, false, + 470, 470, false, false, false, false, false, false, true, true, + 489, 490, false, false, false, false, false, true, false, true, + 462, 351, false, true, false, false, false, false, false, true, + 1203, 172, false, false, true, false, false, false, false, true, + 0,0, false, false, true, false, false, false, false, true, + 1457, 249, false, false, false, false, false, true, false, true, + 480, 489, false, true, false, true, false, false, false, false, + 480, 489, false, false, false, true, false, false, false, false, + 480, 489, false, false, false, true, false, false, false, false, + 491, 491, true, true, true, true, true, true, true, true, + 520, 520, false, false, false, false, false, true, false, true, + 520, 520, false, false, false, false, false, true, false, true, }; const THINGINFO_EXTRA gThingInfoExtra[] = { - true, true, true, false, false, - false, false, false, false, false, - false, false, false, false, false, - true, false, false, true, true, - true, true, false, false, false, - false, false, true, true, true, - true, true, true, true, true, - true, + true, true, true, false, false, + false, false, false, false, false, + false, false, false, false, false, + true, false, false, true, true, + true, true, false, false, false, + false, false, true, true, true, + true, true, true, true, true, + true, }; const DUDEINFO_EXTRA gDudeInfoExtra[] = { - - { false, false, -1, -1, -1, -1, -1, -1 }, // 200 - { false, false, 0, 9, 13, 13, 17, 14 }, // 201 - { false, false, 0, 9, 13, 13, 17, 14 }, // 202 - { false, true, 0, 8, 0, 8, -1, -1 }, // 203 - { false, false, 0, 8, 0, 8, -1, -1 }, // 204 - { false, true, 1, -1, -1, -1, -1, -1 }, // 205 - { true, true, 0, 0, 0, 0, -1, -1 }, // 206 - { true, false, 0, 0, 0, 0, -1, -1 }, // 207 - { true, false, 1, -1, -1, -1, -1, -1 }, // 208 - { true, false, 1, -1, -1, -1, -1, -1 }, // 209 - { true, true, 0, 0, 0, 0, -1, -1 }, // 210 - { false, true, 0, 8, 0, 8, -1, -1 }, // 211 - { false, true, 0, 6, 0, 6, -1, -1 }, // 212 - { false, true, 0, 7, 0, 7, -1, -1 }, // 213 - { false, true, 0, 7, 0, 7, -1, -1 }, // 214 - { false, true, 0, 7, 0, 7, -1, -1 }, // 215 - { false, true, 0, 7, 0, 7, -1, -1 }, // 216 - { false, true, 0, 9, 10, 10, -1, -1 }, // 217 - { false, true, 0, 0, 0, 0, -1, -1 }, // 218 - { true, false, 7, 7, 7, 7, -1, -1 }, // 219 - { false, true, 0, 7, 0, 7, -1, -1 }, // 220 - { false, false, -1, -1, -1, -1, -1, -1 }, // 221 - { false, true, -1, -1, -1, -1, -1, -1 }, // 222 - { false, false, -1, -1, -1, -1, -1, -1 }, // 223 - { false, true, -1, -1, -1, -1, -1, -1 }, // 224 - { false, false, -1, -1, -1, -1, -1, -1 }, // 225 - { false, false, -1, -1, -1, -1, -1, -1 }, // 226 - { false, false, 0, 7, 0, 7, -1, -1 }, // 227 - { false, false, 0, 7, 0, 7, -1, -1 }, // 228 - { false, false, 0, 8, 0, 8, -1, -1 }, // 229 - { false, false, 0, 9, 13, 13, 17, 14 }, // 230 - { false, false, -1, -1, -1, -1, -1, -1 }, // 231 - { false, false, -1, -1, -1, -1, -1, -1 }, // 232 - { false, false, -1, -1, -1, -1, -1, -1 }, // 233 - { false, false, -1, -1, -1, -1, -1, -1 }, // 234 - { false, false, -1, -1, -1, -1, -1, -1 }, // 235 - { false, false, -1, -1, -1, -1, -1, -1 }, // 236 - { false, false, -1, -1, -1, -1, -1, -1 }, // 237 - { false, false, -1, -1, -1, -1, -1, -1 }, // 238 - { false, false, -1, -1, -1, -1, -1, -1 }, // 239 - { false, false, -1, -1, -1, -1, -1, -1 }, // 240 - { false, false, -1, -1, -1, -1, -1, -1 }, // 241 - { false, false, -1, -1, -1, -1, -1, -1 }, // 242 - { false, false, -1, -1, -1, -1, -1, -1 }, // 243 - { false, true, -1, -1, -1, -1, -1, -1 }, // 244 - { false, true, 0, 6, 0, 6, -1, -1 }, // 245 - { false, false, 0, 9, 13, 13, 17, 14 }, // 246 - { false, false, 0, 9, 13, 13, 14, 14 }, // 247 - { false, false, 0, 9, 13, 13, 14, 14 }, // 248 - { false, false, 0, 9, 13, 13, 17, 14 }, // 249 - { false, true, 0, 6, 8, 8, 10, 9 }, // 250 - { false, true, 0, 8, 9, 9, 11, 10 }, // 251 - { false, false, -1, -1, -1, -1, -1, -1 }, // 252 - { false, false, -1, -1, -1, -1, -1, -1 }, // 253 - { false, false, 0, 9, 17, 13, 17, 14 }, // 254 - { false, false, -1, -1, -1, -1, -1, -1 }, // 255 + + { false, false, -1, -1, -1, -1, -1, -1 }, // 200 + { false, false, 0, 9, 13, 13, 17, 14 }, // 201 + { false, false, 0, 9, 13, 13, 17, 14 }, // 202 + { false, true, 0, 8, 0, 8, -1, -1 }, // 203 + { false, false, 0, 8, 0, 8, -1, -1 }, // 204 + { false, true, 1, -1, -1, -1, -1, -1 }, // 205 + { true, true, 0, 0, 0, 0, -1, -1 }, // 206 + { true, false, 0, 0, 0, 0, -1, -1 }, // 207 + { true, false, 1, -1, -1, -1, -1, -1 }, // 208 + { true, false, 1, -1, -1, -1, -1, -1 }, // 209 + { true, true, 0, 0, 0, 0, -1, -1 }, // 210 + { false, true, 0, 8, 0, 8, -1, -1 }, // 211 + { false, true, 0, 6, 0, 6, -1, -1 }, // 212 + { false, true, 0, 7, 0, 7, -1, -1 }, // 213 + { false, true, 0, 7, 0, 7, -1, -1 }, // 214 + { false, true, 0, 7, 0, 7, -1, -1 }, // 215 + { false, true, 0, 7, 0, 7, -1, -1 }, // 216 + { false, true, 0, 9, 10, 10, -1, -1 }, // 217 + { false, true, 0, 0, 0, 0, -1, -1 }, // 218 + { true, false, 7, 7, 7, 7, -1, -1 }, // 219 + { false, true, 0, 7, 0, 7, -1, -1 }, // 220 + { false, false, -1, -1, -1, -1, -1, -1 }, // 221 + { false, true, -1, -1, -1, -1, -1, -1 }, // 222 + { false, false, -1, -1, -1, -1, -1, -1 }, // 223 + { false, true, -1, -1, -1, -1, -1, -1 }, // 224 + { false, false, -1, -1, -1, -1, -1, -1 }, // 225 + { false, false, -1, -1, -1, -1, -1, -1 }, // 226 + { false, false, 0, 7, 0, 7, -1, -1 }, // 227 + { false, false, 0, 7, 0, 7, -1, -1 }, // 228 + { false, false, 0, 8, 0, 8, -1, -1 }, // 229 + { false, false, 0, 9, 13, 13, 17, 14 }, // 230 + { false, false, -1, -1, -1, -1, -1, -1 }, // 231 + { false, false, -1, -1, -1, -1, -1, -1 }, // 232 + { false, false, -1, -1, -1, -1, -1, -1 }, // 233 + { false, false, -1, -1, -1, -1, -1, -1 }, // 234 + { false, false, -1, -1, -1, -1, -1, -1 }, // 235 + { false, false, -1, -1, -1, -1, -1, -1 }, // 236 + { false, false, -1, -1, -1, -1, -1, -1 }, // 237 + { false, false, -1, -1, -1, -1, -1, -1 }, // 238 + { false, false, -1, -1, -1, -1, -1, -1 }, // 239 + { false, false, -1, -1, -1, -1, -1, -1 }, // 240 + { false, false, -1, -1, -1, -1, -1, -1 }, // 241 + { false, false, -1, -1, -1, -1, -1, -1 }, // 242 + { false, false, -1, -1, -1, -1, -1, -1 }, // 243 + { false, true, -1, -1, -1, -1, -1, -1 }, // 244 + { false, true, 0, 6, 0, 6, -1, -1 }, // 245 + { false, false, 0, 9, 13, 13, 17, 14 }, // 246 + { false, false, 0, 9, 13, 13, 14, 14 }, // 247 + { false, false, 0, 9, 13, 13, 14, 14 }, // 248 + { false, false, 0, 9, 13, 13, 17, 14 }, // 249 + { false, true, 0, 6, 8, 8, 10, 9 }, // 250 + { false, true, 0, 8, 9, 9, 11, 10 }, // 251 + { false, false, -1, -1, -1, -1, -1, -1 }, // 252 + { false, false, -1, -1, -1, -1, -1, -1 }, // 253 + { false, false, 0, 9, 17, 13, 17, 14 }, // 254 + { false, false, -1, -1, -1, -1, -1, -1 }, // 255 }; AISTATE genPatrolStates[] = { - //------------------------------------------------------------------------------- + //------------------------------------------------------------------------------- - { kAiStatePatrolWaitL, 0, -1, 0, NULL, NULL, aiPatrolThink, NULL }, - { kAiStatePatrolWaitL, 7, -1, 0, NULL, NULL, aiPatrolThink, NULL }, + { kAiStatePatrolWaitL, 0, -1, 0, NULL, NULL, aiPatrolThink, NULL }, + { kAiStatePatrolWaitL, 7, -1, 0, NULL, NULL, aiPatrolThink, NULL }, - { kAiStatePatrolMoveL, 9, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, - { kAiStatePatrolMoveL, 8, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, - { kAiStatePatrolMoveL, 0, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, - { kAiStatePatrolMoveL, 6, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, - { kAiStatePatrolMoveL, 7, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, + { kAiStatePatrolMoveL, 9, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, + { kAiStatePatrolMoveL, 8, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, + { kAiStatePatrolMoveL, 0, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, + { kAiStatePatrolMoveL, 6, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, + { kAiStatePatrolMoveL, 7, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, - { kAiStatePatrolTurnL, 9, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, - { kAiStatePatrolTurnL, 8, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, - { kAiStatePatrolTurnL, 0, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, - { kAiStatePatrolTurnL, 6, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, - { kAiStatePatrolTurnL, 7, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, + { kAiStatePatrolTurnL, 9, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, + { kAiStatePatrolTurnL, 8, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, + { kAiStatePatrolTurnL, 0, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, + { kAiStatePatrolTurnL, 6, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, + { kAiStatePatrolTurnL, 7, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, - //------------------------------------------------------------------------------- + //------------------------------------------------------------------------------- - { kAiStatePatrolWaitW, 0, -1, 0, NULL, NULL, aiPatrolThink, NULL }, - { kAiStatePatrolWaitW, 10, -1, 0, NULL, NULL, aiPatrolThink, NULL }, - { kAiStatePatrolWaitW, 13, -1, 0, NULL, NULL, aiPatrolThink, NULL }, - { kAiStatePatrolWaitW, 17, -1, 0, NULL, NULL, aiPatrolThink, NULL }, - { kAiStatePatrolWaitW, 8, -1, 0, NULL, NULL, aiPatrolThink, NULL }, - { kAiStatePatrolWaitW, 9, -1, 0, NULL, NULL, aiPatrolThink, NULL }, + { kAiStatePatrolWaitW, 0, -1, 0, NULL, NULL, aiPatrolThink, NULL }, + { kAiStatePatrolWaitW, 10, -1, 0, NULL, NULL, aiPatrolThink, NULL }, + { kAiStatePatrolWaitW, 13, -1, 0, NULL, NULL, aiPatrolThink, NULL }, + { kAiStatePatrolWaitW, 17, -1, 0, NULL, NULL, aiPatrolThink, NULL }, + { kAiStatePatrolWaitW, 8, -1, 0, NULL, NULL, aiPatrolThink, NULL }, + { kAiStatePatrolWaitW, 9, -1, 0, NULL, NULL, aiPatrolThink, NULL }, - { kAiStatePatrolMoveW, 0, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, - { kAiStatePatrolMoveW, 10, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, - { kAiStatePatrolMoveW, 13, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, - { kAiStatePatrolMoveW, 8, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, - { kAiStatePatrolMoveW, 9, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, - { kAiStatePatrolMoveW, 7, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, - { kAiStatePatrolMoveW, 6, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, + { kAiStatePatrolMoveW, 0, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, + { kAiStatePatrolMoveW, 10, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, + { kAiStatePatrolMoveW, 13, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, + { kAiStatePatrolMoveW, 8, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, + { kAiStatePatrolMoveW, 9, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, + { kAiStatePatrolMoveW, 7, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, + { kAiStatePatrolMoveW, 6, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, - { kAiStatePatrolTurnW, 0, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, - { kAiStatePatrolTurnW, 10, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, - { kAiStatePatrolTurnW, 13, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, - { kAiStatePatrolTurnW, 8, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, - { kAiStatePatrolTurnW, 9, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, - { kAiStatePatrolTurnW, 7, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, - { kAiStatePatrolTurnW, 6, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, + { kAiStatePatrolTurnW, 0, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, + { kAiStatePatrolTurnW, 10, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, + { kAiStatePatrolTurnW, 13, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, + { kAiStatePatrolTurnW, 8, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, + { kAiStatePatrolTurnW, 9, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, + { kAiStatePatrolTurnW, 7, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, + { kAiStatePatrolTurnW, 6, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, - //------------------------------------------------------------------------------- + //------------------------------------------------------------------------------- - { kAiStatePatrolWaitC, 17, -1, 0, NULL, NULL, aiPatrolThink, NULL }, - { kAiStatePatrolWaitC, 11, -1, 0, NULL, NULL, aiPatrolThink, NULL }, - { kAiStatePatrolWaitC, 10, -1, 0, NULL, NULL, aiPatrolThink, NULL }, - { kAiStatePatrolWaitC, 14, -1, 0, NULL, NULL, aiPatrolThink, NULL }, + { kAiStatePatrolWaitC, 17, -1, 0, NULL, NULL, aiPatrolThink, NULL }, + { kAiStatePatrolWaitC, 11, -1, 0, NULL, NULL, aiPatrolThink, NULL }, + { kAiStatePatrolWaitC, 10, -1, 0, NULL, NULL, aiPatrolThink, NULL }, + { kAiStatePatrolWaitC, 14, -1, 0, NULL, NULL, aiPatrolThink, NULL }, - { kAiStatePatrolMoveC, 14, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, - { kAiStatePatrolMoveC, 10, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, - { kAiStatePatrolMoveC, 9, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, + { kAiStatePatrolMoveC, 14, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, + { kAiStatePatrolMoveC, 10, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, + { kAiStatePatrolMoveC, 9, -1, 0, NULL, aiPatrolMove, aiPatrolThink, NULL }, - { kAiStatePatrolTurnC, 14, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, - { kAiStatePatrolTurnC, 10, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, - { kAiStatePatrolTurnC, 9, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, + { kAiStatePatrolTurnC, 14, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, + { kAiStatePatrolTurnC, 10, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, + { kAiStatePatrolTurnC, 9, -1, 0, aiPatrolRandGoalAng, aiPatrolTurn, aiPatrolThink, NULL }, - //------------------------------------------------------------------------------- + //------------------------------------------------------------------------------- }; CONDITION_TYPE_NAMES gCondTypeNames[7] = { - - {kCondGameBase, kCondGameMax, "Game"}, - {kCondMixedBase, kCondMixedMax, "Mixed"}, - {kCondWallBase, kCondWallMax, "Wall"}, - {kCondSectorBase, kCondSectorMax, "Sector"}, - {kCondPlayerBase, kCondPlayerMax, "Player"}, - {kCondDudeBase, kCondDudeMax, "Enemy"}, - {kCondSpriteBase, kCondSpriteMax, "Sprite"}, + + {kCondGameBase, kCondGameMax, "Game"}, + {kCondMixedBase, kCondMixedMax, "Mixed"}, + {kCondWallBase, kCondWallMax, "Wall"}, + {kCondSectorBase, kCondSectorMax, "Sector"}, + {kCondPlayerBase, kCondPlayerMax, "Player"}, + {kCondDudeBase, kCondDudeMax, "Enemy"}, + {kCondSpriteBase, kCondSpriteMax, "Sprite"}, }; @@ -255,78 +255,78 @@ CONDITION_TYPE_NAMES gCondTypeNames[7] = { static DBloodActor* nnExtSpawnDude(DBloodActor* sourceactor, DBloodActor* origin, int nType, int a3, int a4) { - DBloodActor* pDudeActor = nullptr; + DBloodActor* pDudeActor = nullptr; - if (nType < kDudeBase || nType >= kDudeMax || (pDudeActor = actSpawnSprite(origin, kStatDude)) == NULL) - return NULL; + if (nType < kDudeBase || nType >= kDudeMax || (pDudeActor = actSpawnSprite(origin, kStatDude)) == NULL) + return NULL; - int angle = origin->spr.ang; - int x, y, z = a4 + origin->spr.pos.Z; - if (a3 < 0) - { - x = origin->spr.pos.X; - y = origin->spr.pos.Y; - } - else - { - x = origin->spr.pos.X + mulscale30r(Cos(angle), a3); - y = origin->spr.pos.Y + mulscale30r(Sin(angle), a3); - } + int angle = origin->spr.ang; + int x, y, z = a4 + origin->spr.pos.Z; + if (a3 < 0) + { + x = origin->spr.pos.X; + y = origin->spr.pos.Y; + } + else + { + x = origin->spr.pos.X + mulscale30r(Cos(angle), a3); + y = origin->spr.pos.Y + mulscale30r(Sin(angle), a3); + } - vec3_t pos = { x, y, z }; - SetActor(pDudeActor, &pos); + vec3_t pos = { x, y, z }; + SetActor(pDudeActor, &pos); - pDudeActor->spr.type = nType; - pDudeActor->spr.ang = angle; + pDudeActor->spr.type = nType; + pDudeActor->spr.ang = angle; - pDudeActor->spr.cstat |= CSTAT_SPRITE_BLOOD_BIT1 | CSTAT_SPRITE_BLOCK_ALL; - pDudeActor->spr.clipdist = getDudeInfo(nType)->clipdist; + pDudeActor->spr.cstat |= CSTAT_SPRITE_BLOOD_BIT1 | CSTAT_SPRITE_BLOCK_ALL; + pDudeActor->spr.clipdist = getDudeInfo(nType)->clipdist; - pDudeActor->xspr.respawn = 1; - pDudeActor->xspr.health = getDudeInfo(nType)->startHealth << 4; + pDudeActor->xspr.respawn = 1; + pDudeActor->xspr.health = getDudeInfo(nType)->startHealth << 4; - if (fileSystem.FindResource(getDudeInfo(nType)->seqStartID, "SEQ")) - seqSpawn(getDudeInfo(nType)->seqStartID, pDudeActor, -1); + if (fileSystem.FindResource(getDudeInfo(nType)->seqStartID, "SEQ")) + seqSpawn(getDudeInfo(nType)->seqStartID, pDudeActor, -1); - // add a way to inherit some values of spawner by dude. - if (sourceactor->spr.flags & kModernTypeFlag1) { + // add a way to inherit some values of spawner by dude. + if (sourceactor->spr.flags & kModernTypeFlag1) { - //inherit pal? - if (pDudeActor->spr.pal <= 0) - pDudeActor->spr.pal = sourceactor->spr.pal; + //inherit pal? + if (pDudeActor->spr.pal <= 0) + pDudeActor->spr.pal = sourceactor->spr.pal; - // inherit spawn sprite trigger settings, so designer can count monsters. - pDudeActor->xspr.txID = sourceactor->xspr.txID; - pDudeActor->xspr.command = sourceactor->xspr.command; - pDudeActor->xspr.triggerOn = sourceactor->xspr.triggerOn; - pDudeActor->xspr.triggerOff = sourceactor->xspr.triggerOff; + // inherit spawn sprite trigger settings, so designer can count monsters. + pDudeActor->xspr.txID = sourceactor->xspr.txID; + pDudeActor->xspr.command = sourceactor->xspr.command; + pDudeActor->xspr.triggerOn = sourceactor->xspr.triggerOn; + pDudeActor->xspr.triggerOff = sourceactor->xspr.triggerOff; - // inherit drop items - pDudeActor->xspr.dropMsg = sourceactor->xspr.dropMsg; + // inherit drop items + pDudeActor->xspr.dropMsg = sourceactor->xspr.dropMsg; - // inherit dude flags - pDudeActor->xspr.dudeDeaf = sourceactor->xspr.dudeDeaf; - pDudeActor->xspr.dudeGuard = sourceactor->xspr.dudeGuard; - pDudeActor->xspr.dudeAmbush = sourceactor->xspr.dudeAmbush; - pDudeActor->xspr.dudeFlag4 = sourceactor->xspr.dudeFlag4; - pDudeActor->xspr.unused1 = sourceactor->xspr.unused1; + // inherit dude flags + pDudeActor->xspr.dudeDeaf = sourceactor->xspr.dudeDeaf; + pDudeActor->xspr.dudeGuard = sourceactor->xspr.dudeGuard; + pDudeActor->xspr.dudeAmbush = sourceactor->xspr.dudeAmbush; + pDudeActor->xspr.dudeFlag4 = sourceactor->xspr.dudeFlag4; + pDudeActor->xspr.unused1 = sourceactor->xspr.unused1; - } + } - aiInitSprite(pDudeActor); + aiInitSprite(pDudeActor); - gKillMgr.AddNewKill(1); + gKillMgr.AddNewKill(1); - bool burning = IsBurningDude(pDudeActor); - if (burning) { - pDudeActor->xspr.burnTime = 10; - pDudeActor->SetTarget(nullptr); - } + bool burning = IsBurningDude(pDudeActor); + if (burning) { + pDudeActor->xspr.burnTime = 10; + pDudeActor->SetTarget(nullptr); + } - if ((burning || (sourceactor->spr.flags & kModernTypeFlag3)) && !pDudeActor->xspr.dudeFlag4) - aiActivateDude(pDudeActor); + if ((burning || (sourceactor->spr.flags & kModernTypeFlag3)) && !pDudeActor->xspr.dudeFlag4) + aiActivateDude(pDudeActor); - return pDudeActor; + return pDudeActor; } //--------------------------------------------------------------------------- @@ -335,23 +335,23 @@ static DBloodActor* nnExtSpawnDude(DBloodActor* sourceactor, DBloodActor* origin // //--------------------------------------------------------------------------- -bool nnExtIsImmune(DBloodActor* actor, int dmgType, int minScale) +bool nnExtIsImmune(DBloodActor* actor, int dmgType, int minScale) { - if (dmgType >= kDmgFall && dmgType < kDmgMax && actor->hasX() && actor->xspr.locked != 1) - { - if (actor->spr.type >= kThingBase && actor->spr.type < kThingMax) - { - return (thingInfo[actor->spr.type - kThingBase].dmgControl[dmgType] <= minScale); - } - else if (actor->IsDudeActor()) - { - if (actor->IsPlayerActor()) return (gPlayer[actor->spr.type - kDudePlayer1].damageControl[dmgType]); - else if (actor->spr.type == kDudeModernCustom) return (actor->genDudeExtra.dmgControl[dmgType] <= minScale); - else return (getDudeInfo(actor->spr.type)->damageVal[dmgType] <= minScale); - } - } + if (dmgType >= kDmgFall && dmgType < kDmgMax && actor->hasX() && actor->xspr.locked != 1) + { + if (actor->spr.type >= kThingBase && actor->spr.type < kThingMax) + { + return (thingInfo[actor->spr.type - kThingBase].dmgControl[dmgType] <= minScale); + } + else if (actor->IsDudeActor()) + { + if (actor->IsPlayerActor()) return (gPlayer[actor->spr.type - kDudePlayer1].damageControl[dmgType]); + else if (actor->spr.type == kDudeModernCustom) return (actor->genDudeExtra.dmgControl[dmgType] <= minScale); + else return (getDudeInfo(actor->spr.type)->damageVal[dmgType] <= minScale); + } + } - return true; + return true; } //--------------------------------------------------------------------------- @@ -360,72 +360,72 @@ bool nnExtIsImmune(DBloodActor* actor, int dmgType, int minScale) // //--------------------------------------------------------------------------- -bool nnExtEraseModernStuff(DBloodActor* actor) +bool nnExtEraseModernStuff(DBloodActor* actor) { - bool erased = false; - switch (actor->spr.type) { - // erase all modern types if the map is not extended - case kModernSpriteDamager: - case kModernCustomDudeSpawn: - case kModernRandomTX: - case kModernSequentialTX: - case kModernSeqSpawner: - case kModernObjPropertiesChanger: - case kModernObjPicnumChanger: - case kModernObjSizeChanger: - case kModernDudeTargetChanger: - case kModernSectorFXChanger: - case kModernObjDataChanger: - case kModernObjDataAccumulator: - case kModernEffectSpawner: - case kModernWindGenerator: - case kModernPlayerControl: - case kModernCondition: - case kModernConditionFalse: - case kModernSlopeChanger: - case kModernStealthRegion: - actor->spr.type = kSpriteDecoration; - erased = true; - break; - case kItemModernMapLevel: - case kDudeModernCustom: - case kDudeModernCustomBurning: - case kModernThingTNTProx: - case kModernThingEnemyLifeLeech: - actor->spr.type = kSpriteDecoration; - ChangeActorStat(actor, kStatDecoration); - erased = true; - break; - // also erase some modernized vanilla types which was not active - case kMarkerWarpDest: - if (actor->spr.statnum == kStatMarker) break; - actor->spr.type = kSpriteDecoration; - erased = true; - break; - } + bool erased = false; + switch (actor->spr.type) { + // erase all modern types if the map is not extended + case kModernSpriteDamager: + case kModernCustomDudeSpawn: + case kModernRandomTX: + case kModernSequentialTX: + case kModernSeqSpawner: + case kModernObjPropertiesChanger: + case kModernObjPicnumChanger: + case kModernObjSizeChanger: + case kModernDudeTargetChanger: + case kModernSectorFXChanger: + case kModernObjDataChanger: + case kModernObjDataAccumulator: + case kModernEffectSpawner: + case kModernWindGenerator: + case kModernPlayerControl: + case kModernCondition: + case kModernConditionFalse: + case kModernSlopeChanger: + case kModernStealthRegion: + actor->spr.type = kSpriteDecoration; + erased = true; + break; + case kItemModernMapLevel: + case kDudeModernCustom: + case kDudeModernCustomBurning: + case kModernThingTNTProx: + case kModernThingEnemyLifeLeech: + actor->spr.type = kSpriteDecoration; + ChangeActorStat(actor, kStatDecoration); + erased = true; + break; + // also erase some modernized vanilla types which was not active + case kMarkerWarpDest: + if (actor->spr.statnum == kStatMarker) break; + actor->spr.type = kSpriteDecoration; + erased = true; + break; + } - if (actor->xspr.Sight) - { - actor->xspr.Sight = false; // it does not work in vanilla at all - erased = true; - } + if (actor->xspr.Sight) + { + actor->xspr.Sight = false; // it does not work in vanilla at all + erased = true; + } - if (actor->xspr.Proximity) - { - // proximity works only for things and dudes in vanilla - switch (actor->spr.statnum) - { - case kStatThing: - case kStatDude: - break; - default: - actor->xspr.Proximity = false; - erased = true; - break; - } - } + if (actor->xspr.Proximity) + { + // proximity works only for things and dudes in vanilla + switch (actor->spr.statnum) + { + case kStatThing: + case kStatDude: + break; + default: + actor->xspr.Proximity = false; + erased = true; + break; + } + } - return erased; + return erased; } //--------------------------------------------------------------------------- @@ -436,20 +436,20 @@ bool nnExtEraseModernStuff(DBloodActor* actor) void nnExtTriggerObject(EventObject& eob, int command) { - if (eob.isSector()) - { - trTriggerSector(eob.sector(), command); - } - else if (eob.isWall()) - { - trTriggerWall(eob.wall(), command); - } - else if (eob.isActor()) - { - auto objActor = eob.actor(); - if (!objActor || !objActor->hasX()) return; - trTriggerSprite(objActor, command); - } + if (eob.isSector()) + { + trTriggerSector(eob.sector(), command); + } + else if (eob.isWall()) + { + trTriggerWall(eob.wall(), command); + } + else if (eob.isActor()) + { + auto objActor = eob.actor(); + if (!objActor || !objActor->hasX()) return; + trTriggerSprite(objActor, command); + } } //--------------------------------------------------------------------------- @@ -458,31 +458,31 @@ void nnExtTriggerObject(EventObject& eob, int command) // //--------------------------------------------------------------------------- -void nnExtResetGlobals() +void nnExtResetGlobals() { - gAllowTrueRandom = gEventRedirectsUsed = false; + gAllowTrueRandom = gEventRedirectsUsed = false; - // reset counters - gProxySpritesCount = gSightSpritesCount = gPhysSpritesCount = gImpactSpritesCount = 0; + // reset counters + gProxySpritesCount = gSightSpritesCount = gPhysSpritesCount = gImpactSpritesCount = 0; - // fill arrays with negative values to avoid index 0 situation - memset(gSightSpritesList, 0, sizeof(gSightSpritesList)); - memset(gProxySpritesList, 0, sizeof(gProxySpritesList)); - memset(gPhysSpritesList, 0, sizeof(gPhysSpritesList)); - memset(gImpactSpritesList, 0, sizeof(gImpactSpritesList)); + // fill arrays with negative values to avoid index 0 situation + memset(gSightSpritesList, 0, sizeof(gSightSpritesList)); + memset(gProxySpritesList, 0, sizeof(gProxySpritesList)); + memset(gPhysSpritesList, 0, sizeof(gPhysSpritesList)); + memset(gImpactSpritesList, 0, sizeof(gImpactSpritesList)); - // reset tracking conditions, if any - for (size_t i = 0; i < countof(gCondition); i++) - { - TRCONDITION* pCond = &gCondition[i]; - for (unsigned k = 0; k < kMaxTracedObjects; k++) - { - pCond->obj[k].obj = EventObject(nullptr); - } - pCond->actor = nullptr; - pCond->length = 0; - } - gTrackingCondsCount = 0; + // reset tracking conditions, if any + for (size_t i = 0; i < countof(gCondition); i++) + { + TRCONDITION* pCond = &gCondition[i]; + for (unsigned k = 0; k < kMaxTracedObjects; k++) + { + pCond->obj[k].obj = EventObject(nullptr); + } + pCond->actor = nullptr; + pCond->length = 0; + } + gTrackingCondsCount = 0; } //--------------------------------------------------------------------------- @@ -491,358 +491,358 @@ void nnExtResetGlobals() // //--------------------------------------------------------------------------- -void nnExtInitModernStuff(TArray& actors) +void nnExtInitModernStuff(TArray& actors) { - nnExtResetGlobals(); + nnExtResetGlobals(); - // use true random only for single player mode, otherwise use Blood's default one. - if (gGameOptions.nGameType == 0 && !VanillaMode()) - { - gStdRandom.seed(std::random_device()()); + // use true random only for single player mode, otherwise use Blood's default one. + if (gGameOptions.nGameType == 0 && !VanillaMode()) + { + gStdRandom.seed(std::random_device()()); - // since true random is not working if compiled with old mingw versions, we should - // check if it works in game and if not - switch to using in-game random function. - for (int i = kMaxRandomizeRetries; i >= 0; i--) - { - std::uniform_int_distribution dist_a_b(0, 100); - if (gAllowTrueRandom || i <= 0) break; - else if (dist_a_b(gStdRandom) != 0) - gAllowTrueRandom = true; - } - } - - for (auto actor : actors) - { - if (!actor->exists() || !actor->hasX()) continue; - - switch (actor->spr.type) { - case kModernRandomTX: - case kModernSequentialTX: - if (actor->xspr.command == kCmdLink) gEventRedirectsUsed = true; - break; - case kDudeModernCustom: - case kDudeModernCustomBurning: - getSpriteMassBySize(actor); // create mass cache - break; - case kModernCondition: - case kModernConditionFalse: - if (!actor->xspr.rxID && actor->xspr.data1 > kCondGameMax) condError(actor,"\nThe condition must have RX ID!\nSPRITE #%d", actor->GetIndex()); - else if (!actor->xspr.txID && !actor->spr.flags) - { - Printf(PRINT_HIGH, "The condition must have TX ID or hitag to be set: RX ID %d, SPRITE #%d", actor->xspr.rxID, actor->GetIndex()); - } - break; - } + // since true random is not working if compiled with old mingw versions, we should + // check if it works in game and if not - switch to using in-game random function. + for (int i = kMaxRandomizeRetries; i >= 0; i--) + { + std::uniform_int_distribution dist_a_b(0, 100); + if (gAllowTrueRandom || i <= 0) break; + else if (dist_a_b(gStdRandom) != 0) + gAllowTrueRandom = true; + } + } - // auto set going On and going Off if both are empty - if (actor->xspr.txID && !actor->xspr.triggerOn && !actor->xspr.triggerOff) - actor->xspr.triggerOn = actor->xspr.triggerOff = true; - - // copy custom start health to avoid overwrite by kThingBloodChunks - if (actor->IsDudeActor()) - actor->xspr.sysData2 = actor->xspr.data4; - - // check reserved statnums - if (actor->spr.statnum >= kStatModernBase && actor->spr.statnum < kStatModernMax) - { - bool sysStat = true; - switch (actor->spr.statnum) - { - case kStatModernStealthRegion: - sysStat = (actor->spr.type != kModernStealthRegion); - break; - case kStatModernDudeTargetChanger: - sysStat = (actor->spr.type != kModernDudeTargetChanger); - break; - case kStatModernCondition: - sysStat = (actor->spr.type != kModernCondition && actor->spr.type != kModernConditionFalse); - break; - case kStatModernEventRedirector: - sysStat = (actor->spr.type != kModernRandomTX && actor->spr.type != kModernSequentialTX); - break; - case kStatModernWindGen: - sysStat = (actor->spr.type != kModernWindGenerator); - break; - case kStatModernPlayerLinker: - case kStatModernQavScene: - sysStat = (actor->spr.type != kModernPlayerControl); - break; - } + for (auto actor : actors) + { + if (!actor->exists() || !actor->hasX()) continue; - if (sysStat) - I_Error("Sprite statnum %d on sprite #%d is in a range of reserved (%d - %d)!", actor->spr.statnum, actor->GetIndex(), kStatModernBase, kStatModernMax); - } + switch (actor->spr.type) { + case kModernRandomTX: + case kModernSequentialTX: + if (actor->xspr.command == kCmdLink) gEventRedirectsUsed = true; + break; + case kDudeModernCustom: + case kDudeModernCustomBurning: + getSpriteMassBySize(actor); // create mass cache + break; + case kModernCondition: + case kModernConditionFalse: + if (!actor->xspr.rxID && actor->xspr.data1 > kCondGameMax) condError(actor, "\nThe condition must have RX ID!\nSPRITE #%d", actor->GetIndex()); + else if (!actor->xspr.txID && !actor->spr.flags) + { + Printf(PRINT_HIGH, "The condition must have TX ID or hitag to be set: RX ID %d, SPRITE #%d", actor->xspr.rxID, actor->GetIndex()); + } + break; + } - switch (actor->spr.type) - { - case kModernRandomTX: - case kModernSequentialTX: - if (actor->xspr.command != kCmdLink) break; - // add statnum for faster redirects search - ChangeActorStat(actor, kStatModernEventRedirector); - break; - case kModernWindGenerator: - actor->spr.cstat &= ~CSTAT_SPRITE_BLOCK; - ChangeActorStat(actor, kStatModernWindGen); - break; - case kModernDudeTargetChanger: - case kModernObjDataAccumulator: - case kModernRandom: - case kModernRandom2: - case kModernStealthRegion: - actor->spr.cstat &= ~CSTAT_SPRITE_BLOCK; - actor->spr.cstat |= CSTAT_SPRITE_INVISIBLE; - switch (actor->spr.type) - { - // stealth regions for patrolling enemies - case kModernStealthRegion: - ChangeActorStat(actor, kStatModernStealthRegion); - break; - // add statnum for faster dude searching - case kModernDudeTargetChanger: - ChangeActorStat(actor, kStatModernDudeTargetChanger); - if (actor->xspr.busyTime <= 0) actor->xspr.busyTime = 5; - actor->xspr.command = kCmdLink; - break; - // remove kStatItem status from random item generators - case kModernRandom: - case kModernRandom2: - ChangeActorStat(actor, kStatDecoration); - actor->xspr.sysData1 = actor->xspr.command; // save the command so spawned item can inherit it - actor->xspr.command = kCmdLink; // generator itself can't send commands - break; - } - break; - case kModernThingTNTProx: - actor->xspr.Proximity = true; - break; - case kDudeModernCustom: - { - if (actor->xspr.txID <= 0) break; - int found = 0; - BloodStatIterator it(kStatDude); - while (DBloodActor* iactor = it.Next()) - { - if (iactor->xspr.rxID != actor->xspr.txID) continue; - else if (found) I_Error("\nCustom dude (TX ID %d):\nOnly one incarnation allowed per channel!", actor->xspr.txID); - ChangeActorStat(iactor, kStatInactive); - found++; - } - break; - } - case kDudePodMother: - case kDudeTentacleMother: - actor->xspr.state = 1; - break; - case kModernPlayerControl: - switch (actor->xspr.command) - { - case kCmdLink: - { - if (actor->xspr.data1 < 1 || actor->xspr.data1 > kMaxPlayers) - I_Error("\nPlayer Control (SPRITE #%d):\nPlayer out of a range (data1 = %d)", actor->GetIndex(), actor->xspr.data1); + // auto set going On and going Off if both are empty + if (actor->xspr.txID && !actor->xspr.triggerOn && !actor->xspr.triggerOff) + actor->xspr.triggerOn = actor->xspr.triggerOff = true; - //if (numplayers < actor->xspr.data1) - //I_Error("\nPlayer Control (SPRITE #%d):\n There is no player #%d", actor->GetIndex(), actor->xspr.data1); + // copy custom start health to avoid overwrite by kThingBloodChunks + if (actor->IsDudeActor()) + actor->xspr.sysData2 = actor->xspr.data4; - if (actor->xspr.rxID && actor->xspr.rxID != kChannelLevelStart) - I_Error("\nPlayer Control (SPRITE #%d) with Link command should have no RX ID!", actor->GetIndex()); + // check reserved statnums + if (actor->spr.statnum >= kStatModernBase && actor->spr.statnum < kStatModernMax) + { + bool sysStat = true; + switch (actor->spr.statnum) + { + case kStatModernStealthRegion: + sysStat = (actor->spr.type != kModernStealthRegion); + break; + case kStatModernDudeTargetChanger: + sysStat = (actor->spr.type != kModernDudeTargetChanger); + break; + case kStatModernCondition: + sysStat = (actor->spr.type != kModernCondition && actor->spr.type != kModernConditionFalse); + break; + case kStatModernEventRedirector: + sysStat = (actor->spr.type != kModernRandomTX && actor->spr.type != kModernSequentialTX); + break; + case kStatModernWindGen: + sysStat = (actor->spr.type != kModernWindGenerator); + break; + case kStatModernPlayerLinker: + case kStatModernQavScene: + sysStat = (actor->spr.type != kModernPlayerControl); + break; + } - if (actor->xspr.txID && actor->xspr.txID < kChannelUser) - I_Error("\nPlayer Control (SPRITE #%d):\nTX ID should be in range of %d and %d!", actor->GetIndex(), kChannelUser, kChannelMax); + if (sysStat) + I_Error("Sprite statnum %d on sprite #%d is in a range of reserved (%d - %d)!", actor->spr.statnum, actor->GetIndex(), kStatModernBase, kStatModernMax); + } - // only one linker per player allowed - BloodStatIterator it(kStatModernPlayerLinker); - while (auto iactor = it.Next()) - { - if (actor->xspr.data1 == iactor->xspr.data1) - I_Error("\nPlayer Control (SPRITE #%d):\nPlayer %d already linked with different player control sprite #%d!", actor->GetIndex(), actor->xspr.data1, iactor->GetIndex()); - } - actor->xspr.sysData1 = -1; - actor->spr.cstat &= ~CSTAT_SPRITE_BLOCK; - ChangeActorStat(actor, kStatModernPlayerLinker); - break; - } - case 67: // play qav animation - if (actor->xspr.txID && !actor->xspr.waitTime) actor->xspr.waitTime = 1; - ChangeActorStat(actor, kStatModernQavScene); - break; - } - break; - case kModernCondition: - case kModernConditionFalse: - if (actor->xspr.busyTime > 0) - { - if (actor->xspr.waitTime > 0) - { - actor->xspr.busyTime += ClipHigh(((actor->xspr.waitTime * 120) / 10), 4095); actor->xspr.waitTime = 0; - Printf(PRINT_HIGH, "Summing busyTime and waitTime for tracking condition #%d, RX ID %d. Result = %d ticks", actor->GetIndex(), actor->xspr.rxID, actor->xspr.busyTime); - } - actor->xspr.busy = actor->xspr.busyTime; - } - - if (actor->xspr.waitTime && actor->xspr.command >= kCmdNumberic) - condError(actor, "Delay is not available when using numberic commands (%d - %d)", kCmdNumberic, 255); + switch (actor->spr.type) + { + case kModernRandomTX: + case kModernSequentialTX: + if (actor->xspr.command != kCmdLink) break; + // add statnum for faster redirects search + ChangeActorStat(actor, kStatModernEventRedirector); + break; + case kModernWindGenerator: + actor->spr.cstat &= ~CSTAT_SPRITE_BLOCK; + ChangeActorStat(actor, kStatModernWindGen); + break; + case kModernDudeTargetChanger: + case kModernObjDataAccumulator: + case kModernRandom: + case kModernRandom2: + case kModernStealthRegion: + actor->spr.cstat &= ~CSTAT_SPRITE_BLOCK; + actor->spr.cstat |= CSTAT_SPRITE_INVISIBLE; + switch (actor->spr.type) + { + // stealth regions for patrolling enemies + case kModernStealthRegion: + ChangeActorStat(actor, kStatModernStealthRegion); + break; + // add statnum for faster dude searching + case kModernDudeTargetChanger: + ChangeActorStat(actor, kStatModernDudeTargetChanger); + if (actor->xspr.busyTime <= 0) actor->xspr.busyTime = 5; + actor->xspr.command = kCmdLink; + break; + // remove kStatItem status from random item generators + case kModernRandom: + case kModernRandom2: + ChangeActorStat(actor, kStatDecoration); + actor->xspr.sysData1 = actor->xspr.command; // save the command so spawned item can inherit it + actor->xspr.command = kCmdLink; // generator itself can't send commands + break; + } + break; + case kModernThingTNTProx: + actor->xspr.Proximity = true; + break; + case kDudeModernCustom: + { + if (actor->xspr.txID <= 0) break; + int found = 0; + BloodStatIterator it(kStatDude); + while (DBloodActor* iactor = it.Next()) + { + if (iactor->xspr.rxID != actor->xspr.txID) continue; + else if (found) I_Error("\nCustom dude (TX ID %d):\nOnly one incarnation allowed per channel!", actor->xspr.txID); + ChangeActorStat(iactor, kStatInactive); + found++; + } + break; + } + case kDudePodMother: + case kDudeTentacleMother: + actor->xspr.state = 1; + break; + case kModernPlayerControl: + switch (actor->xspr.command) + { + case kCmdLink: + { + if (actor->xspr.data1 < 1 || actor->xspr.data1 > kMaxPlayers) + I_Error("\nPlayer Control (SPRITE #%d):\nPlayer out of a range (data1 = %d)", actor->GetIndex(), actor->xspr.data1); - actor->xspr.Decoupled = false; // must go through operateSprite always - actor->xspr.Sight = actor->xspr.Impact = actor->xspr.Touch = actor->xspr.triggerOff = false; - actor->xspr.Proximity = actor->xspr.Push = actor->xspr.Vector = actor->xspr.triggerOn = false; - actor->xspr.state = actor->xspr.restState = 0; - - actor->xspr.targetX = actor->xspr.targetY = actor->xspr.targetZ = actor->xspr.sysData2 = -1; - actor->SetTarget(nullptr); - ChangeActorStat(actor, kStatModernCondition); - auto oldStat = actor->spr.cstat; - actor->spr.cstat = CSTAT_SPRITE_ALIGNMENT_SLOPE; - - if (oldStat & CSTAT_SPRITE_BLOCK) - actor->spr.cstat |= CSTAT_SPRITE_BLOCK; - - if (oldStat & CSTAT_SPRITE_MOVE_FORWARD) actor->spr.cstat |= CSTAT_SPRITE_MOVE_FORWARD; - else if (oldStat & CSTAT_SPRITE_MOVE_REVERSE) actor->spr.cstat |= CSTAT_SPRITE_MOVE_REVERSE; + //if (numplayers < actor->xspr.data1) + //I_Error("\nPlayer Control (SPRITE #%d):\n There is no player #%d", actor->GetIndex(), actor->xspr.data1); - actor->spr.cstat |= CSTAT_SPRITE_INVISIBLE; - break; - } + if (actor->xspr.rxID && actor->xspr.rxID != kChannelLevelStart) + I_Error("\nPlayer Control (SPRITE #%d) with Link command should have no RX ID!", actor->GetIndex()); - // the following trigger flags are senseless to have together - if ((actor->xspr.Touch && (actor->xspr.Proximity || actor->xspr.Sight) && actor->xspr.DudeLockout) - || (actor->xspr.Touch && actor->xspr.Proximity && !actor->xspr.Sight)) actor->xspr.Touch = false; + if (actor->xspr.txID && actor->xspr.txID < kChannelUser) + I_Error("\nPlayer Control (SPRITE #%d):\nTX ID should be in range of %d and %d!", actor->GetIndex(), kChannelUser, kChannelMax); - if (actor->xspr.Proximity && actor->xspr.Sight && actor->xspr.DudeLockout) - actor->xspr.Proximity = false; - - // very quick fix for floor sprites with Touch trigger flag if their Z is equals sector floorz / ceilgz - if (actor->spr.insector() && actor->xspr.Touch && (actor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_FLOOR)) { - if (actor->spr.pos.Z == actor->spr.sector()->floorz) actor->spr.pos.Z--; - else if (actor->spr.pos.Z == actor->spr.sector()->ceilingz) actor->spr.pos.Z++; - } + // only one linker per player allowed + BloodStatIterator it(kStatModernPlayerLinker); + while (auto iactor = it.Next()) + { + if (actor->xspr.data1 == iactor->xspr.data1) + I_Error("\nPlayer Control (SPRITE #%d):\nPlayer %d already linked with different player control sprite #%d!", actor->GetIndex(), actor->xspr.data1, iactor->GetIndex()); + } + actor->xspr.sysData1 = -1; + actor->spr.cstat &= ~CSTAT_SPRITE_BLOCK; + ChangeActorStat(actor, kStatModernPlayerLinker); + break; + } + case 67: // play qav animation + if (actor->xspr.txID && !actor->xspr.waitTime) actor->xspr.waitTime = 1; + ChangeActorStat(actor, kStatModernQavScene); + break; + } + break; + case kModernCondition: + case kModernConditionFalse: + if (actor->xspr.busyTime > 0) + { + if (actor->xspr.waitTime > 0) + { + actor->xspr.busyTime += ClipHigh(((actor->xspr.waitTime * 120) / 10), 4095); actor->xspr.waitTime = 0; + Printf(PRINT_HIGH, "Summing busyTime and waitTime for tracking condition #%d, RX ID %d. Result = %d ticks", actor->GetIndex(), actor->xspr.rxID, actor->xspr.busyTime); + } + actor->xspr.busy = actor->xspr.busyTime; + } - // make Proximity flag work not just for dudes and things... - if (actor->xspr.Proximity && gProxySpritesCount < kMaxSuperXSprites) - { - switch (actor->spr.statnum) - { - case kStatFX: case kStatExplosion: case kStatItem: - case kStatPurge: case kStatSpares: case kStatFlare: - case kStatInactive: case kStatFree: case kStatMarker: - case kStatPathMarker: case kStatThing: case kStatDude: - case kStatModernPlayerLinker: - break; - default: - gProxySpritesList[gProxySpritesCount++] = actor; - if (gProxySpritesCount == kMaxSuperXSprites) - I_Error("Max (%d) *additional* Proximity sprites reached!", kMaxSuperXSprites); - break; - } - } + if (actor->xspr.waitTime && actor->xspr.command >= kCmdNumberic) + condError(actor, "Delay is not available when using numberic commands (%d - %d)", kCmdNumberic, 255); - // make Sight, Screen, Aim flags work not just for dudes and things... - if ((actor->xspr.Sight || actor->xspr.unused3) && gSightSpritesCount < kMaxSuperXSprites) - { - switch (actor->spr.statnum) - { - case kStatFX: case kStatExplosion: case kStatItem: - case kStatPurge: case kStatSpares: case kStatFlare: - case kStatInactive: case kStatFree: case kStatMarker: - case kStatPathMarker: case kStatModernPlayerLinker: - break; - default: - gSightSpritesList[gSightSpritesCount++] = actor; - if (gSightSpritesCount == kMaxSuperXSprites) - I_Error("Max (%d) Sight sprites reached!", kMaxSuperXSprites); - break; - } - } + actor->xspr.Decoupled = false; // must go through operateSprite always + actor->xspr.Sight = actor->xspr.Impact = actor->xspr.Touch = actor->xspr.triggerOff = false; + actor->xspr.Proximity = actor->xspr.Push = actor->xspr.Vector = actor->xspr.triggerOn = false; + actor->xspr.state = actor->xspr.restState = 0; - // make Impact flag work for sprites that affected by explosions... - if (actor->xspr.Impact && gImpactSpritesCount < kMaxSuperXSprites) - { - switch (actor->spr.statnum) - { - case kStatFX: case kStatExplosion: case kStatItem: - case kStatPurge: case kStatSpares: case kStatFlare: - case kStatInactive: case kStatFree: case kStatMarker: - case kStatPathMarker: case kStatModernPlayerLinker: - break; - default: - gImpactSpritesList[gImpactSpritesCount++] = actor; - if (gImpactSpritesCount == kMaxSuperXSprites) - I_Error("Max (%d) *additional* Impact sprites reached!", kMaxSuperXSprites); - break; - } - } - } + actor->xspr.targetX = actor->xspr.targetY = actor->xspr.targetZ = actor->xspr.sysData2 = -1; + actor->SetTarget(nullptr); + ChangeActorStat(actor, kStatModernCondition); + auto oldStat = actor->spr.cstat; + actor->spr.cstat = CSTAT_SPRITE_ALIGNMENT_SLOPE; - // collect objects for tracking conditions - BloodStatIterator it2(kStatModernCondition); - while (auto iactor = it2.Next()) - { - if (iactor->xspr.busyTime <= 0 || iactor->xspr.isTriggered) continue; - else if (gTrackingCondsCount >= kMaxTrackingConditions) - I_Error("\nMax (%d) tracking conditions reached!", kMaxTrackingConditions); - - int count = 0; - TRCONDITION* pCond = &gCondition[gTrackingCondsCount]; + if (oldStat & CSTAT_SPRITE_BLOCK) + actor->spr.cstat |= CSTAT_SPRITE_BLOCK; - for (auto iactor2 : actors) - { - if (!iactor->exists() || !iactor2->hasX() || iactor2->xspr.txID != iactor->xspr.rxID || iactor2 == iactor) - continue; + if (oldStat & CSTAT_SPRITE_MOVE_FORWARD) actor->spr.cstat |= CSTAT_SPRITE_MOVE_FORWARD; + else if (oldStat & CSTAT_SPRITE_MOVE_REVERSE) actor->spr.cstat |= CSTAT_SPRITE_MOVE_REVERSE; - switch (iactor2->spr.type) - { - case kSwitchToggle: // exceptions - case kSwitchOneWay: // exceptions - continue; - } + actor->spr.cstat |= CSTAT_SPRITE_INVISIBLE; + break; + } - if (iactor2->spr.type == kModernCondition || iactor2->spr.type == kModernConditionFalse) - condError(iactor, "Tracking condition always must be first in condition sequence!"); + // the following trigger flags are senseless to have together + if ((actor->xspr.Touch && (actor->xspr.Proximity || actor->xspr.Sight) && actor->xspr.DudeLockout) + || (actor->xspr.Touch && actor->xspr.Proximity && !actor->xspr.Sight)) actor->xspr.Touch = false; - if (count >= kMaxTracedObjects) - condError(iactor, "Max(%d) objects to track reached for condition #%d, RXID: %d!"); + if (actor->xspr.Proximity && actor->xspr.Sight && actor->xspr.DudeLockout) + actor->xspr.Proximity = false; - pCond->obj[count].obj = EventObject(iactor2); - pCond->obj[count++].cmd = (uint8_t)iactor2->xspr.command; - } + // very quick fix for floor sprites with Touch trigger flag if their Z is equals sector floorz / ceilgz + if (actor->spr.insector() && actor->xspr.Touch && (actor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_FLOOR)) { + if (actor->spr.pos.Z == actor->spr.sector()->floorz) actor->spr.pos.Z--; + else if (actor->spr.pos.Z == actor->spr.sector()->ceilingz) actor->spr.pos.Z++; + } - for (auto& sect: sector) - { - if (!sect.hasX() || sect.xs().txID != iactor->xspr.rxID) continue; - else if (count >= kMaxTracedObjects) - condError(iactor, "Max(%d) objects to track reached for condition #%d, RXID: %d!"); + // make Proximity flag work not just for dudes and things... + if (actor->xspr.Proximity && gProxySpritesCount < kMaxSuperXSprites) + { + switch (actor->spr.statnum) + { + case kStatFX: case kStatExplosion: case kStatItem: + case kStatPurge: case kStatSpares: case kStatFlare: + case kStatInactive: case kStatFree: case kStatMarker: + case kStatPathMarker: case kStatThing: case kStatDude: + case kStatModernPlayerLinker: + break; + default: + gProxySpritesList[gProxySpritesCount++] = actor; + if (gProxySpritesCount == kMaxSuperXSprites) + I_Error("Max (%d) *additional* Proximity sprites reached!", kMaxSuperXSprites); + break; + } + } - pCond->obj[count].obj = EventObject(§); - pCond->obj[count++].cmd = sect.xs().command; - } + // make Sight, Screen, Aim flags work not just for dudes and things... + if ((actor->xspr.Sight || actor->xspr.unused3) && gSightSpritesCount < kMaxSuperXSprites) + { + switch (actor->spr.statnum) + { + case kStatFX: case kStatExplosion: case kStatItem: + case kStatPurge: case kStatSpares: case kStatFlare: + case kStatInactive: case kStatFree: case kStatMarker: + case kStatPathMarker: case kStatModernPlayerLinker: + break; + default: + gSightSpritesList[gSightSpritesCount++] = actor; + if (gSightSpritesCount == kMaxSuperXSprites) + I_Error("Max (%d) Sight sprites reached!", kMaxSuperXSprites); + break; + } + } - for(auto& wal : wall) - { - if (!wal.hasX() || wal.xw().txID != iactor->xspr.rxID) - continue; + // make Impact flag work for sprites that affected by explosions... + if (actor->xspr.Impact && gImpactSpritesCount < kMaxSuperXSprites) + { + switch (actor->spr.statnum) + { + case kStatFX: case kStatExplosion: case kStatItem: + case kStatPurge: case kStatSpares: case kStatFlare: + case kStatInactive: case kStatFree: case kStatMarker: + case kStatPathMarker: case kStatModernPlayerLinker: + break; + default: + gImpactSpritesList[gImpactSpritesCount++] = actor; + if (gImpactSpritesCount == kMaxSuperXSprites) + I_Error("Max (%d) *additional* Impact sprites reached!", kMaxSuperXSprites); + break; + } + } + } - switch (wal.type) { - case kSwitchToggle: // exceptions - case kSwitchOneWay: // exceptions - continue; - } + // collect objects for tracking conditions + BloodStatIterator it2(kStatModernCondition); + while (auto iactor = it2.Next()) + { + if (iactor->xspr.busyTime <= 0 || iactor->xspr.isTriggered) continue; + else if (gTrackingCondsCount >= kMaxTrackingConditions) + I_Error("\nMax (%d) tracking conditions reached!", kMaxTrackingConditions); - if (count >= kMaxTracedObjects) - condError(iactor, "Max(%d) objects to track reached for condition #%d, RXID: %d!"); - - pCond->obj[count].obj = EventObject(&wal); - pCond->obj[count++].cmd = wal.xw().command; - } + int count = 0; + TRCONDITION* pCond = &gCondition[gTrackingCondsCount]; - if (iactor->xspr.data1 > kCondGameMax && count == 0) - Printf(PRINT_HIGH, "No objects to track found for condition #%d, RXID: %d!", iactor->GetIndex(), iactor->xspr.rxID); + for (auto iactor2 : actors) + { + if (!iactor->exists() || !iactor2->hasX() || iactor2->xspr.txID != iactor->xspr.rxID || iactor2 == iactor) + continue; - pCond->length = count; - pCond->actor = iactor; - gTrackingCondsCount++; + switch (iactor2->spr.type) + { + case kSwitchToggle: // exceptions + case kSwitchOneWay: // exceptions + continue; + } - } + if (iactor2->spr.type == kModernCondition || iactor2->spr.type == kModernConditionFalse) + condError(iactor, "Tracking condition always must be first in condition sequence!"); + + if (count >= kMaxTracedObjects) + condError(iactor, "Max(%d) objects to track reached for condition #%d, RXID: %d!"); + + pCond->obj[count].obj = EventObject(iactor2); + pCond->obj[count++].cmd = (uint8_t)iactor2->xspr.command; + } + + for (auto& sect : sector) + { + if (!sect.hasX() || sect.xs().txID != iactor->xspr.rxID) continue; + else if (count >= kMaxTracedObjects) + condError(iactor, "Max(%d) objects to track reached for condition #%d, RXID: %d!"); + + pCond->obj[count].obj = EventObject(§); + pCond->obj[count++].cmd = sect.xs().command; + } + + for (auto& wal : wall) + { + if (!wal.hasX() || wal.xw().txID != iactor->xspr.rxID) + continue; + + switch (wal.type) { + case kSwitchToggle: // exceptions + case kSwitchOneWay: // exceptions + continue; + } + + if (count >= kMaxTracedObjects) + condError(iactor, "Max(%d) objects to track reached for condition #%d, RXID: %d!"); + + pCond->obj[count].obj = EventObject(&wal); + pCond->obj[count++].cmd = wal.xw().command; + } + + if (iactor->xspr.data1 > kCondGameMax && count == 0) + Printf(PRINT_HIGH, "No objects to track found for condition #%d, RXID: %d!", iactor->GetIndex(), iactor->xspr.rxID); + + pCond->length = count; + pCond->actor = iactor; + gTrackingCondsCount++; + + } } @@ -853,26 +853,26 @@ void nnExtInitModernStuff(TArray& actors) // //--------------------------------------------------------------------------- -int nnExtRandom(int a, int b) +int nnExtRandom(int a, int b) { - if (!gAllowTrueRandom) return Random(((b + 1) - a)) + a; - // used for better randomness in single player - std::uniform_int_distribution dist_a_b(a, b); - return dist_a_b(gStdRandom); + if (!gAllowTrueRandom) return Random(((b + 1) - a)) + a; + // used for better randomness in single player + std::uniform_int_distribution dist_a_b(a, b); + return dist_a_b(gStdRandom); } -static int GetDataVal(DBloodActor* actor, int data) +static int GetDataVal(DBloodActor* actor, int data) { - if (!actor->hasX()) return -1; - - switch (data) { - case 0: return actor->xspr.data1; - case 1: return actor->xspr.data2; - case 2: return actor->xspr.data3; - case 3: return actor->xspr.data4; - } + if (!actor->hasX()) return -1; - return -1; + switch (data) { + case 0: return actor->xspr.data1; + case 1: return actor->xspr.data2; + case 2: return actor->xspr.data3; + case 3: return actor->xspr.data4; + } + + return -1; } //--------------------------------------------------------------------------- @@ -881,48 +881,48 @@ static int GetDataVal(DBloodActor* actor, int data) // //--------------------------------------------------------------------------- -static int randomGetDataValue(DBloodActor* actor, int randType) +static int randomGetDataValue(DBloodActor* actor, int randType) { - if (actor == NULL || !actor->hasX()) return -1; - int random = 0; int bad = 0; int maxRetries = kMaxRandomizeRetries; + if (actor == NULL || !actor->hasX()) return -1; + int random = 0; int bad = 0; int maxRetries = kMaxRandomizeRetries; - int rData[4]; - rData[0] = actor->xspr.data1; rData[2] = actor->xspr.data3; - rData[1] = actor->xspr.data2; rData[3] = actor->xspr.data4; - // randomize only in case if at least 2 data fields fits. - for (int i = 0; i < 4; i++) - { - switch (randType) { - case kRandomizeItem: - if (rData[i] >= kItemWeaponBase && rData[i] < kItemMax) break; - else bad++; - break; - case kRandomizeDude: - if (rData[i] >= kDudeBase && rData[i] < kDudeMax) break; - else bad++; - break; - case kRandomizeTX: - if (rData[i] > kChannelZero && rData[i] < kChannelUserMax) break; - else bad++; - break; - default: - bad++; - break; - } - } + int rData[4]; + rData[0] = actor->xspr.data1; rData[2] = actor->xspr.data3; + rData[1] = actor->xspr.data2; rData[3] = actor->xspr.data4; + // randomize only in case if at least 2 data fields fits. + for (int i = 0; i < 4; i++) + { + switch (randType) { + case kRandomizeItem: + if (rData[i] >= kItemWeaponBase && rData[i] < kItemMax) break; + else bad++; + break; + case kRandomizeDude: + if (rData[i] >= kDudeBase && rData[i] < kDudeMax) break; + else bad++; + break; + case kRandomizeTX: + if (rData[i] > kChannelZero && rData[i] < kChannelUserMax) break; + else bad++; + break; + default: + bad++; + break; + } + } - if (bad < 3) - { - // try randomize few times - while (maxRetries > 0) - { - random = nnExtRandom(0, 3); - if (rData[random] > 0) return rData[random]; - else maxRetries--; - } - } + if (bad < 3) + { + // try randomize few times + while (maxRetries > 0) + { + random = nnExtRandom(0, 3); + if (rData[random] > 0) return rData[random]; + else maxRetries--; + } + } - return -1; + return -1; } //--------------------------------------------------------------------------- @@ -931,41 +931,41 @@ static int randomGetDataValue(DBloodActor* actor, int randType) // //--------------------------------------------------------------------------- -static DBloodActor* randomDropPickupObject(DBloodActor* sourceactor, int prevItem) +static DBloodActor* randomDropPickupObject(DBloodActor* sourceactor, int prevItem) { - DBloodActor* spawned = nullptr; - int selected = -1; - int maxRetries = 9; - if (sourceactor->hasX()) - { - while ((selected = randomGetDataValue(sourceactor, kRandomizeItem)) == prevItem) if (maxRetries-- <= 0) break; - if (selected > 0) - { - spawned = actDropObject(sourceactor, selected); - if (spawned) - { - sourceactor->xspr.dropMsg = uint8_t(spawned->spr.type); // store dropped item type in dropMsg - spawned->spr.pos.X = sourceactor->spr.pos.X; - spawned->spr.pos.Y = sourceactor->spr.pos.Y; - spawned->spr.pos.Z = sourceactor->spr.pos.Z; + DBloodActor* spawned = nullptr; + int selected = -1; + int maxRetries = 9; + if (sourceactor->hasX()) + { + while ((selected = randomGetDataValue(sourceactor, kRandomizeItem)) == prevItem) if (maxRetries-- <= 0) break; + if (selected > 0) + { + spawned = actDropObject(sourceactor, selected); + if (spawned) + { + sourceactor->xspr.dropMsg = uint8_t(spawned->spr.type); // store dropped item type in dropMsg + spawned->spr.pos.X = sourceactor->spr.pos.X; + spawned->spr.pos.Y = sourceactor->spr.pos.Y; + spawned->spr.pos.Z = sourceactor->spr.pos.Z; - if ((sourceactor->spr.flags & kModernTypeFlag1) && (sourceactor->xspr.txID > 0 || (sourceactor->xspr.txID != 3 && sourceactor->xspr.lockMsg > 0))) - { - spawned->addX(); + if ((sourceactor->spr.flags & kModernTypeFlag1) && (sourceactor->xspr.txID > 0 || (sourceactor->xspr.txID != 3 && sourceactor->xspr.lockMsg > 0))) + { + spawned->addX(); - // inherit spawn sprite trigger settings, so designer can send command when item picked up. - spawned->xspr.txID = sourceactor->xspr.txID; - spawned->xspr.command = sourceactor->xspr.sysData1; - spawned->xspr.triggerOn = sourceactor->xspr.triggerOn; - spawned->xspr.triggerOff = sourceactor->xspr.triggerOff; + // inherit spawn sprite trigger settings, so designer can send command when item picked up. + spawned->xspr.txID = sourceactor->xspr.txID; + spawned->xspr.command = sourceactor->xspr.sysData1; + spawned->xspr.triggerOn = sourceactor->xspr.triggerOn; + spawned->xspr.triggerOff = sourceactor->xspr.triggerOff; - spawned->xspr.Pickup = true; + spawned->xspr.Pickup = true; - } - } - } - } - return spawned; + } + } + } + } + return spawned; } //--------------------------------------------------------------------------- @@ -976,12 +976,12 @@ static DBloodActor* randomDropPickupObject(DBloodActor* sourceactor, int prevIte DBloodActor* randomSpawnDude(DBloodActor* sourceactor, DBloodActor* origin, int a3, int a4) { - DBloodActor* spawned = NULL; int selected = -1; - - if ((selected = randomGetDataValue(sourceactor, kRandomizeDude)) > 0) - spawned = nnExtSpawnDude(sourceactor, origin, selected, a3, 0); + DBloodActor* spawned = NULL; int selected = -1; - return spawned; + if ((selected = randomGetDataValue(sourceactor, kRandomizeDude)) > 0) + spawned = nnExtSpawnDude(sourceactor, origin, selected, a3, 0); + + return spawned; } //--------------------------------------------------------------------------- @@ -990,56 +990,56 @@ DBloodActor* randomSpawnDude(DBloodActor* sourceactor, DBloodActor* origin, int // //--------------------------------------------------------------------------- -static void windGenDoVerticalWind(int factor, sectortype* pSector) +static void windGenDoVerticalWind(int factor, sectortype* pSector) { - int val, maxZ = 0, zdiff; bool maxZfound = false; - - // find maxz marker first - BloodSectIterator it(pSector); - while (auto actor = it.Next()) - { - if (actor->spr.type == kMarkerOn && actor->spr.statnum != kStatMarker) - { - maxZ = actor->spr.pos.Z; - maxZfound = true; - break; - } - } + int val, maxZ = 0, zdiff; bool maxZfound = false; - it.Reset(pSector); - while (auto actor = it.Next()) - { - switch (actor->spr.statnum) - { - case kStatFree: - continue; - case kStatFX: - if (actor->zvel) break; - continue; - case kStatThing: - case kStatDude: - if (actor->spr.flags & kPhysGravity) break; - continue; - default: - if (actor->hasX() && actor->xspr.physAttr & kPhysGravity) break; - continue; - } + // find maxz marker first + BloodSectIterator it(pSector); + while (auto actor = it.Next()) + { + if (actor->spr.type == kMarkerOn && actor->spr.statnum != kStatMarker) + { + maxZ = actor->spr.pos.Z; + maxZfound = true; + break; + } + } - if (maxZfound && actor->spr.pos.Z <= maxZ) - { - zdiff = actor->spr.pos.Z - maxZ; - if (actor->zvel < 0) actor->zvel += MulScale(actor->zvel >> 4, zdiff, 16); - continue; + it.Reset(pSector); + while (auto actor = it.Next()) + { + switch (actor->spr.statnum) + { + case kStatFree: + continue; + case kStatFX: + if (actor->zvel) break; + continue; + case kStatThing: + case kStatDude: + if (actor->spr.flags & kPhysGravity) break; + continue; + default: + if (actor->hasX() && actor->xspr.physAttr & kPhysGravity) break; + continue; + } - } + if (maxZfound && actor->spr.pos.Z <= maxZ) + { + zdiff = actor->spr.pos.Z - maxZ; + if (actor->zvel < 0) actor->zvel += MulScale(actor->zvel >> 4, zdiff, 16); + continue; - val = -MulScale(factor * 64, 0x10000, 16); - if (actor->zvel >= 0) actor->zvel += val; - else actor->zvel = val; + } - actor->spr.pos.Z += actor->zvel >> 12; + val = -MulScale(factor * 64, 0x10000, 16); + if (actor->zvel >= 0) actor->zvel += val; + else actor->zvel = val; - } + actor->spr.pos.Z += actor->zvel >> 12; + + } } @@ -1051,308 +1051,308 @@ static void windGenDoVerticalWind(int factor, sectortype* pSector) void nnExtProcessSuperSprites() { - // process tracking conditions - if (gTrackingCondsCount > 0) - { - for (int i = 0; i < gTrackingCondsCount; i++) - { - TRCONDITION const* pCond = &gCondition[i]; - auto aCond = pCond->actor; - if (aCond->xspr.locked || aCond->xspr.isTriggered || ++aCond->xspr.busy < aCond->xspr.busyTime) - continue; + // process tracking conditions + if (gTrackingCondsCount > 0) + { + for (int i = 0; i < gTrackingCondsCount; i++) + { + TRCONDITION const* pCond = &gCondition[i]; + auto aCond = pCond->actor; + if (aCond->xspr.locked || aCond->xspr.isTriggered || ++aCond->xspr.busy < aCond->xspr.busyTime) + continue; - if (aCond->xspr.data1 >= kCondGameBase && aCond->xspr.data1 < kCondGameMax) - { - EVENT evn; - evn.target = EventObject(pCond->actor); - evn.cmd = (int8_t)aCond->xspr.command; - evn.funcID = kCallbackMax; - useCondition(pCond->actor, evn); - } - else if (pCond->length > 0) - { - aCond->xspr.busy = 0; - for (unsigned k = 0; k < pCond->length; k++) - { - EVENT evn; - evn.target = pCond->obj[k].obj; - evn.cmd = pCond->obj[k].cmd; - evn.funcID = kCallbackMax; - useCondition(pCond->actor, evn); - } - } - - } - } - - // process floor oriented kModernWindGenerator to create a vertical wind in the sectors - BloodStatIterator it(kStatModernWindGen); - while (auto windactor = it.Next()) - { + if (aCond->xspr.data1 >= kCondGameBase && aCond->xspr.data1 < kCondGameMax) + { + EVENT evn; + evn.target = EventObject(pCond->actor); + evn.cmd = (int8_t)aCond->xspr.command; + evn.funcID = kCallbackMax; + useCondition(pCond->actor, evn); + } + else if (pCond->length > 0) + { + aCond->xspr.busy = 0; + for (unsigned k = 0; k < pCond->length; k++) + { + EVENT evn; + evn.target = pCond->obj[k].obj; + evn.cmd = pCond->obj[k].cmd; + evn.funcID = kCallbackMax; + useCondition(pCond->actor, evn); + } + } - if (!(windactor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_FLOOR) || windactor->spr.statnum >= kMaxStatus || !windactor->hasX()) - continue; + } + } - if (!windactor->xspr.state || windactor->xspr.locked) - continue; + // process floor oriented kModernWindGenerator to create a vertical wind in the sectors + BloodStatIterator it(kStatModernWindGen); + while (auto windactor = it.Next()) + { - int j, rx; - bool fWindAlways = (windactor->spr.flags & kModernTypeFlag1); + if (!(windactor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_FLOOR) || windactor->spr.statnum >= kMaxStatus || !windactor->hasX()) + continue; - if (windactor->xspr.txID) { + if (!windactor->xspr.state || windactor->xspr.locked) + continue; - rx = windactor->xspr.txID; - for (j = bucketHead[rx]; j < bucketHead[rx + 1]; j++) - { - if (!rxBucket[j].isSector()) continue; - auto pSector = rxBucket[j].sector(); - XSECTOR* pXSector = &pSector->xs(); + int j, rx; + bool fWindAlways = (windactor->spr.flags & kModernTypeFlag1); - if ((!pXSector->locked) && (fWindAlways || pXSector->windAlways || pXSector->busy)) - windGenDoVerticalWind(windactor->xspr.sysData2, pSector); - } + if (windactor->xspr.txID) { - DBloodActor* pXRedir = nullptr; // check redirected TX buckets - while ((pXRedir = evrListRedirectors(OBJ_SPRITE, nullptr, nullptr, windactor, pXRedir, &rx)) != nullptr) - { - for (j = bucketHead[rx]; j < bucketHead[rx + 1]; j++) - { - if (!rxBucket[j].isSector()) continue; - auto pSector = rxBucket[j].sector(); - XSECTOR* pXSector = &pSector->xs(); + rx = windactor->xspr.txID; + for (j = bucketHead[rx]; j < bucketHead[rx + 1]; j++) + { + if (!rxBucket[j].isSector()) continue; + auto pSector = rxBucket[j].sector(); + XSECTOR* pXSector = &pSector->xs(); - if ((!pXSector->locked) && (fWindAlways || pXSector->windAlways || pXSector->busy)) - windGenDoVerticalWind(windactor->xspr.sysData2, pSector); - } - } + if ((!pXSector->locked) && (fWindAlways || pXSector->windAlways || pXSector->busy)) + windGenDoVerticalWind(windactor->xspr.sysData2, pSector); + } - } - else if (windactor->spr.insector()) - { - sectortype* pSect = windactor->spr.sector(); - XSECTOR* pXSector = (pSect->hasX()) ? &pSect->xs() : nullptr; - if ((fWindAlways) || (pXSector && !pXSector->locked && (pXSector->windAlways || pXSector->busy))) - windGenDoVerticalWind(windactor->xspr.sysData2, windactor->spr.sector()); - } - } + DBloodActor* pXRedir = nullptr; // check redirected TX buckets + while ((pXRedir = evrListRedirectors(OBJ_SPRITE, nullptr, nullptr, windactor, pXRedir, &rx)) != nullptr) + { + for (j = bucketHead[rx]; j < bucketHead[rx + 1]; j++) + { + if (!rxBucket[j].isSector()) continue; + auto pSector = rxBucket[j].sector(); + XSECTOR* pXSector = &pSector->xs(); - // process additional proximity sprites - if (gProxySpritesCount > 0) - { - for (int i = 0; i < gProxySpritesCount; i++) - { - DBloodActor* pProx = gProxySpritesList[i]; - if (!pProx || !pProx->hasX()) continue; + if ((!pXSector->locked) && (fWindAlways || pXSector->windAlways || pXSector->busy)) + windGenDoVerticalWind(windactor->xspr.sysData2, pSector); + } + } - if (!pProx->xspr.Proximity || (!pProx->xspr.Interrutable && pProx->xspr.state != pProx->xspr.restState) || pProx->xspr.locked == 1 - || pProx->xspr.isTriggered) continue; // don't process locked or triggered sprites + } + else if (windactor->spr.insector()) + { + sectortype* pSect = windactor->spr.sector(); + XSECTOR* pXSector = (pSect->hasX()) ? &pSect->xs() : nullptr; + if ((fWindAlways) || (pXSector && !pXSector->locked && (pXSector->windAlways || pXSector->busy))) + windGenDoVerticalWind(windactor->xspr.sysData2, windactor->spr.sector()); + } + } - int okDist = (pProx->IsDudeActor()) ? 96 : ClipLow(pProx->spr.clipdist * 3, 32); - int x = pProx->spr.pos.X; - int y = pProx->spr.pos.Y; - int z = pProx->spr.pos.Z; - auto pSect = pProx->spr.sector(); + // process additional proximity sprites + if (gProxySpritesCount > 0) + { + for (int i = 0; i < gProxySpritesCount; i++) + { + DBloodActor* pProx = gProxySpritesList[i]; + if (!pProx || !pProx->hasX()) continue; - if (!pProx->xspr.DudeLockout) - { - BloodStatIterator itr(kStatDude); - while (auto affected = itr.Next()) - { - if (!affected->hasX() || affected->xspr.health <= 0) continue; - else if (CheckProximity(affected, x, y, z, pSect, okDist)) - { - trTriggerSprite(pProx, kCmdSpriteProximity); - break; - } - } - } - else - { - for (int a = connecthead; a >= 0; a = connectpoint2[a]) - { - PLAYER* pPlayer = &gPlayer[a]; - if (!pPlayer || !pPlayer->actor->hasX() || pPlayer->actor->xspr.health <= 0) - continue; + if (!pProx->xspr.Proximity || (!pProx->xspr.Interrutable && pProx->xspr.state != pProx->xspr.restState) || pProx->xspr.locked == 1 + || pProx->xspr.isTriggered) continue; // don't process locked or triggered sprites - if (pPlayer->actor->xspr.health > 0 && CheckProximity(gPlayer->actor, x, y, z, pSect, okDist)) - { - trTriggerSprite(pProx, kCmdSpriteProximity); - break; - } - } - } - } - } + int okDist = (pProx->IsDudeActor()) ? 96 : ClipLow(pProx->spr.clipdist * 3, 32); + int x = pProx->spr.pos.X; + int y = pProx->spr.pos.Y; + int z = pProx->spr.pos.Z; + auto pSect = pProx->spr.sector(); - // process sight sprites (for players only) - if (gSightSpritesCount > 0) - { - for (int i = 0; i < gSightSpritesCount; i++) - { - DBloodActor* pSight = gSightSpritesList[i]; - if (!pSight || !pSight->hasX()) continue; + if (!pProx->xspr.DudeLockout) + { + BloodStatIterator itr(kStatDude); + while (auto affected = itr.Next()) + { + if (!affected->hasX() || affected->xspr.health <= 0) continue; + else if (CheckProximity(affected, x, y, z, pSect, okDist)) + { + trTriggerSprite(pProx, kCmdSpriteProximity); + break; + } + } + } + else + { + for (int a = connecthead; a >= 0; a = connectpoint2[a]) + { + PLAYER* pPlayer = &gPlayer[a]; + if (!pPlayer || !pPlayer->actor->hasX() || pPlayer->actor->xspr.health <= 0) + continue; - if ((!pSight->xspr.Interrutable && pSight->xspr.state != pSight->xspr.restState) || pSight->xspr.locked == 1 || - pSight->xspr.isTriggered) continue; // don't process locked or triggered sprites + if (pPlayer->actor->xspr.health > 0 && CheckProximity(gPlayer->actor, x, y, z, pSect, okDist)) + { + trTriggerSprite(pProx, kCmdSpriteProximity); + break; + } + } + } + } + } - // sprite is drawn for one of players - if ((pSight->xspr.unused3 & kTriggerSpriteScreen) && (pSight->spr.cstat2 & CSTAT2_SPRITE_MAPPED)) - { - trTriggerSprite(pSight, kCmdSpriteSight); - pSight->spr.cstat2 &= ~CSTAT2_SPRITE_MAPPED; - continue; - } + // process sight sprites (for players only) + if (gSightSpritesCount > 0) + { + for (int i = 0; i < gSightSpritesCount; i++) + { + DBloodActor* pSight = gSightSpritesList[i]; + if (!pSight || !pSight->hasX()) continue; - int x = pSight->spr.pos.X; - int y = pSight->spr.pos.Y; - int z = pSight->spr.pos.Z; - auto pSightSect = pSight->spr.sector(); - int ztop2, zbot2; - - for (int a = connecthead; a >= 0; a = connectpoint2[a]) - { - PLAYER* pPlayer = &gPlayer[a]; - if (!pPlayer || !pPlayer->actor->hasX() || pPlayer->actor->xspr.health <= 0) - continue; + if ((!pSight->xspr.Interrutable && pSight->xspr.state != pSight->xspr.restState) || pSight->xspr.locked == 1 || + pSight->xspr.isTriggered) continue; // don't process locked or triggered sprites - auto plActor = pPlayer->actor; - GetActorExtents(plActor, &ztop2, &zbot2); - if (cansee(x, y, z, pSightSect, plActor->spr.pos.X, plActor->spr.pos.Y, ztop2, plActor->spr.sector())) - { - if (pSight->xspr.Sight) - { - trTriggerSprite(pSight, kCmdSpriteSight); - break; - } + // sprite is drawn for one of players + if ((pSight->xspr.unused3 & kTriggerSpriteScreen) && (pSight->spr.cstat2 & CSTAT2_SPRITE_MAPPED)) + { + trTriggerSprite(pSight, kCmdSpriteSight); + pSight->spr.cstat2 &= ~CSTAT2_SPRITE_MAPPED; + continue; + } - if (pSight->xspr.unused3 & kTriggerSpriteAim) - { - bool vector = (pSight->spr.cstat & CSTAT_SPRITE_BLOCK_HITSCAN); - if (!vector) - pSight->spr.cstat |= CSTAT_SPRITE_BLOCK_HITSCAN; + int x = pSight->spr.pos.X; + int y = pSight->spr.pos.Y; + int z = pSight->spr.pos.Z; + auto pSightSect = pSight->spr.sector(); + int ztop2, zbot2; - HitScan(pPlayer->actor, pPlayer->zWeapon, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, CLIPMASK0 | CLIPMASK1, 0); + for (int a = connecthead; a >= 0; a = connectpoint2[a]) + { + PLAYER* pPlayer = &gPlayer[a]; + if (!pPlayer || !pPlayer->actor->hasX() || pPlayer->actor->xspr.health <= 0) + continue; - if (!vector) - pSight->spr.cstat &= ~CSTAT_SPRITE_BLOCK_HITSCAN; + auto plActor = pPlayer->actor; + GetActorExtents(plActor, &ztop2, &zbot2); + if (cansee(x, y, z, pSightSect, plActor->spr.pos.X, plActor->spr.pos.Y, ztop2, plActor->spr.sector())) + { + if (pSight->xspr.Sight) + { + trTriggerSprite(pSight, kCmdSpriteSight); + break; + } - if (gHitInfo.actor() == pSight) - { - trTriggerSprite(gHitInfo.actor(), kCmdSpriteSight); - break; - } - } - } - } - } - } + if (pSight->xspr.unused3 & kTriggerSpriteAim) + { + bool vector = (pSight->spr.cstat & CSTAT_SPRITE_BLOCK_HITSCAN); + if (!vector) + pSight->spr.cstat |= CSTAT_SPRITE_BLOCK_HITSCAN; - // process Debris sprites for movement - if (gPhysSpritesCount > 0) - { - for (int i = 0; i < gPhysSpritesCount; i++) - { - DBloodActor* debrisactor = gPhysSpritesList[i]; - if (debrisactor == nullptr || !debrisactor->hasX()) continue; + HitScan(pPlayer->actor, pPlayer->zWeapon, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, CLIPMASK0 | CLIPMASK1, 0); - if (debrisactor->spr.statnum == kStatFree || (debrisactor->spr.flags & kHitagFree) != 0) - { - gPhysSpritesList[i] = nullptr; - continue; - } + if (!vector) + pSight->spr.cstat &= ~CSTAT_SPRITE_BLOCK_HITSCAN; - if (!(debrisactor->xspr.physAttr & kPhysMove) && !(debrisactor->xspr.physAttr & kPhysGravity)) - { - gPhysSpritesList[i] = nullptr; - continue; - } + if (gHitInfo.actor() == pSight) + { + trTriggerSprite(gHitInfo.actor(), kCmdSpriteSight); + break; + } + } + } + } + } + } - XSECTOR* pXSector = (debrisactor->spr.sector()->hasX()) ? &debrisactor->spr.sector()->xs() : nullptr; - viewBackupSpriteLoc(debrisactor); + // process Debris sprites for movement + if (gPhysSpritesCount > 0) + { + for (int i = 0; i < gPhysSpritesCount; i++) + { + DBloodActor* debrisactor = gPhysSpritesList[i]; + if (debrisactor == nullptr || !debrisactor->hasX()) continue; - bool uwater = false; - int mass = debrisactor->spriteMass.mass; - int airVel = debrisactor->spriteMass.airVel; + if (debrisactor->spr.statnum == kStatFree || (debrisactor->spr.flags & kHitagFree) != 0) + { + gPhysSpritesList[i] = nullptr; + continue; + } - int top, bottom; - GetActorExtents(debrisactor, &top, &bottom); - - if (pXSector != nullptr) - { - if ((uwater = pXSector->Underwater) != 0) airVel <<= 6; - if (pXSector->panVel != 0 && getflorzofslopeptr(debrisactor->spr.sector(), debrisactor->spr.pos.X, debrisactor->spr.pos.Y) <= bottom) - { - int angle = pXSector->panAngle; int speed = 0; - if (pXSector->panAlways || pXSector->state || pXSector->busy) - { - speed = pXSector->panVel << 9; - if (!pXSector->panAlways && pXSector->busy) - speed = MulScale(speed, pXSector->busy, 16); - } - if (debrisactor->spr.sector()->floorstat & CSTAT_SECTOR_ALIGN) - angle = (angle + GetWallAngle(debrisactor->spr.sector()->firstWall()) + 512) & 2047; - int dx = MulScale(speed, Cos(angle), 30); - int dy = MulScale(speed, Sin(angle), 30); - debrisactor->xvel += dx; - debrisactor->yvel += dy; - } - } + if (!(debrisactor->xspr.physAttr & kPhysMove) && !(debrisactor->xspr.physAttr & kPhysGravity)) + { + gPhysSpritesList[i] = nullptr; + continue; + } - actAirDrag(debrisactor, airVel); + XSECTOR* pXSector = (debrisactor->spr.sector()->hasX()) ? &debrisactor->spr.sector()->xs() : nullptr; + viewBackupSpriteLoc(debrisactor); - if (debrisactor->xspr.physAttr & kPhysDebrisTouch) - { - PLAYER* pPlayer = NULL; - for (int a = connecthead; a != -1; a = connectpoint2[a]) - { - pPlayer = &gPlayer[a]; - DBloodActor* pact = pPlayer->actor; + bool uwater = false; + int mass = debrisactor->spriteMass.mass; + int airVel = debrisactor->spriteMass.airVel; - if (pact && pact->hit.hit.type == kHitSprite && pact->hit.hit.actor() == debrisactor) - { - int nSpeed = approxDist(pact->xvel, pact->yvel); - nSpeed = ClipLow(nSpeed - MulScale(nSpeed, mass, 6), 0x9000 - (mass << 3)); + int top, bottom; + GetActorExtents(debrisactor, &top, &bottom); - debrisactor->xvel += MulScale(nSpeed, Cos(pPlayer->actor->spr.ang), 30); - debrisactor->yvel += MulScale(nSpeed, Sin(pPlayer->actor->spr.ang), 30); + if (pXSector != nullptr) + { + if ((uwater = pXSector->Underwater) != 0) airVel <<= 6; + if (pXSector->panVel != 0 && getflorzofslopeptr(debrisactor->spr.sector(), debrisactor->spr.pos.X, debrisactor->spr.pos.Y) <= bottom) + { + int angle = pXSector->panAngle; int speed = 0; + if (pXSector->panAlways || pXSector->state || pXSector->busy) + { + speed = pXSector->panVel << 9; + if (!pXSector->panAlways && pXSector->busy) + speed = MulScale(speed, pXSector->busy, 16); + } + if (debrisactor->spr.sector()->floorstat & CSTAT_SECTOR_ALIGN) + angle = (angle + GetWallAngle(debrisactor->spr.sector()->firstWall()) + 512) & 2047; + int dx = MulScale(speed, Cos(angle), 30); + int dy = MulScale(speed, Sin(angle), 30); + debrisactor->xvel += dx; + debrisactor->yvel += dy; + } + } - debrisactor->hit.hit.setSprite(pPlayer->actor); - } - } - } - - if (debrisactor->xspr.physAttr & kPhysGravity) debrisactor->xspr.physAttr |= kPhysFalling; - if ((debrisactor->xspr.physAttr & kPhysFalling) || debrisactor->xvel || debrisactor->yvel || debrisactor->zvel || debrisactor->spr.sector()->velFloor || debrisactor->spr.sector()->velCeil) - debrisMove(i); + actAirDrag(debrisactor, airVel); - if (debrisactor->xvel || debrisactor->yvel) - debrisactor->xspr.goalAng = getangle(debrisactor->xvel, debrisactor->yvel) & 2047; + if (debrisactor->xspr.physAttr & kPhysDebrisTouch) + { + PLAYER* pPlayer = NULL; + for (int a = connecthead; a != -1; a = connectpoint2[a]) + { + pPlayer = &gPlayer[a]; + DBloodActor* pact = pPlayer->actor; - int ang = debrisactor->spr.ang & 2047; - if ((uwater = spriteIsUnderwater(debrisactor)) == false) evKillActor(debrisactor, kCallbackEnemeyBubble); - else if (Chance(0x1000 - mass)) - { - if (debrisactor->zvel > 0x100) debrisBubble(debrisactor); - if (ang == debrisactor->xspr.goalAng) - { - debrisactor->xspr.goalAng = (debrisactor->spr.ang + Random3(kAng60)) & 2047; - debrisBubble(debrisactor); - } - } + if (pact && pact->hit.hit.type == kHitSprite && pact->hit.hit.actor() == debrisactor) + { + int nSpeed = approxDist(pact->xvel, pact->yvel); + nSpeed = ClipLow(nSpeed - MulScale(nSpeed, mass, 6), 0x9000 - (mass << 3)); - int angStep = ClipLow(mulscale8(1, ((abs(debrisactor->xvel) + abs(debrisactor->yvel)) >> 5)), (uwater) ? 1 : 0); - if (ang < debrisactor->xspr.goalAng) debrisactor->spr.ang = ClipHigh(ang + angStep, debrisactor->xspr.goalAng); - else if (ang > debrisactor->xspr.goalAng) debrisactor->spr.ang = ClipLow(ang - angStep, debrisactor->xspr.goalAng); + debrisactor->xvel += MulScale(nSpeed, Cos(pPlayer->actor->spr.ang), 30); + debrisactor->yvel += MulScale(nSpeed, Sin(pPlayer->actor->spr.ang), 30); - auto pSector = debrisactor->spr.sector(); - int cz = getceilzofslopeptr(pSector, debrisactor->spr.pos.X, debrisactor->spr.pos.Y); - int fz = getflorzofslopeptr(pSector, debrisactor->spr.pos.X, debrisactor->spr.pos.Y); + debrisactor->hit.hit.setSprite(pPlayer->actor); + } + } + } - GetActorExtents(debrisactor, &top, &bottom); - if (fz >= bottom && pSector->lowerLink == nullptr && !(pSector->ceilingstat & CSTAT_SECTOR_SKY)) debrisactor->spr.pos.Z += ClipLow(cz - top, 0); - if (cz <= top && pSector->upperLink == nullptr && !(pSector->floorstat & CSTAT_SECTOR_SKY)) debrisactor->spr.pos.Z += ClipHigh(fz - bottom, 0); - } - } + if (debrisactor->xspr.physAttr & kPhysGravity) debrisactor->xspr.physAttr |= kPhysFalling; + if ((debrisactor->xspr.physAttr & kPhysFalling) || debrisactor->xvel || debrisactor->yvel || debrisactor->zvel || debrisactor->spr.sector()->velFloor || debrisactor->spr.sector()->velCeil) + debrisMove(i); + + if (debrisactor->xvel || debrisactor->yvel) + debrisactor->xspr.goalAng = getangle(debrisactor->xvel, debrisactor->yvel) & 2047; + + int ang = debrisactor->spr.ang & 2047; + if ((uwater = spriteIsUnderwater(debrisactor)) == false) evKillActor(debrisactor, kCallbackEnemeyBubble); + else if (Chance(0x1000 - mass)) + { + if (debrisactor->zvel > 0x100) debrisBubble(debrisactor); + if (ang == debrisactor->xspr.goalAng) + { + debrisactor->xspr.goalAng = (debrisactor->spr.ang + Random3(kAng60)) & 2047; + debrisBubble(debrisactor); + } + } + + int angStep = ClipLow(mulscale8(1, ((abs(debrisactor->xvel) + abs(debrisactor->yvel)) >> 5)), (uwater) ? 1 : 0); + if (ang < debrisactor->xspr.goalAng) debrisactor->spr.ang = ClipHigh(ang + angStep, debrisactor->xspr.goalAng); + else if (ang > debrisactor->xspr.goalAng) debrisactor->spr.ang = ClipLow(ang - angStep, debrisactor->xspr.goalAng); + + auto pSector = debrisactor->spr.sector(); + int cz = getceilzofslopeptr(pSector, debrisactor->spr.pos.X, debrisactor->spr.pos.Y); + int fz = getflorzofslopeptr(pSector, debrisactor->spr.pos.X, debrisactor->spr.pos.Y); + + GetActorExtents(debrisactor, &top, &bottom); + if (fz >= bottom && pSector->lowerLink == nullptr && !(pSector->ceilingstat & CSTAT_SECTOR_SKY)) debrisactor->spr.pos.Z += ClipLow(cz - top, 0); + if (cz <= top && pSector->upperLink == nullptr && !(pSector->floorstat & CSTAT_SECTOR_SKY)) debrisactor->spr.pos.Z += ClipHigh(fz - bottom, 0); + } + } } //--------------------------------------------------------------------------- @@ -1361,10 +1361,10 @@ void nnExtProcessSuperSprites() // //--------------------------------------------------------------------------- -void sfxPlayMissileSound(DBloodActor* actor, int missileId) +void sfxPlayMissileSound(DBloodActor* actor, int missileId) { - const MISSILEINFO_EXTRA* pMissType = &gMissileInfoExtra[missileId - kMissileBase]; - sfxPlay3DSound(actor, Chance(0x5000) ? pMissType->fireSound[0] : pMissType->fireSound[1], -1, 0); + const MISSILEINFO_EXTRA* pMissType = &gMissileInfoExtra[missileId - kMissileBase]; + sfxPlay3DSound(actor, Chance(0x5000) ? pMissType->fireSound[0] : pMissType->fireSound[1], -1, 0); } //--------------------------------------------------------------------------- @@ -1373,10 +1373,10 @@ void sfxPlayMissileSound(DBloodActor* actor, int missileId) // //--------------------------------------------------------------------------- -void sfxPlayVectorSound(DBloodActor* actor, int vectorId) +void sfxPlayVectorSound(DBloodActor* actor, int vectorId) { - const VECTORINFO_EXTRA* pVectorData = &gVectorInfoExtra[vectorId]; - sfxPlay3DSound(actor, Chance(0x5000) ? pVectorData->fireSound[0] : pVectorData->fireSound[1], -1, 0); + const VECTORINFO_EXTRA* pVectorData = &gVectorInfoExtra[vectorId]; + sfxPlay3DSound(actor, Chance(0x5000) ? pVectorData->fireSound[0] : pVectorData->fireSound[1], -1, 0); } //--------------------------------------------------------------------------- @@ -1387,121 +1387,121 @@ void sfxPlayVectorSound(DBloodActor* actor, int vectorId) int getSpriteMassBySize(DBloodActor* actor) { - int mass = 0; int seqId = -1; int clipDist = actor->spr.clipdist; - if (!actor->hasX()) - { - I_Error("getSpriteMassBySize: actor->spr.hasX == false"); - } - else if (actor->IsDudeActor()) - { - switch (actor->spr.type) - { - case kDudePodMother: // fake dude, no seq - break; - case kDudeModernCustom: - case kDudeModernCustomBurning: - seqId = actor->xspr.data2; - clipDist = actor->genDudeExtra.initVals[2]; - break; - default: - seqId = getDudeInfo(actor->spr.type)->seqStartID; - break; - } - } - else - { - seqId = seqGetID(actor); - } + int mass = 0; int seqId = -1; int clipDist = actor->spr.clipdist; + if (!actor->hasX()) + { + I_Error("getSpriteMassBySize: actor->spr.hasX == false"); + } + else if (actor->IsDudeActor()) + { + switch (actor->spr.type) + { + case kDudePodMother: // fake dude, no seq + break; + case kDudeModernCustom: + case kDudeModernCustomBurning: + seqId = actor->xspr.data2; + clipDist = actor->genDudeExtra.initVals[2]; + break; + default: + seqId = getDudeInfo(actor->spr.type)->seqStartID; + break; + } + } + else + { + seqId = seqGetID(actor); + } - SPRITEMASS* cached = &actor->spriteMass; - if (((seqId >= 0 && seqId == cached->seqId) || actor->spr.picnum == cached->picnum) && actor->spr.xrepeat == cached->xrepeat && - actor->spr.yrepeat == cached->yrepeat && clipDist == cached->clipdist) - { - return cached->mass; - } + SPRITEMASS* cached = &actor->spriteMass; + if (((seqId >= 0 && seqId == cached->seqId) || actor->spr.picnum == cached->picnum) && actor->spr.xrepeat == cached->xrepeat && + actor->spr.yrepeat == cached->yrepeat && clipDist == cached->clipdist) + { + return cached->mass; + } - int picnum = actor->spr.picnum; - int massDiv = 30; - int addMul = 2; - int subMul = 2; + int picnum = actor->spr.picnum; + int massDiv = 30; + int addMul = 2; + int subMul = 2; - if (seqId >= 0) - { - auto pSeq = getSequence(seqId); - if (pSeq) - { - picnum = seqGetTile(&pSeq->frames[0]); - } - else - picnum = actor->spr.picnum; - } + if (seqId >= 0) + { + auto pSeq = getSequence(seqId); + if (pSeq) + { + picnum = seqGetTile(&pSeq->frames[0]); + } + else + picnum = actor->spr.picnum; + } - clipDist = ClipLow(actor->spr.clipdist, 1); - int x = tileWidth(picnum); - int y = tileHeight(picnum); - int xrepeat = actor->spr.xrepeat; - int yrepeat = actor->spr.yrepeat; + clipDist = ClipLow(actor->spr.clipdist, 1); + int x = tileWidth(picnum); + int y = tileHeight(picnum); + int xrepeat = actor->spr.xrepeat; + int yrepeat = actor->spr.yrepeat; - // take surface type into account - switch (tileGetSurfType(actor->spr.picnum)) - { - case 1: massDiv = 16; break; // stone - case 2: massDiv = 18; break; // metal - case 3: massDiv = 21; break; // wood - case 4: massDiv = 25; break; // flesh - case 5: massDiv = 28; break; // water - case 6: massDiv = 26; break; // dirt - case 7: massDiv = 27; break; // clay - case 8: massDiv = 35; break; // snow - case 9: massDiv = 22; break; // ice - case 10: massDiv = 37; break; // leaves - case 11: massDiv = 33; break; // cloth - case 12: massDiv = 36; break; // plant - case 13: massDiv = 24; break; // goo - case 14: massDiv = 23; break; // lava - } + // take surface type into account + switch (tileGetSurfType(actor->spr.picnum)) + { + case 1: massDiv = 16; break; // stone + case 2: massDiv = 18; break; // metal + case 3: massDiv = 21; break; // wood + case 4: massDiv = 25; break; // flesh + case 5: massDiv = 28; break; // water + case 6: massDiv = 26; break; // dirt + case 7: massDiv = 27; break; // clay + case 8: massDiv = 35; break; // snow + case 9: massDiv = 22; break; // ice + case 10: massDiv = 37; break; // leaves + case 11: massDiv = 33; break; // cloth + case 12: massDiv = 36; break; // plant + case 13: massDiv = 24; break; // goo + case 14: massDiv = 23; break; // lava + } - mass = ((x + y) * (clipDist / 2)) / massDiv; + mass = ((x + y) * (clipDist / 2)) / massDiv; - if (xrepeat > 64) mass += ((xrepeat - 64) * addMul); - else if (xrepeat < 64 && mass > 0) - { - for (int i = 64 - xrepeat; i > 0; i--) - { - if ((mass -= subMul) <= 100 && subMul-- <= 1) - { - mass -= i; - break; - } - } - } + if (xrepeat > 64) mass += ((xrepeat - 64) * addMul); + else if (xrepeat < 64 && mass > 0) + { + for (int i = 64 - xrepeat; i > 0; i--) + { + if ((mass -= subMul) <= 100 && subMul-- <= 1) + { + mass -= i; + break; + } + } + } - if (yrepeat > 64) mass += ((yrepeat - 64) * addMul); - else if (yrepeat < 64 && mass > 0) - { - for (int i = 64 - yrepeat; i > 0; i--) - { - if ((mass -= subMul) <= 100 && subMul-- <= 1) - { - mass -= i; - break; - } - } - } + if (yrepeat > 64) mass += ((yrepeat - 64) * addMul); + else if (yrepeat < 64 && mass > 0) + { + for (int i = 64 - yrepeat; i > 0; i--) + { + if ((mass -= subMul) <= 100 && subMul-- <= 1) + { + mass -= i; + break; + } + } + } - if (mass <= 0) cached->mass = 1 + Random(10); - else cached->mass = ClipRange(mass, 1, 65535); + if (mass <= 0) cached->mass = 1 + Random(10); + else cached->mass = ClipRange(mass, 1, 65535); - cached->airVel = ClipRange(400 - cached->mass, 32, 400); - cached->fraction = ClipRange(60000 - (cached->mass << 7), 8192, 60000); + cached->airVel = ClipRange(400 - cached->mass, 32, 400); + cached->fraction = ClipRange(60000 - (cached->mass << 7), 8192, 60000); - cached->xrepeat = actor->spr.xrepeat; - cached->yrepeat = actor->spr.yrepeat; - cached->picnum = actor->spr.picnum; - cached->seqId = seqId; - cached->clipdist = actor->spr.clipdist; + cached->xrepeat = actor->spr.xrepeat; + cached->yrepeat = actor->spr.yrepeat; + cached->picnum = actor->spr.picnum; + cached->seqId = seqId; + cached->clipdist = actor->spr.clipdist; - return cached->mass; + return cached->mass; } //--------------------------------------------------------------------------- @@ -1510,33 +1510,33 @@ int getSpriteMassBySize(DBloodActor* actor) // //--------------------------------------------------------------------------- -static int debrisGetIndex(DBloodActor* actor) +static int debrisGetIndex(DBloodActor* actor) { - if (!actor->hasX() || actor->xspr.physAttr == 0) - return -1; + if (!actor->hasX() || actor->xspr.physAttr == 0) + return -1; - for (int i = 0; i < gPhysSpritesCount; i++) - { - if (gPhysSpritesList[i] != actor) continue; - return i; - } + for (int i = 0; i < gPhysSpritesCount; i++) + { + if (gPhysSpritesList[i] != actor) continue; + return i; + } - return -1; + return -1; } -int debrisGetFreeIndex(void) +int debrisGetFreeIndex(void) { - for (int i = 0; i < kMaxSuperXSprites; i++) - { - if (gPhysSpritesList[i] == nullptr) return i; - auto actor = gPhysSpritesList[i]; - if (actor->spr.statnum == kStatFree) return i; + for (int i = 0; i < kMaxSuperXSprites; i++) + { + if (gPhysSpritesList[i] == nullptr) return i; + auto actor = gPhysSpritesList[i]; + if (actor->spr.statnum == kStatFree) return i; - else if ((actor->spr.flags & kHitagFree) || !gPhysSpritesList[i]->hasX()) return i; - else if (gPhysSpritesList[i]->xspr.physAttr == 0) return i; - } + else if ((actor->spr.flags & kHitagFree) || !gPhysSpritesList[i]->hasX()) return i; + else if (gPhysSpritesList[i]->xspr.physAttr == 0) return i; + } - return -1; + return -1; } //--------------------------------------------------------------------------- @@ -1547,33 +1547,33 @@ int debrisGetFreeIndex(void) void debrisConcuss(DBloodActor* owneractor, int listIndex, int x, int y, int z, int dmg) { - DBloodActor* actor = gPhysSpritesList[listIndex]; - if (actor != nullptr && actor->hasX()) - { - int dx = actor->spr.pos.X - x; int dy = actor->spr.pos.Y - y; int dz = (actor->spr.pos.Z - z) >> 4; - dmg = scale(0x40000, dmg, 0x40000 + dx * dx + dy * dy + dz * dz); - bool thing = (actor->spr.type >= kThingBase && actor->spr.type < kThingMax); - int size = (tileWidth(actor->spr.picnum) * actor->spr.xrepeat * tileHeight(actor->spr.picnum) * actor->spr.yrepeat) >> 1; - if (actor->xspr.physAttr & kPhysDebrisExplode) - { - if (actor->spriteMass.mass > 0) - { - int t = scale(dmg, size, actor->spriteMass.mass); + DBloodActor* actor = gPhysSpritesList[listIndex]; + if (actor != nullptr && actor->hasX()) + { + int dx = actor->spr.pos.X - x; int dy = actor->spr.pos.Y - y; int dz = (actor->spr.pos.Z - z) >> 4; + dmg = scale(0x40000, dmg, 0x40000 + dx * dx + dy * dy + dz * dz); + bool thing = (actor->spr.type >= kThingBase && actor->spr.type < kThingMax); + int size = (tileWidth(actor->spr.picnum) * actor->spr.xrepeat * tileHeight(actor->spr.picnum) * actor->spr.yrepeat) >> 1; + if (actor->xspr.physAttr & kPhysDebrisExplode) + { + if (actor->spriteMass.mass > 0) + { + int t = scale(dmg, size, actor->spriteMass.mass); - actor->xvel += MulScale(t, dx, 16); - actor->yvel += MulScale(t, dy, 16); - actor->zvel += MulScale(t, dz, 16); - } + actor->xvel += MulScale(t, dx, 16); + actor->yvel += MulScale(t, dy, 16); + actor->zvel += MulScale(t, dz, 16); + } - if (thing) - actor->spr.statnum = kStatThing; // temporary change statnum property - } + if (thing) + actor->spr.statnum = kStatThing; // temporary change statnum property + } - actDamageSprite(owneractor, actor, kDamageExplode, dmg); - - if (thing) - actor->spr.statnum = kStatDecoration; // return statnum property back - } + actDamageSprite(owneractor, actor, kDamageExplode, dmg); + + if (thing) + actor->spr.statnum = kStatDecoration; // return statnum property back + } } //--------------------------------------------------------------------------- @@ -1584,26 +1584,26 @@ void debrisConcuss(DBloodActor* owneractor, int listIndex, int x, int y, int z, void debrisBubble(DBloodActor* actor) { - int top, bottom; - GetActorExtents(actor, &top, &bottom); - for (unsigned int i = 0; i < 1 + Random(5); i++) { - - int nDist = (actor->spr.xrepeat * (tileWidth(actor->spr.picnum) >> 1)) >> 2; - int nAngle = Random(2048); - int x = actor->spr.pos.X + MulScale(nDist, Cos(nAngle), 30); - int y = actor->spr.pos.Y + MulScale(nDist, Sin(nAngle), 30); - int z = bottom - Random(bottom - top); - auto pFX = gFX.fxSpawnActor((FX_ID)(FX_23 + Random(3)), actor->spr.sector(), x, y, z, 0); - if (pFX) { - pFX->xvel = actor->xvel + Random2(0x1aaaa); - pFX->yvel = actor->yvel + Random2(0x1aaaa); - pFX->zvel = actor->zvel + Random2(0x1aaaa); - } + int top, bottom; + GetActorExtents(actor, &top, &bottom); + for (unsigned int i = 0; i < 1 + Random(5); i++) { - } - - if (Chance(0x2000)) - evPostActor(actor, 0, kCallbackEnemeyBubble); + int nDist = (actor->spr.xrepeat * (tileWidth(actor->spr.picnum) >> 1)) >> 2; + int nAngle = Random(2048); + int x = actor->spr.pos.X + MulScale(nDist, Cos(nAngle), 30); + int y = actor->spr.pos.Y + MulScale(nDist, Sin(nAngle), 30); + int z = bottom - Random(bottom - top); + auto pFX = gFX.fxSpawnActor((FX_ID)(FX_23 + Random(3)), actor->spr.sector(), x, y, z, 0); + if (pFX) { + pFX->xvel = actor->xvel + Random2(0x1aaaa); + pFX->yvel = actor->yvel + Random2(0x1aaaa); + pFX->zvel = actor->zvel + Random2(0x1aaaa); + } + + } + + if (Chance(0x2000)) + evPostActor(actor, 0, kCallbackEnemeyBubble); } //--------------------------------------------------------------------------- @@ -1614,241 +1614,241 @@ void debrisBubble(DBloodActor* actor) void debrisMove(int listIndex) { - DBloodActor* actor = gPhysSpritesList[listIndex]; - auto pSector = actor->spr.sector(); + DBloodActor* actor = gPhysSpritesList[listIndex]; + auto pSector = actor->spr.sector(); - if (!actor->hasX() || !pSector) - { - gPhysSpritesList[listIndex] = nullptr; - return; - } + if (!actor->hasX() || !pSector) + { + gPhysSpritesList[listIndex] = nullptr; + return; + } - int top, bottom; - GetActorExtents(actor, &top, &bottom); + int top, bottom; + GetActorExtents(actor, &top, &bottom); - Collision moveHit; - moveHit.setNone(); - int floorDist = (bottom - actor->spr.pos.Z) >> 2; - int ceilDist = (actor->spr.pos.Z - top) >> 2; - int clipDist = actor->spr.clipdist << 2; - int mass = actor->spriteMass.mass; + Collision moveHit; + moveHit.setNone(); + int floorDist = (bottom - actor->spr.pos.Z) >> 2; + int ceilDist = (actor->spr.pos.Z - top) >> 2; + int clipDist = actor->spr.clipdist << 2; + int mass = actor->spriteMass.mass; - bool uwater = false; - int tmpFraction = actor->spriteMass.fraction; - if (pSector->hasX() && pSector->xs().Underwater) - { - tmpFraction >>= 1; - uwater = true; - } + bool uwater = false; + int tmpFraction = actor->spriteMass.fraction; + if (pSector->hasX() && pSector->xs().Underwater) + { + tmpFraction >>= 1; + uwater = true; + } - if (actor->xvel || actor->yvel) - { + if (actor->xvel || actor->yvel) + { - auto oldcstat = actor->spr.cstat; - actor->spr.cstat &= ~(CSTAT_SPRITE_BLOCK | CSTAT_SPRITE_BLOCK_HITSCAN); + auto oldcstat = actor->spr.cstat; + actor->spr.cstat &= ~(CSTAT_SPRITE_BLOCK | CSTAT_SPRITE_BLOCK_HITSCAN); - ClipMove(actor->spr.pos, &pSector, actor->xvel >> 12, - actor->yvel >> 12, clipDist, ceilDist, floorDist, CLIPMASK0, moveHit); - actor->hit.hit = moveHit; + ClipMove(actor->spr.pos, &pSector, actor->xvel >> 12, + actor->yvel >> 12, clipDist, ceilDist, floorDist, CLIPMASK0, moveHit); + actor->hit.hit = moveHit; - actor->spr.cstat = oldcstat; - if (actor->spr.sector() != pSector) - { - if (!pSector) return; - else ChangeActorSect(actor, pSector); - } + actor->spr.cstat = oldcstat; + if (actor->spr.sector() != pSector) + { + if (!pSector) return; + else ChangeActorSect(actor, pSector); + } - if (pSector->type >= kSectorPath && pSector->type <= kSectorRotate) - { - auto pSector2 = pSector; - if (pushmove(&actor->spr.pos, &pSector2, clipDist, ceilDist, floorDist, CLIPMASK0) != -1) - pSector = pSector2; - } + if (pSector->type >= kSectorPath && pSector->type <= kSectorRotate) + { + auto pSector2 = pSector; + if (pushmove(&actor->spr.pos, &pSector2, clipDist, ceilDist, floorDist, CLIPMASK0) != -1) + pSector = pSector2; + } - if (actor->hit.hit.type == kHitWall) - { - moveHit = actor->hit.hit; - actWallBounceVector(&actor->xvel, &actor->yvel, moveHit.hitWall, tmpFraction); - } + if (actor->hit.hit.type == kHitWall) + { + moveHit = actor->hit.hit; + actWallBounceVector(&actor->xvel, &actor->yvel, moveHit.hitWall, tmpFraction); + } - } - else if (!FindSector(actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z, &pSector)) - { - return; - } + } + else if (!FindSector(actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z, &pSector)) + { + return; + } - if (actor->spr.sector() != pSector) - { - assert(pSector); - ChangeActorSect(actor, pSector); - pSector = actor->spr.sector(); - } + if (actor->spr.sector() != pSector) + { + assert(pSector); + ChangeActorSect(actor, pSector); + pSector = actor->spr.sector(); + } - if (pSector->hasX()) - uwater = pSector->xs().Underwater; + if (pSector->hasX()) + uwater = pSector->xs().Underwater; - if (actor->zvel) - actor->spr.pos.Z += actor->zvel >> 8; + if (actor->zvel) + actor->spr.pos.Z += actor->zvel >> 8; - int ceilZ, floorZ; - Collision ceilColl, floorColl; - GetZRange(actor, &ceilZ, &ceilColl, &floorZ, &floorColl, clipDist, CLIPMASK0, PARALLAXCLIP_CEILING | PARALLAXCLIP_FLOOR); - GetActorExtents(actor, &top, &bottom); + int ceilZ, floorZ; + Collision ceilColl, floorColl; + GetZRange(actor, &ceilZ, &ceilColl, &floorZ, &floorColl, clipDist, CLIPMASK0, PARALLAXCLIP_CEILING | PARALLAXCLIP_FLOOR); + GetActorExtents(actor, &top, &bottom); - if ((actor->xspr.physAttr & kPhysDebrisSwim) && uwater) - { - int vc = 0; - int cz = getceilzofslopeptr(pSector, actor->spr.pos.X, actor->spr.pos.Y); - int fz = getflorzofslopeptr(pSector, actor->spr.pos.X, actor->spr.pos.Y); - int div = ClipLow(bottom - top, 1); + if ((actor->xspr.physAttr & kPhysDebrisSwim) && uwater) + { + int vc = 0; + int cz = getceilzofslopeptr(pSector, actor->spr.pos.X, actor->spr.pos.Y); + int fz = getflorzofslopeptr(pSector, actor->spr.pos.X, actor->spr.pos.Y); + int div = ClipLow(bottom - top, 1); - if (pSector->lowerLink) cz += (cz < 0) ? 0x500 : -0x500; - if (top > cz && (!(actor->xspr.physAttr & kPhysDebrisFloat) || fz <= bottom << 2)) - actor->zvel -= DivScale((bottom - ceilZ) >> 6, mass, 8); + if (pSector->lowerLink) cz += (cz < 0) ? 0x500 : -0x500; + if (top > cz && (!(actor->xspr.physAttr & kPhysDebrisFloat) || fz <= bottom << 2)) + actor->zvel -= DivScale((bottom - ceilZ) >> 6, mass, 8); - if (fz < bottom) - vc = 58254 + ((bottom - fz) * -80099) / div; + if (fz < bottom) + vc = 58254 + ((bottom - fz) * -80099) / div; - if (vc) - { - actor->spr.pos.Z += ((vc << 2) >> 1) >> 8; - actor->zvel += vc; - } + if (vc) + { + actor->spr.pos.Z += ((vc << 2) >> 1) >> 8; + actor->zvel += vc; + } - } - else if ((actor->xspr.physAttr & kPhysGravity) && bottom < floorZ) - { - actor->spr.pos.Z += 455; - actor->zvel += 58254; + } + else if ((actor->xspr.physAttr & kPhysGravity) && bottom < floorZ) + { + actor->spr.pos.Z += 455; + actor->zvel += 58254; - } + } - int i; - if ((i = CheckLink(actor)) != 0) - { - GetZRange(actor, &ceilZ, &ceilColl, &floorZ, &floorColl, clipDist, CLIPMASK0, PARALLAXCLIP_CEILING | PARALLAXCLIP_FLOOR); - if (!(actor->spr.cstat & CSTAT_SPRITE_INVISIBLE)) - { - switch (i) - { - case kMarkerUpWater: - case kMarkerUpGoo: - int pitch = (150000 - (actor->spriteMass.mass << 9)) + Random3(8192); - sfxPlay3DSoundCP(actor, 720, -1, 0, pitch, 75 - Random(40)); - if (!spriteIsUnderwater(actor)) - { - evKillActor(actor, kCallbackEnemeyBubble); - } - else - { - evPostActor(actor, 0, kCallbackEnemeyBubble); - for (int ii = 2; ii <= 5; ii++) - { - if (Chance(0x5000 * ii)) - evPostActor(actor, Random(5), kCallbackEnemeyBubble); - } - } - break; - } - } - } + int i; + if ((i = CheckLink(actor)) != 0) + { + GetZRange(actor, &ceilZ, &ceilColl, &floorZ, &floorColl, clipDist, CLIPMASK0, PARALLAXCLIP_CEILING | PARALLAXCLIP_FLOOR); + if (!(actor->spr.cstat & CSTAT_SPRITE_INVISIBLE)) + { + switch (i) + { + case kMarkerUpWater: + case kMarkerUpGoo: + int pitch = (150000 - (actor->spriteMass.mass << 9)) + Random3(8192); + sfxPlay3DSoundCP(actor, 720, -1, 0, pitch, 75 - Random(40)); + if (!spriteIsUnderwater(actor)) + { + evKillActor(actor, kCallbackEnemeyBubble); + } + else + { + evPostActor(actor, 0, kCallbackEnemeyBubble); + for (int ii = 2; ii <= 5; ii++) + { + if (Chance(0x5000 * ii)) + evPostActor(actor, Random(5), kCallbackEnemeyBubble); + } + } + break; + } + } + } - GetActorExtents(actor, &top, &bottom); + GetActorExtents(actor, &top, &bottom); - if (floorZ <= bottom) { + if (floorZ <= bottom) { - actor->hit.florhit = floorColl; - int v30 = actor->zvel - actor->spr.sector()->velFloor; + actor->hit.florhit = floorColl; + int v30 = actor->zvel - actor->spr.sector()->velFloor; - if (v30 > 0) - { - actor->xspr.physAttr |= kPhysFalling; - actFloorBounceVector(&actor->xvel, &actor->yvel, &v30, actor->spr.sector(), tmpFraction); - actor->zvel = v30; + if (v30 > 0) + { + actor->xspr.physAttr |= kPhysFalling; + actFloorBounceVector(&actor->xvel, &actor->yvel, &v30, actor->spr.sector(), tmpFraction); + actor->zvel = v30; - if (abs(actor->zvel) < 0x10000) - { - actor->zvel = actor->spr.sector()->velFloor; - actor->xspr.physAttr &= ~kPhysFalling; - } + if (abs(actor->zvel) < 0x10000) + { + actor->zvel = actor->spr.sector()->velFloor; + actor->xspr.physAttr &= ~kPhysFalling; + } - moveHit = floorColl; - DBloodActor* pFX = NULL, *pFX2 = NULL; - switch (tileGetSurfType(floorColl)) - { - case kSurfLava: - if ((pFX = gFX.fxSpawnActor(FX_10, actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y, floorZ, 0)) == NULL) break; - for (i = 0; i < 7; i++) - { - if ((pFX2 = gFX.fxSpawnActor(FX_14, pFX->spr.sector(), pFX->spr.pos.X, pFX->spr.pos.Y, pFX->spr.pos.Z, 0)) == NULL) continue; - pFX2->xvel = Random2(0x6aaaa); - pFX2->yvel = Random2(0x6aaaa); - pFX2->zvel = -(int)Random(0xd5555); - } - break; - case kSurfWater: - gFX.fxSpawnActor(FX_9, actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y, floorZ, 0); - break; - } + moveHit = floorColl; + DBloodActor* pFX = NULL, * pFX2 = NULL; + switch (tileGetSurfType(floorColl)) + { + case kSurfLava: + if ((pFX = gFX.fxSpawnActor(FX_10, actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y, floorZ, 0)) == NULL) break; + for (i = 0; i < 7; i++) + { + if ((pFX2 = gFX.fxSpawnActor(FX_14, pFX->spr.sector(), pFX->spr.pos.X, pFX->spr.pos.Y, pFX->spr.pos.Z, 0)) == NULL) continue; + pFX2->xvel = Random2(0x6aaaa); + pFX2->yvel = Random2(0x6aaaa); + pFX2->zvel = -(int)Random(0xd5555); + } + break; + case kSurfWater: + gFX.fxSpawnActor(FX_9, actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y, floorZ, 0); + break; + } - } - else if (actor->zvel == 0) - { - actor->xspr.physAttr &= ~kPhysFalling; - } - } - else - { - actor->hit.florhit.setNone(); - if (actor->xspr.physAttr & kPhysGravity) - actor->xspr.physAttr |= kPhysFalling; - } + } + else if (actor->zvel == 0) + { + actor->xspr.physAttr &= ~kPhysFalling; + } + } + else + { + actor->hit.florhit.setNone(); + if (actor->xspr.physAttr & kPhysGravity) + actor->xspr.physAttr |= kPhysFalling; + } - if (top <= ceilZ) - { - actor->hit.ceilhit = moveHit = ceilColl; - actor->spr.pos.Z += ClipLow(ceilZ - top, 0); - if (actor->zvel <= 0 && (actor->xspr.physAttr & kPhysFalling)) - actor->zvel = MulScale(-actor->zvel, 0x2000, 16); + if (top <= ceilZ) + { + actor->hit.ceilhit = moveHit = ceilColl; + actor->spr.pos.Z += ClipLow(ceilZ - top, 0); + if (actor->zvel <= 0 && (actor->xspr.physAttr & kPhysFalling)) + actor->zvel = MulScale(-actor->zvel, 0x2000, 16); - } - else - { - actor->hit.ceilhit.setNone(); - GetActorExtents(actor, &top, &bottom); - } + } + else + { + actor->hit.ceilhit.setNone(); + GetActorExtents(actor, &top, &bottom); + } - if (moveHit.type != kHitNone && actor->xspr.Impact && !actor->xspr.locked && !actor->xspr.isTriggered && (actor->xspr.state == actor->xspr.restState || actor->xspr.Interrutable)) { - if (actor->spr.type >= kThingBase && actor->spr.type < kThingMax) - ChangeActorStat(actor, kStatThing); + if (moveHit.type != kHitNone && actor->xspr.Impact && !actor->xspr.locked && !actor->xspr.isTriggered && (actor->xspr.state == actor->xspr.restState || actor->xspr.Interrutable)) { + if (actor->spr.type >= kThingBase && actor->spr.type < kThingMax) + ChangeActorStat(actor, kStatThing); - trTriggerSprite(actor, kCmdToggle); - } + trTriggerSprite(actor, kCmdToggle); + } - if (!actor->xvel && !actor->yvel) return; - else if (floorColl.type == kHitSprite) - { + if (!actor->xvel && !actor->yvel) return; + else if (floorColl.type == kHitSprite) + { - if ((floorColl.actor()->spr.cstat & CSTAT_SPRITE_ALIGNMENT_MASK) == 0) - { - actor->xvel += MulScale(4, actor->spr.pos.X - floorColl.actor()->spr.pos.X, 2); - actor->yvel += MulScale(4, actor->spr.pos.Y - floorColl.actor()->spr.pos.Y, 2); - return; - } - } + if ((floorColl.actor()->spr.cstat & CSTAT_SPRITE_ALIGNMENT_MASK) == 0) + { + actor->xvel += MulScale(4, actor->spr.pos.X - floorColl.actor()->spr.pos.X, 2); + actor->yvel += MulScale(4, actor->spr.pos.Y - floorColl.actor()->spr.pos.Y, 2); + return; + } + } - actor->xspr.height = ClipLow(floorZ - bottom, 0) >> 8; - if (uwater || actor->xspr.height >= 0x100) - return; + actor->xspr.height = ClipLow(floorZ - bottom, 0) >> 8; + if (uwater || actor->xspr.height >= 0x100) + return; - int nDrag = 0x2a00; - if (actor->xspr.height > 0) - nDrag -= scale(nDrag, actor->xspr.height, 0x100); + int nDrag = 0x2a00; + if (actor->xspr.height > 0) + nDrag -= scale(nDrag, actor->xspr.height, 0x100); - actor->xvel -= mulscale16r(actor->xvel, nDrag); - actor->yvel -= mulscale16r(actor->yvel, nDrag); - if (approxDist(actor->xvel, actor->yvel) < 0x1000) - actor->xvel = actor->yvel = 0; + actor->xvel -= mulscale16r(actor->xvel, nDrag); + actor->yvel -= mulscale16r(actor->yvel, nDrag); + if (approxDist(actor->xvel, actor->yvel) < 0x1000) + actor->xvel = actor->yvel = 0; } //--------------------------------------------------------------------------- @@ -1857,18 +1857,18 @@ void debrisMove(int listIndex) // //--------------------------------------------------------------------------- -bool ceilIsTooLow(DBloodActor* actor) +bool ceilIsTooLow(DBloodActor* actor) { - if (actor != nullptr) - { - sectortype* pSector = actor->spr.sector(); - int a = pSector->ceilingz - pSector->floorz; - int top, bottom; - GetActorExtents(actor, &top, &bottom); - int b = top - bottom; - if (a > b) return true; - } - return false; + if (actor != nullptr) + { + sectortype* pSector = actor->spr.sector(); + int a = pSector->ceilingz - pSector->floorz; + int top, bottom; + GetActorExtents(actor, &top, &bottom); + int b = top - bottom; + if (a > b) return true; + } + return false; } //--------------------------------------------------------------------------- @@ -1879,16 +1879,16 @@ bool ceilIsTooLow(DBloodActor* actor) void aiSetGenIdleState(DBloodActor* actor) { - switch (actor->spr.type) - { - case kDudeModernCustom: - case kDudeModernCustomBurning: - aiGenDudeNewState(actor, &genIdle); - break; - default: - aiNewState(actor, &genIdle); - break; - } + switch (actor->spr.type) + { + case kDudeModernCustom: + case kDudeModernCustomBurning: + aiGenDudeNewState(actor, &genIdle); + break; + default: + aiNewState(actor, &genIdle); + break; + } } //--------------------------------------------------------------------------- @@ -1897,42 +1897,42 @@ void aiSetGenIdleState(DBloodActor* actor) // //--------------------------------------------------------------------------- -void windGenStopWindOnSectors(DBloodActor* sourceactor) +void windGenStopWindOnSectors(DBloodActor* sourceactor) { - if (sourceactor->xspr.txID <= 0 && sourceactor->spr.sector()->hasX()) - { - sourceactor->spr.sector()->xs().windVel = 0; - return; - } + if (sourceactor->xspr.txID <= 0 && sourceactor->spr.sector()->hasX()) + { + sourceactor->spr.sector()->xs().windVel = 0; + return; + } - for (int i = bucketHead[sourceactor->xspr.txID]; i < bucketHead[sourceactor->xspr.txID + 1]; i++) - { - if (!rxBucket[i].isSector()) continue; - auto pSector = rxBucket[i].sector(); - XSECTOR* pXSector = &pSector->xs(); + for (int i = bucketHead[sourceactor->xspr.txID]; i < bucketHead[sourceactor->xspr.txID + 1]; i++) + { + if (!rxBucket[i].isSector()) continue; + auto pSector = rxBucket[i].sector(); + XSECTOR* pXSector = &pSector->xs(); - if ((pXSector->state == 1 && !pXSector->windAlways) - || ((sourceactor->spr.flags & kModernTypeFlag1) && !(sourceactor->spr.flags & kModernTypeFlag2))) - { - pXSector->windVel = 0; - } - } - - // check redirected TX buckets - int rx = -1; - DBloodActor* pXRedir = nullptr; - while ((pXRedir = evrListRedirectors(OBJ_SPRITE, nullptr, nullptr, sourceactor, pXRedir, &rx)) != nullptr) - { - for (int i = bucketHead[rx]; i < bucketHead[rx + 1]; i++) - { - if (!rxBucket[i].isSector()) continue; - auto pSector = rxBucket[i].sector(); - XSECTOR* pXSector = &pSector->xs(); + if ((pXSector->state == 1 && !pXSector->windAlways) + || ((sourceactor->spr.flags & kModernTypeFlag1) && !(sourceactor->spr.flags & kModernTypeFlag2))) + { + pXSector->windVel = 0; + } + } - if ((pXSector->state == 1 && !pXSector->windAlways) || (sourceactor->spr.flags & kModernTypeFlag2)) - pXSector->windVel = 0; - } - } + // check redirected TX buckets + int rx = -1; + DBloodActor* pXRedir = nullptr; + while ((pXRedir = evrListRedirectors(OBJ_SPRITE, nullptr, nullptr, sourceactor, pXRedir, &rx)) != nullptr) + { + for (int i = bucketHead[rx]; i < bucketHead[rx + 1]; i++) + { + if (!rxBucket[i].isSector()) continue; + auto pSector = rxBucket[i].sector(); + XSECTOR* pXSector = &pSector->xs(); + + if ((pXSector->state == 1 && !pXSector->windAlways) || (sourceactor->spr.flags & kModernTypeFlag2)) + pXSector->windVel = 0; + } + } } //--------------------------------------------------------------------------- @@ -1941,40 +1941,40 @@ void windGenStopWindOnSectors(DBloodActor* sourceactor) // //--------------------------------------------------------------------------- -void trPlayerCtrlStartScene(DBloodActor* sourceactor, PLAYER* pPlayer, bool force) +void trPlayerCtrlStartScene(DBloodActor* sourceactor, PLAYER* pPlayer, bool force) { - TRPLAYERCTRL* pCtrl = &gPlayerCtrl[pPlayer->nPlayer]; + TRPLAYERCTRL* pCtrl = &gPlayerCtrl[pPlayer->nPlayer]; - if (pCtrl->qavScene.initiator != nullptr && !force) return; - - QAV* pQav = playerQavSceneLoad(sourceactor->xspr.data2); - if (pQav != nullptr) - { - // save current weapon - sourceactor->xspr.dropMsg = pPlayer->curWeapon; + if (pCtrl->qavScene.initiator != nullptr && !force) return; - auto initiator = pCtrl->qavScene.initiator; - if (initiator != nullptr && initiator != sourceactor && initiator->hasX()) - sourceactor->xspr.dropMsg = initiator->xspr.dropMsg; + QAV* pQav = playerQavSceneLoad(sourceactor->xspr.data2); + if (pQav != nullptr) + { + // save current weapon + sourceactor->xspr.dropMsg = pPlayer->curWeapon; - if (initiator == nullptr) - WeaponLower(pPlayer); + auto initiator = pCtrl->qavScene.initiator; + if (initiator != nullptr && initiator != sourceactor && initiator->hasX()) + sourceactor->xspr.dropMsg = initiator->xspr.dropMsg; - sourceactor->xspr.sysData1 = ClipLow((pQav->duration * sourceactor->xspr.waitTime) / 4, 0); // how many times animation should be played + if (initiator == nullptr) + WeaponLower(pPlayer); - pCtrl->qavScene.initiator = sourceactor; - pCtrl->qavScene.qavResrc = pQav; - pCtrl->qavScene.dummy = -1; + sourceactor->xspr.sysData1 = ClipLow((pQav->duration * sourceactor->xspr.waitTime) / 4, 0); // how many times animation should be played - //pCtrl->qavScene.qavResrc->Preload(); + pCtrl->qavScene.initiator = sourceactor; + pCtrl->qavScene.qavResrc = pQav; + pCtrl->qavScene.dummy = -1; - pPlayer->sceneQav = sourceactor->xspr.data2; - pPlayer->weaponTimer = pCtrl->qavScene.qavResrc->duration; - pPlayer->qavCallback = (sourceactor->xspr.data3 > 0) ? ClipRange(sourceactor->xspr.data3 - 1, 0, 32) : -1; - pPlayer->qavLoop = false; - pPlayer->qavLastTick = I_GetTime(pCtrl->qavScene.qavResrc->ticrate); - pPlayer->qavTimer = pCtrl->qavScene.qavResrc->duration; - } + //pCtrl->qavScene.qavResrc->Preload(); + + pPlayer->sceneQav = sourceactor->xspr.data2; + pPlayer->weaponTimer = pCtrl->qavScene.qavResrc->duration; + pPlayer->qavCallback = (sourceactor->xspr.data3 > 0) ? ClipRange(sourceactor->xspr.data3 - 1, 0, 32) : -1; + pPlayer->qavLoop = false; + pPlayer->qavLastTick = I_GetTime(pCtrl->qavScene.qavResrc->ticrate); + pPlayer->qavTimer = pCtrl->qavScene.qavResrc->duration; + } } //--------------------------------------------------------------------------- @@ -1985,27 +1985,27 @@ void trPlayerCtrlStartScene(DBloodActor* sourceactor, PLAYER* pPlayer, bool forc void trPlayerCtrlStopScene(PLAYER* pPlayer) { - TRPLAYERCTRL* pCtrl = &gPlayerCtrl[pPlayer->nPlayer]; - auto initiator = pCtrl->qavScene.initiator; - if (initiator->hasX()) - { - initiator->xspr.sysData1 = 0; - } + TRPLAYERCTRL* pCtrl = &gPlayerCtrl[pPlayer->nPlayer]; + auto initiator = pCtrl->qavScene.initiator; + if (initiator->hasX()) + { + initiator->xspr.sysData1 = 0; + } - if (pCtrl->qavScene.initiator != nullptr) - { - pCtrl->qavScene.initiator = nullptr; - pCtrl->qavScene.qavResrc = nullptr; - pPlayer->sceneQav = -1; + if (pCtrl->qavScene.initiator != nullptr) + { + pCtrl->qavScene.initiator = nullptr; + pCtrl->qavScene.qavResrc = nullptr; + pPlayer->sceneQav = -1; - // restore weapon - if (pPlayer->actor->xspr.health > 0) - { - int oldWeapon = (initiator->hasX() && initiator->xspr.dropMsg != 0) ? initiator->xspr.dropMsg : 1; - pPlayer->newWeapon = pPlayer->curWeapon = oldWeapon; - WeaponRaise(pPlayer); - } - } + // restore weapon + if (pPlayer->actor->xspr.health > 0) + { + int oldWeapon = (initiator->hasX() && initiator->xspr.dropMsg != 0) ? initiator->xspr.dropMsg : 1; + pPlayer->newWeapon = pPlayer->curWeapon = oldWeapon; + WeaponRaise(pPlayer); + } + } } @@ -2015,58 +2015,58 @@ void trPlayerCtrlStopScene(PLAYER* pPlayer) // //--------------------------------------------------------------------------- -void trPlayerCtrlLink(DBloodActor* sourceactor, PLAYER* pPlayer, bool checkCondition) +void trPlayerCtrlLink(DBloodActor* sourceactor, PLAYER* pPlayer, bool checkCondition) { - // save player's sprite index to let the tracking condition know it after savegame loading... - auto actor = pPlayer->actor; - sourceactor->prevmarker = actor; - - actor->xspr.txID = sourceactor->xspr.txID; - actor->xspr.command = kCmdToggle; - actor->xspr.triggerOn = sourceactor->xspr.triggerOn; - actor->xspr.triggerOff = sourceactor->xspr.triggerOff; - actor->xspr.busyTime = sourceactor->xspr.busyTime; - actor->xspr.waitTime = sourceactor->xspr.waitTime; - actor->xspr.restState = sourceactor->xspr.restState; + // save player's sprite index to let the tracking condition know it after savegame loading... + auto actor = pPlayer->actor; + sourceactor->prevmarker = actor; - actor->xspr.Push = sourceactor->xspr.Push; - actor->xspr.Impact = sourceactor->xspr.Impact; - actor->xspr.Vector = sourceactor->xspr.Vector; - actor->xspr.Touch = sourceactor->xspr.Touch; - actor->xspr.Sight = sourceactor->xspr.Sight; - actor->xspr.Proximity = sourceactor->xspr.Proximity; + actor->xspr.txID = sourceactor->xspr.txID; + actor->xspr.command = kCmdToggle; + actor->xspr.triggerOn = sourceactor->xspr.triggerOn; + actor->xspr.triggerOff = sourceactor->xspr.triggerOff; + actor->xspr.busyTime = sourceactor->xspr.busyTime; + actor->xspr.waitTime = sourceactor->xspr.waitTime; + actor->xspr.restState = sourceactor->xspr.restState; - actor->xspr.Decoupled = sourceactor->xspr.Decoupled; - actor->xspr.Interrutable = sourceactor->xspr.Interrutable; - actor->xspr.DudeLockout = sourceactor->xspr.DudeLockout; + actor->xspr.Push = sourceactor->xspr.Push; + actor->xspr.Impact = sourceactor->xspr.Impact; + actor->xspr.Vector = sourceactor->xspr.Vector; + actor->xspr.Touch = sourceactor->xspr.Touch; + actor->xspr.Sight = sourceactor->xspr.Sight; + actor->xspr.Proximity = sourceactor->xspr.Proximity; - actor->xspr.data1 = sourceactor->xspr.data1; - actor->xspr.data2 = sourceactor->xspr.data2; - actor->xspr.data3 = sourceactor->xspr.data3; - actor->xspr.data4 = sourceactor->xspr.data4; + actor->xspr.Decoupled = sourceactor->xspr.Decoupled; + actor->xspr.Interrutable = sourceactor->xspr.Interrutable; + actor->xspr.DudeLockout = sourceactor->xspr.DudeLockout; - actor->xspr.key = sourceactor->xspr.key; - actor->xspr.dropMsg = sourceactor->xspr.dropMsg; + actor->xspr.data1 = sourceactor->xspr.data1; + actor->xspr.data2 = sourceactor->xspr.data2; + actor->xspr.data3 = sourceactor->xspr.data3; + actor->xspr.data4 = sourceactor->xspr.data4; - // let's check if there is tracking condition expecting objects with this TX id - if (checkCondition && sourceactor->xspr.txID >= kChannelUser) - { - for (int i = 0; i < gTrackingCondsCount; i++) - { - TRCONDITION* pCond = &gCondition[i]; - if (pCond->actor->xspr.rxID != sourceactor->xspr.txID) - continue; - - // search for player control sprite and replace it with actual player sprite - for (unsigned k = 0; k < pCond->length; k++) - { - if (!pCond->obj[k].obj.isActor() || pCond->obj[k].obj.actor() != sourceactor) continue; - pCond->obj[k].obj = EventObject(pPlayer->actor); - pCond->obj[k].cmd = (uint8_t)pPlayer->actor->xspr.command; - break; - } - } - } + actor->xspr.key = sourceactor->xspr.key; + actor->xspr.dropMsg = sourceactor->xspr.dropMsg; + + // let's check if there is tracking condition expecting objects with this TX id + if (checkCondition && sourceactor->xspr.txID >= kChannelUser) + { + for (int i = 0; i < gTrackingCondsCount; i++) + { + TRCONDITION* pCond = &gCondition[i]; + if (pCond->actor->xspr.rxID != sourceactor->xspr.txID) + continue; + + // search for player control sprite and replace it with actual player sprite + for (unsigned k = 0; k < pCond->length; k++) + { + if (!pCond->obj[k].obj.isActor() || pCond->obj[k].obj.actor() != sourceactor) continue; + pCond->obj[k].obj = EventObject(pPlayer->actor); + pCond->obj[k].cmd = (uint8_t)pPlayer->actor->xspr.command; + break; + } + } + } } //--------------------------------------------------------------------------- @@ -2075,22 +2075,22 @@ void trPlayerCtrlLink(DBloodActor* sourceactor, PLAYER* pPlayer, bool checkCondi // //--------------------------------------------------------------------------- -void trPlayerCtrlSetRace(int value, PLAYER* pPlayer) +void trPlayerCtrlSetRace(int value, PLAYER* pPlayer) { - playerSetRace(pPlayer, value); - switch (pPlayer->lifeMode) - { - case kModeHuman: - case kModeBeast: - playerSizeReset(pPlayer); - break; - case kModeHumanShrink: - playerSizeShrink(pPlayer, 2); - break; - case kModeHumanGrown: - playerSizeGrow(pPlayer, 2); - break; - } + playerSetRace(pPlayer, value); + switch (pPlayer->lifeMode) + { + case kModeHuman: + case kModeBeast: + playerSizeReset(pPlayer); + break; + case kModeHumanShrink: + playerSizeShrink(pPlayer, 2); + break; + case kModeHumanGrown: + playerSizeGrow(pPlayer, 2); + break; + } } //--------------------------------------------------------------------------- @@ -2099,19 +2099,19 @@ void trPlayerCtrlSetRace(int value, PLAYER* pPlayer) // //--------------------------------------------------------------------------- -void trPlayerCtrlSetMoveSpeed(int value, PLAYER* pPlayer) +void trPlayerCtrlSetMoveSpeed(int value, PLAYER* pPlayer) { - int speed = ClipRange(value, 0, 500); - for (int i = 0; i < kModeMax; i++) - { - for (int a = 0; a < kPostureMax; a++) - { - POSTURE* curPosture = &pPlayer->pPosture[i][a]; POSTURE* defPosture = &gPostureDefaults[i][a]; - curPosture->frontAccel = (defPosture->frontAccel * speed) / kPercFull; - curPosture->sideAccel = (defPosture->sideAccel * speed) / kPercFull; - curPosture->backAccel = (defPosture->backAccel * speed) / kPercFull; - } - } + int speed = ClipRange(value, 0, 500); + for (int i = 0; i < kModeMax; i++) + { + for (int a = 0; a < kPostureMax; a++) + { + POSTURE* curPosture = &pPlayer->pPosture[i][a]; POSTURE* defPosture = &gPostureDefaults[i][a]; + curPosture->frontAccel = (defPosture->frontAccel * speed) / kPercFull; + curPosture->sideAccel = (defPosture->sideAccel * speed) / kPercFull; + curPosture->backAccel = (defPosture->backAccel * speed) / kPercFull; + } + } } //--------------------------------------------------------------------------- @@ -2120,15 +2120,15 @@ void trPlayerCtrlSetMoveSpeed(int value, PLAYER* pPlayer) // //--------------------------------------------------------------------------- -void trPlayerCtrlSetJumpHeight(int value, PLAYER* pPlayer) +void trPlayerCtrlSetJumpHeight(int value, PLAYER* pPlayer) { - int jump = ClipRange(value, 0, 500); - for (int i = 0; i < kModeMax; i++) - { - POSTURE* curPosture = &pPlayer->pPosture[i][kPostureStand]; POSTURE* defPosture = &gPostureDefaults[i][kPostureStand]; - curPosture->normalJumpZ = (defPosture->normalJumpZ * jump) / kPercFull; - curPosture->pwupJumpZ = (defPosture->pwupJumpZ * jump) / kPercFull; - } + int jump = ClipRange(value, 0, 500); + for (int i = 0; i < kModeMax; i++) + { + POSTURE* curPosture = &pPlayer->pPosture[i][kPostureStand]; POSTURE* defPosture = &gPostureDefaults[i][kPostureStand]; + curPosture->normalJumpZ = (defPosture->normalJumpZ * jump) / kPercFull; + curPosture->pwupJumpZ = (defPosture->pwupJumpZ * jump) / kPercFull; + } } //--------------------------------------------------------------------------- @@ -2137,40 +2137,40 @@ void trPlayerCtrlSetJumpHeight(int value, PLAYER* pPlayer) // //--------------------------------------------------------------------------- -void trPlayerCtrlSetScreenEffect(int value, int timeval, PLAYER* pPlayer) +void trPlayerCtrlSetScreenEffect(int value, int timeval, PLAYER* pPlayer) { - int eff = ClipLow(value, 0); - int time = (eff > 0) ? timeval : 0; - switch (eff) { - case 0: // clear all - case 1: // tilting - pPlayer->tiltEffect = ClipRange(time, 0, 220); - if (eff) break; - [[fallthrough]]; - case 2: // pain - pPlayer->painEffect = ClipRange(time, 0, 2048); - if (eff) break; - [[fallthrough]]; - case 3: // blind - pPlayer->blindEffect = ClipRange(time, 0, 2048); - if (eff) break; - [[fallthrough]]; - case 4: // pickup - pPlayer->pickupEffect = ClipRange(time, 0, 2048); - if (eff) break; - [[fallthrough]]; - case 5: // quakeEffect - pPlayer->quakeEffect = ClipRange(time, 0, 2048); - if (eff) break; - [[fallthrough]]; - case 6: // visibility - pPlayer->visibility = ClipRange(time, 0, 2048); - if (eff) break; - [[fallthrough]]; - case 7: // delirium - pPlayer->pwUpTime[kPwUpDeliriumShroom] = ClipHigh(time << 1, 432000); - break; - } + int eff = ClipLow(value, 0); + int time = (eff > 0) ? timeval : 0; + switch (eff) { + case 0: // clear all + case 1: // tilting + pPlayer->tiltEffect = ClipRange(time, 0, 220); + if (eff) break; + [[fallthrough]]; + case 2: // pain + pPlayer->painEffect = ClipRange(time, 0, 2048); + if (eff) break; + [[fallthrough]]; + case 3: // blind + pPlayer->blindEffect = ClipRange(time, 0, 2048); + if (eff) break; + [[fallthrough]]; + case 4: // pickup + pPlayer->pickupEffect = ClipRange(time, 0, 2048); + if (eff) break; + [[fallthrough]]; + case 5: // quakeEffect + pPlayer->quakeEffect = ClipRange(time, 0, 2048); + if (eff) break; + [[fallthrough]]; + case 6: // visibility + pPlayer->visibility = ClipRange(time, 0, 2048); + if (eff) break; + [[fallthrough]]; + case 7: // delirium + pPlayer->pwUpTime[kPwUpDeliriumShroom] = ClipHigh(time << 1, 432000); + break; + } } @@ -2182,28 +2182,28 @@ void trPlayerCtrlSetScreenEffect(int value, int timeval, PLAYER* pPlayer) void trPlayerCtrlSetLookAngle(int value, PLAYER* pPlayer) { - double const upAngle = 289; - double const downAngle = -347; - double const lookStepUp = 4.0 * upAngle / 60.0; - double const lookStepDown = -4.0 * downAngle / 60.0; - double const look = value << 5; - double adjustment; + double const upAngle = 289; + double const downAngle = -347; + double const lookStepUp = 4.0 * upAngle / 60.0; + double const lookStepDown = -4.0 * downAngle / 60.0; + double const look = value << 5; + double adjustment; - if (look > 0) - { - adjustment = min(MulScaleF(lookStepUp, look, 8), upAngle); - } - else if (look < 0) - { - adjustment = -max(MulScaleF(lookStepDown, abs(look), 8), downAngle); - } - else - { - adjustment = 0; - } + if (look > 0) + { + adjustment = min(MulScaleF(lookStepUp, look, 8), upAngle); + } + else if (look < 0) + { + adjustment = -max(MulScaleF(lookStepDown, abs(look), 8), downAngle); + } + else + { + adjustment = 0; + } - pPlayer->horizon.settarget(100. * tan(adjustment * pi::pi() / 1024.)); - pPlayer->horizon.lockinput(); + pPlayer->horizon.settarget(100. * tan(adjustment * pi::pi() / 1024.)); + pPlayer->horizon.lockinput(); } //--------------------------------------------------------------------------- @@ -2214,47 +2214,47 @@ void trPlayerCtrlSetLookAngle(int value, PLAYER* pPlayer) void trPlayerCtrlEraseStuff(int value, PLAYER* pPlayer) { - - switch (value) - { - case 0: // erase all - [[fallthrough]]; - case 1: // erase weapons - WeaponLower(pPlayer); - for (int i = 0; i < 14; i++) { - pPlayer->hasWeapon[i] = false; - // also erase ammo - if (i < 12) pPlayer->ammoCount[i] = 0; - } + switch (value) + { + case 0: // erase all + [[fallthrough]]; + case 1: // erase weapons + WeaponLower(pPlayer); - pPlayer->hasWeapon[1] = true; - pPlayer->curWeapon = kWeapNone; - pPlayer->nextWeapon = kWeapPitchFork; + for (int i = 0; i < 14; i++) { + pPlayer->hasWeapon[i] = false; + // also erase ammo + if (i < 12) pPlayer->ammoCount[i] = 0; + } - WeaponRaise(pPlayer); - if (value) break; - [[fallthrough]]; - case 2: // erase all armor - for (int i = 0; i < 3; i++) pPlayer->armor[i] = 0; - if (value) break; - [[fallthrough]]; - case 3: // erase all pack items - for (int i = 0; i < 5; i++) { - pPlayer->packSlots[i].isActive = false; - pPlayer->packSlots[i].curAmount = 0; - } - pPlayer->packItemId = -1; - if (value) break; - [[fallthrough]]; - case 4: // erase all keys - for (int i = 0; i < 8; i++) pPlayer->hasKey[i] = false; - if (value) break; - [[fallthrough]]; - case 5: // erase powerups - for (int i = 0; i < kMaxPowerUps; i++) pPlayer->pwUpTime[i] = 0; - break; - } + pPlayer->hasWeapon[1] = true; + pPlayer->curWeapon = kWeapNone; + pPlayer->nextWeapon = kWeapPitchFork; + + WeaponRaise(pPlayer); + if (value) break; + [[fallthrough]]; + case 2: // erase all armor + for (int i = 0; i < 3; i++) pPlayer->armor[i] = 0; + if (value) break; + [[fallthrough]]; + case 3: // erase all pack items + for (int i = 0; i < 5; i++) { + pPlayer->packSlots[i].isActive = false; + pPlayer->packSlots[i].curAmount = 0; + } + pPlayer->packItemId = -1; + if (value) break; + [[fallthrough]]; + case 4: // erase all keys + for (int i = 0; i < 8; i++) pPlayer->hasKey[i] = false; + if (value) break; + [[fallthrough]]; + case 5: // erase powerups + for (int i = 0; i < kMaxPowerUps; i++) pPlayer->pwUpTime[i] = 0; + break; + } } @@ -2264,67 +2264,68 @@ void trPlayerCtrlEraseStuff(int value, PLAYER* pPlayer) // //--------------------------------------------------------------------------- -void trPlayerCtrlGiveStuff(int data2, int weapon, int data4, PLAYER* pPlayer, TRPLAYERCTRL* pCtrl) +void trPlayerCtrlGiveStuff(int data2, int weapon, int data4, PLAYER* pPlayer, TRPLAYERCTRL* pCtrl) { - switch (data2) - { - case 1: // give N weapon and default ammo for it - case 2: // give just N ammo for selected weapon - if (weapon <= 0 || weapon > 13) - { - Printf(PRINT_HIGH, "Weapon #%d is out of a weapons range!", weapon); - break; - } else if (data2 == 2 && data4 == 0) - { - Printf(PRINT_HIGH, "Zero ammo for weapon #%d is specified!", weapon); - break; - } - switch (weapon) - { - case kWeapProximity: // remote bomb - case kWeapRemote: // prox bomb - pPlayer->hasWeapon[weapon] = true; - weapon--; - pPlayer->ammoCount[weapon] = ClipHigh(pPlayer->ammoCount[weapon] + ((data2 == 2) ? data4 : 1), gAmmoInfo[weapon].max); - weapon++; - break; - default: - for (int i = 0; i < 11; i++) - { - if (gWeaponItemData[i].type != weapon) continue; + switch (data2) + { + case 1: // give N weapon and default ammo for it + case 2: // give just N ammo for selected weapon + if (weapon <= 0 || weapon > 13) + { + Printf(PRINT_HIGH, "Weapon #%d is out of a weapons range!", weapon); + break; + } + else if (data2 == 2 && data4 == 0) + { + Printf(PRINT_HIGH, "Zero ammo for weapon #%d is specified!", weapon); + break; + } + switch (weapon) + { + case kWeapProximity: // remote bomb + case kWeapRemote: // prox bomb + pPlayer->hasWeapon[weapon] = true; + weapon--; + pPlayer->ammoCount[weapon] = ClipHigh(pPlayer->ammoCount[weapon] + ((data2 == 2) ? data4 : 1), gAmmoInfo[weapon].max); + weapon++; + break; + default: + for (int i = 0; i < 11; i++) + { + if (gWeaponItemData[i].type != weapon) continue; - const WEAPONITEMDATA* pWeaponData = &gWeaponItemData[i]; - int nAmmoType = pWeaponData->ammoType; - switch (data2) { - case 1: - pPlayer->hasWeapon[weapon] = true; - if (pPlayer->ammoCount[nAmmoType] >= pWeaponData->count) break; - pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + pWeaponData->count, gAmmoInfo[nAmmoType].max); - break; - case 2: - pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + data4, gAmmoInfo[nAmmoType].max); - break; - } - break; - } - break; - } - if (pPlayer->hasWeapon[weapon] && data4 == 0) // switch on it - { - pPlayer->nextWeapon = kWeapNone; + const WEAPONITEMDATA* pWeaponData = &gWeaponItemData[i]; + int nAmmoType = pWeaponData->ammoType; + switch (data2) { + case 1: + pPlayer->hasWeapon[weapon] = true; + if (pPlayer->ammoCount[nAmmoType] >= pWeaponData->count) break; + pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + pWeaponData->count, gAmmoInfo[nAmmoType].max); + break; + case 2: + pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + data4, gAmmoInfo[nAmmoType].max); + break; + } + break; + } + break; + } + if (pPlayer->hasWeapon[weapon] && data4 == 0) // switch on it + { + pPlayer->nextWeapon = kWeapNone; - if (pPlayer->sceneQav >= 0 && pCtrl->qavScene.initiator && pCtrl->qavScene.initiator->hasX()) - { - pCtrl->qavScene.initiator->xspr.dropMsg = weapon; - } - else if (pPlayer->curWeapon != weapon) - { - pPlayer->newWeapon = weapon; - WeaponRaise(pPlayer); - } - } - break; - } + if (pPlayer->sceneQav >= 0 && pCtrl->qavScene.initiator && pCtrl->qavScene.initiator->hasX()) + { + pCtrl->qavScene.initiator->xspr.dropMsg = weapon; + } + else if (pPlayer->curWeapon != weapon) + { + pPlayer->newWeapon = weapon; + WeaponRaise(pPlayer); + } + } + break; + } } //--------------------------------------------------------------------------- @@ -2335,32 +2336,32 @@ void trPlayerCtrlGiveStuff(int data2, int weapon, int data4, PLAYER* pPlayer, TR void trPlayerCtrlUsePackItem(int data2, int data3, int data4, PLAYER* pPlayer, int evCmd) { - unsigned int invItem = data2 - 1; - switch (evCmd) - { - case kCmdOn: - if (!pPlayer->packSlots[invItem].isActive) packUseItem(pPlayer, invItem); - break; - case kCmdOff: - if (pPlayer->packSlots[invItem].isActive) packUseItem(pPlayer, invItem); - break; - default: - packUseItem(pPlayer, invItem); - break; - } + unsigned int invItem = data2 - 1; + switch (evCmd) + { + case kCmdOn: + if (!pPlayer->packSlots[invItem].isActive) packUseItem(pPlayer, invItem); + break; + case kCmdOff: + if (pPlayer->packSlots[invItem].isActive) packUseItem(pPlayer, invItem); + break; + default: + packUseItem(pPlayer, invItem); + break; + } - switch (data4) - { - case 2: // both - case 0: // switch on it - if (pPlayer->packSlots[invItem].curAmount > 0) pPlayer->packItemId = invItem; - if (!data4) break; - [[fallthrough]]; - case 1: // force remove after use - pPlayer->packSlots[invItem].isActive = false; - pPlayer->packSlots[invItem].curAmount = 0; - break; - } + switch (data4) + { + case 2: // both + case 0: // switch on it + if (pPlayer->packSlots[invItem].curAmount > 0) pPlayer->packItemId = invItem; + if (!data4) break; + [[fallthrough]]; + case 1: // force remove after use + pPlayer->packSlots[invItem].isActive = false; + pPlayer->packSlots[invItem].curAmount = 0; + break; + } } //--------------------------------------------------------------------------- @@ -2372,33 +2373,33 @@ void trPlayerCtrlUsePackItem(int data2, int data3, int data4, PLAYER* pPlayer, i void trPlayerCtrlUsePowerup(DBloodActor* sourceactor, PLAYER* pPlayer, int evCmd) { - bool relative = (sourceactor->spr.flags & kModernTypeFlag1); + bool relative = (sourceactor->spr.flags & kModernTypeFlag1); - int nPower = (kMinAllowedPowerup + sourceactor->xspr.data2) - 1; - int nTime = ClipRange(abs(sourceactor->xspr.data3) * 100, -gPowerUpInfo[nPower].maxTime, gPowerUpInfo[nPower].maxTime); - if (sourceactor->xspr.data3 < 0) - nTime = -nTime; + int nPower = (kMinAllowedPowerup + sourceactor->xspr.data2) - 1; + int nTime = ClipRange(abs(sourceactor->xspr.data3) * 100, -gPowerUpInfo[nPower].maxTime, gPowerUpInfo[nPower].maxTime); + if (sourceactor->xspr.data3 < 0) + nTime = -nTime; - if (pPlayer->pwUpTime[nPower]) - { - if (!relative && nTime <= 0) - powerupDeactivate(pPlayer, nPower); - } + if (pPlayer->pwUpTime[nPower]) + { + if (!relative && nTime <= 0) + powerupDeactivate(pPlayer, nPower); + } - if (nTime != 0) - { - if (pPlayer->pwUpTime[nPower] <= 0) - powerupActivate(pPlayer, nPower); // MUST activate first for powerups like kPwUpDeathMask - - // ...so we able to change time amount - if (relative) pPlayer->pwUpTime[nPower] += nTime; - else pPlayer->pwUpTime[nPower] = nTime; - } + if (nTime != 0) + { + if (pPlayer->pwUpTime[nPower] <= 0) + powerupActivate(pPlayer, nPower); // MUST activate first for powerups like kPwUpDeathMask - if (pPlayer->pwUpTime[nPower] <= 0) - powerupDeactivate(pPlayer, nPower); + // ...so we able to change time amount + if (relative) pPlayer->pwUpTime[nPower] += nTime; + else pPlayer->pwUpTime[nPower] = nTime; + } - return; + if (pPlayer->pwUpTime[nPower] <= 0) + powerupDeactivate(pPlayer, nPower); + + return; } @@ -2408,92 +2409,92 @@ void trPlayerCtrlUsePowerup(DBloodActor* sourceactor, PLAYER* pPlayer, int evCmd // //--------------------------------------------------------------------------- -void useObjResizer(DBloodActor* sourceactor, int targType, sectortype* targSect, walltype* targWall, DBloodActor* targetactor) +void useObjResizer(DBloodActor* sourceactor, int targType, sectortype* targSect, walltype* targWall, DBloodActor* targetactor) { - switch (targType) - { - // for sectors - case OBJ_SECTOR: - if (!targSect) return; - if (valueIsBetween(sourceactor->xspr.data1, -1, 32767)) - targSect->floorxpan_ = (float)ClipRange(sourceactor->xspr.data1, 0, 255); + switch (targType) + { + // for sectors + case OBJ_SECTOR: + if (!targSect) return; + if (valueIsBetween(sourceactor->xspr.data1, -1, 32767)) + targSect->floorxpan_ = (float)ClipRange(sourceactor->xspr.data1, 0, 255); - if (valueIsBetween(sourceactor->xspr.data2, -1, 32767)) - targSect->floorypan_ = (float)ClipRange(sourceactor->xspr.data2, 0, 255); + if (valueIsBetween(sourceactor->xspr.data2, -1, 32767)) + targSect->floorypan_ = (float)ClipRange(sourceactor->xspr.data2, 0, 255); - if (valueIsBetween(sourceactor->xspr.data3, -1, 32767)) - targSect->ceilingxpan_ = (float)ClipRange(sourceactor->xspr.data3, 0, 255); + if (valueIsBetween(sourceactor->xspr.data3, -1, 32767)) + targSect->ceilingxpan_ = (float)ClipRange(sourceactor->xspr.data3, 0, 255); - if (valueIsBetween(sourceactor->xspr.data4, -1, 65535)) - targSect->ceilingypan_ = (float)ClipRange(sourceactor->xspr.data4, 0, 255); - break; - // for sprites - case OBJ_SPRITE: - { - bool fit = false; - // resize by seq scaling - if (sourceactor->spr.flags & kModernTypeFlag1) - { - if (valueIsBetween(sourceactor->xspr.data1, -255, 32767)) - { - int mulDiv = (valueIsBetween(sourceactor->xspr.data2, 0, 257)) ? sourceactor->xspr.data2 : 256; - if (sourceactor->xspr.data1 > 0) targetactor->xspr.scale = mulDiv * ClipHigh(sourceactor->xspr.data1, 25); - else if (sourceactor->xspr.data1 < 0) targetactor->xspr.scale = mulDiv / ClipHigh(abs(sourceactor->xspr.data1), 25); - else targetactor->xspr.scale = 0; - fit = true; - } + if (valueIsBetween(sourceactor->xspr.data4, -1, 65535)) + targSect->ceilingypan_ = (float)ClipRange(sourceactor->xspr.data4, 0, 255); + break; + // for sprites + case OBJ_SPRITE: + { + bool fit = false; + // resize by seq scaling + if (sourceactor->spr.flags & kModernTypeFlag1) + { + if (valueIsBetween(sourceactor->xspr.data1, -255, 32767)) + { + int mulDiv = (valueIsBetween(sourceactor->xspr.data2, 0, 257)) ? sourceactor->xspr.data2 : 256; + if (sourceactor->xspr.data1 > 0) targetactor->xspr.scale = mulDiv * ClipHigh(sourceactor->xspr.data1, 25); + else if (sourceactor->xspr.data1 < 0) targetactor->xspr.scale = mulDiv / ClipHigh(abs(sourceactor->xspr.data1), 25); + else targetactor->xspr.scale = 0; + fit = true; + } - // resize by repeats - } - else - { - if (valueIsBetween(sourceactor->xspr.data1, -1, 32767)) - { - targetactor->spr.xrepeat = ClipRange(sourceactor->xspr.data1, 0, 255); - fit = true; - } - - if (valueIsBetween(sourceactor->xspr.data2, -1, 32767)) - { - targetactor->spr.yrepeat = ClipRange(sourceactor->xspr.data2, 0, 255); - fit = true; - } - } + // resize by repeats + } + else + { + if (valueIsBetween(sourceactor->xspr.data1, -1, 32767)) + { + targetactor->spr.xrepeat = ClipRange(sourceactor->xspr.data1, 0, 255); + fit = true; + } - if (fit && (targetactor->spr.type == kDudeModernCustom || targetactor->spr.type == kDudeModernCustomBurning)) - { - // request properties update for custom dude - - targetactor->genDudeExtra.updReq[kGenDudePropertySpriteSize] = true; - targetactor->genDudeExtra.updReq[kGenDudePropertyAttack] = true; - targetactor->genDudeExtra.updReq[kGenDudePropertyMass] = true; - targetactor->genDudeExtra.updReq[kGenDudePropertyDmgScale] = true; - evPostActor(targetactor, kGenDudeUpdTimeRate, kCallbackGenDudeUpdate); + if (valueIsBetween(sourceactor->xspr.data2, -1, 32767)) + { + targetactor->spr.yrepeat = ClipRange(sourceactor->xspr.data2, 0, 255); + fit = true; + } + } - } + if (fit && (targetactor->spr.type == kDudeModernCustom || targetactor->spr.type == kDudeModernCustomBurning)) + { + // request properties update for custom dude - if (valueIsBetween(sourceactor->xspr.data3, -1, 32767)) - targetactor->spr.xoffset = ClipRange(sourceactor->xspr.data3, 0, 255); + targetactor->genDudeExtra.updReq[kGenDudePropertySpriteSize] = true; + targetactor->genDudeExtra.updReq[kGenDudePropertyAttack] = true; + targetactor->genDudeExtra.updReq[kGenDudePropertyMass] = true; + targetactor->genDudeExtra.updReq[kGenDudePropertyDmgScale] = true; + evPostActor(targetactor, kGenDudeUpdTimeRate, kCallbackGenDudeUpdate); - if (valueIsBetween(sourceactor->xspr.data4, -1, 65535)) - targetactor->spr.yoffset = ClipRange(sourceactor->xspr.data4, 0, 255); - break; - } - case OBJ_WALL: - if (!targWall) return; - if (valueIsBetween(sourceactor->xspr.data1, -1, 32767)) - targWall->xrepeat = ClipRange(sourceactor->xspr.data1, 0, 255); + } - if (valueIsBetween(sourceactor->xspr.data2, -1, 32767)) - targWall->yrepeat = ClipRange(sourceactor->xspr.data2, 0, 255); + if (valueIsBetween(sourceactor->xspr.data3, -1, 32767)) + targetactor->spr.xoffset = ClipRange(sourceactor->xspr.data3, 0, 255); - if (valueIsBetween(sourceactor->xspr.data3, -1, 32767)) - targWall->xpan_ = (float)ClipRange(sourceactor->xspr.data3, 0, 255); + if (valueIsBetween(sourceactor->xspr.data4, -1, 65535)) + targetactor->spr.yoffset = ClipRange(sourceactor->xspr.data4, 0, 255); + break; + } + case OBJ_WALL: + if (!targWall) return; + if (valueIsBetween(sourceactor->xspr.data1, -1, 32767)) + targWall->xrepeat = ClipRange(sourceactor->xspr.data1, 0, 255); - if (valueIsBetween(sourceactor->xspr.data4, -1, 65535)) - targWall->ypan_ = (float)ClipRange(sourceactor->xspr.data4, 0, 255); - break; - } + if (valueIsBetween(sourceactor->xspr.data2, -1, 32767)) + targWall->yrepeat = ClipRange(sourceactor->xspr.data2, 0, 255); + + if (valueIsBetween(sourceactor->xspr.data3, -1, 32767)) + targWall->xpan_ = (float)ClipRange(sourceactor->xspr.data3, 0, 255); + + if (valueIsBetween(sourceactor->xspr.data4, -1, 65535)) + targWall->ypan_ = (float)ClipRange(sourceactor->xspr.data4, 0, 255); + break; + } } //--------------------------------------------------------------------------- @@ -2504,422 +2505,422 @@ void useObjResizer(DBloodActor* sourceactor, int targType, sectortype* targSect, void usePropertiesChanger(DBloodActor* sourceactor, int objType, sectortype* pSector, walltype* pWall, DBloodActor* targetactor) { - switch (objType) - { - case OBJ_WALL: - { - if (!pWall) return; + switch (objType) + { + case OBJ_WALL: + { + if (!pWall) return; - // data3 = set wall hitag - if (valueIsBetween(sourceactor->xspr.data3, -1, 32767)) - { - if ((sourceactor->spr.flags & kModernTypeFlag1)) pWall->hitag |= sourceactor->xspr.data3; - else pWall->hitag = sourceactor->xspr.data3; - } + // data3 = set wall hitag + if (valueIsBetween(sourceactor->xspr.data3, -1, 32767)) + { + if ((sourceactor->spr.flags & kModernTypeFlag1)) pWall->hitag |= sourceactor->xspr.data3; + else pWall->hitag = sourceactor->xspr.data3; + } - // data4 = set wall cstat - if (valueIsBetween(sourceactor->xspr.data4, -1, 65535)) - { - auto old = pWall->cstat; + // data4 = set wall cstat + if (valueIsBetween(sourceactor->xspr.data4, -1, 65535)) + { + auto old = pWall->cstat; - // set new cstat - if ((sourceactor->spr.flags & kModernTypeFlag1)) pWall->cstat |= EWallFlags::FromInt(sourceactor->xspr.data4); // relative - else pWall->cstat = EWallFlags::FromInt(sourceactor->xspr.data4); // absolute + // set new cstat + if ((sourceactor->spr.flags & kModernTypeFlag1)) pWall->cstat |= EWallFlags::FromInt(sourceactor->xspr.data4); // relative + else pWall->cstat = EWallFlags::FromInt(sourceactor->xspr.data4); // absolute - // and hanlde exceptions - pWall->cstat |= old & (CSTAT_WALL_BOTTOM_SWAP | CSTAT_WALL_ALIGN_BOTTOM | CSTAT_WALL_1WAY); - pWall->cstat = (pWall->cstat & ~CSTAT_WALL_MOVE_MASK) | (old & CSTAT_WALL_MOVE_MASK); + // and hanlde exceptions + pWall->cstat |= old & (CSTAT_WALL_BOTTOM_SWAP | CSTAT_WALL_ALIGN_BOTTOM | CSTAT_WALL_1WAY); + pWall->cstat = (pWall->cstat & ~CSTAT_WALL_MOVE_MASK) | (old & CSTAT_WALL_MOVE_MASK); #if 0 - // old code for reference. This does not look right. - if (old & 0xc000) { + // old code for reference. This does not look right. + if (old & 0xc000) { - if (!(pWall->cstat & 0xc000)) - pWall->cstat |= 0xc000; // kWallMoveMask + if (!(pWall->cstat & 0xc000)) + pWall->cstat |= 0xc000; // kWallMoveMask - if ((old & 0x0) && !(pWall->cstat & 0x0)) pWall->cstat |= 0x0; // kWallMoveNone - else if ((old & 0x4000) && !(pWall->cstat & 0x4000)) pWall->cstat |= 0x4000; // kWallMoveForward - else if ((old & 0x8000) && !(pWall->cstat & CSTAT_SPRITE_INVISIBLE)) pWall->cstat |= CSTAT_SPRITE_INVISIBLE; // kWallMoveBackward + if ((old & 0x0) && !(pWall->cstat & 0x0)) pWall->cstat |= 0x0; // kWallMoveNone + else if ((old & 0x4000) && !(pWall->cstat & 0x4000)) pWall->cstat |= 0x4000; // kWallMoveForward + else if ((old & 0x8000) && !(pWall->cstat & CSTAT_SPRITE_INVISIBLE)) pWall->cstat |= CSTAT_SPRITE_INVISIBLE; // kWallMoveBackward - } + } #endif - } - } - break; - case OBJ_SPRITE: - { - bool thing2debris = false; - int old = -1; + } + } + break; + case OBJ_SPRITE: + { + bool thing2debris = false; + int old = -1; - // data3 = set sprite hitag - if (valueIsBetween(sourceactor->xspr.data3, -1, 32767)) - { - old = targetactor->spr.flags; + // data3 = set sprite hitag + if (valueIsBetween(sourceactor->xspr.data3, -1, 32767)) + { + old = targetactor->spr.flags; - // set new hitag - if ((sourceactor->spr.flags & kModernTypeFlag1)) targetactor->spr.flags = sourceactor->spr.flags |= sourceactor->xspr.data3; // relative - else targetactor->spr.flags = sourceactor->xspr.data3; // absolute + // set new hitag + if ((sourceactor->spr.flags & kModernTypeFlag1)) targetactor->spr.flags = sourceactor->spr.flags |= sourceactor->xspr.data3; // relative + else targetactor->spr.flags = sourceactor->xspr.data3; // absolute - // and handle exceptions - if ((old & kHitagFree) && !(targetactor->spr.flags & kHitagFree)) targetactor->spr.flags |= kHitagFree; - if ((old & kHitagRespawn) && !(targetactor->spr.flags & kHitagRespawn)) targetactor->spr.flags |= kHitagRespawn; + // and handle exceptions + if ((old & kHitagFree) && !(targetactor->spr.flags & kHitagFree)) targetactor->spr.flags |= kHitagFree; + if ((old & kHitagRespawn) && !(targetactor->spr.flags & kHitagRespawn)) targetactor->spr.flags |= kHitagRespawn; - // prepare things for different (debris) physics. - if (targetactor->spr.statnum == kStatThing && debrisGetFreeIndex() >= 0) thing2debris = true; + // prepare things for different (debris) physics. + if (targetactor->spr.statnum == kStatThing && debrisGetFreeIndex() >= 0) thing2debris = true; - } + } - // data2 = sprite physics settings - if (valueIsBetween(sourceactor->xspr.data2, -1, 32767) || thing2debris) - { - switch (targetactor->spr.statnum) - { - case kStatDude: // dudes already treating in game - case kStatFree: - case kStatMarker: - case kStatPathMarker: - break; - default: - // store physics attributes in xsprite to avoid setting hitag for modern types! - int flags = (targetactor->xspr.physAttr != 0) ? targetactor->xspr.physAttr : 0; - int oldFlags = flags; + // data2 = sprite physics settings + if (valueIsBetween(sourceactor->xspr.data2, -1, 32767) || thing2debris) + { + switch (targetactor->spr.statnum) + { + case kStatDude: // dudes already treating in game + case kStatFree: + case kStatMarker: + case kStatPathMarker: + break; + default: + // store physics attributes in xsprite to avoid setting hitag for modern types! + int flags = (targetactor->xspr.physAttr != 0) ? targetactor->xspr.physAttr : 0; + int oldFlags = flags; - if (thing2debris) - { - // converting thing to debris - if ((targetactor->spr.flags & kPhysMove) != 0) flags |= kPhysMove; - else flags &= ~kPhysMove; + if (thing2debris) + { + // converting thing to debris + if ((targetactor->spr.flags & kPhysMove) != 0) flags |= kPhysMove; + else flags &= ~kPhysMove; - if ((targetactor->spr.flags & kPhysGravity) != 0) flags |= (kPhysGravity | kPhysFalling); - else flags &= ~(kPhysGravity | kPhysFalling); + if ((targetactor->spr.flags & kPhysGravity) != 0) flags |= (kPhysGravity | kPhysFalling); + else flags &= ~(kPhysGravity | kPhysFalling); - targetactor->spr.flags &= ~(kPhysMove | kPhysGravity | kPhysFalling); - targetactor->xvel = targetactor->yvel = targetactor->zvel = 0; - targetactor->xspr.restState = targetactor->xspr.state; + targetactor->spr.flags &= ~(kPhysMove | kPhysGravity | kPhysFalling); + targetactor->xvel = targetactor->yvel = targetactor->zvel = 0; + targetactor->xspr.restState = targetactor->xspr.state; - } - else - { - // WTF is this?!? - char digits[6] = {}; - snprintf(digits, 6, "%d", sourceactor->xspr.data2); - for (unsigned int i = 0; i < sizeof(digits); i++) - digits[i] = (digits[i] >= 48 && digits[i] <= 57) ? (digits[i] - 57) + 9 : 0; + } + else + { + // WTF is this?!? + char digits[6] = {}; + snprintf(digits, 6, "%d", sourceactor->xspr.data2); + for (unsigned int i = 0; i < sizeof(digits); i++) + digits[i] = (digits[i] >= 48 && digits[i] <= 57) ? (digits[i] - 57) + 9 : 0; - // first digit of data2: set main physics attributes - switch (digits[0]) - { - case 0: - flags &= ~kPhysMove; - flags &= ~(kPhysGravity | kPhysFalling); - break; - case 1: - flags |= kPhysMove; - flags &= ~(kPhysGravity | kPhysFalling); - break; - case 2: - flags &= ~kPhysMove; - flags |= (kPhysGravity | kPhysFalling); - break; - case 3: - flags |= kPhysMove; - flags |= (kPhysGravity | kPhysFalling); - break; - } + // first digit of data2: set main physics attributes + switch (digits[0]) + { + case 0: + flags &= ~kPhysMove; + flags &= ~(kPhysGravity | kPhysFalling); + break; + case 1: + flags |= kPhysMove; + flags &= ~(kPhysGravity | kPhysFalling); + break; + case 2: + flags &= ~kPhysMove; + flags |= (kPhysGravity | kPhysFalling); + break; + case 3: + flags |= kPhysMove; + flags |= (kPhysGravity | kPhysFalling); + break; + } - // second digit of data2: touch physics flags - switch (digits[1]) - { - case 0: - flags &= ~kPhysDebrisTouch; - break; - case 1: - flags |= kPhysDebrisTouch; - break; - } + // second digit of data2: touch physics flags + switch (digits[1]) + { + case 0: + flags &= ~kPhysDebrisTouch; + break; + case 1: + flags |= kPhysDebrisTouch; + break; + } - // third digit of data2: weapon physics flags - switch (digits[2]) - { - case 0: - flags &= ~kPhysDebrisVector; - flags &= ~kPhysDebrisExplode; - break; - case 1: - flags |= kPhysDebrisVector; - flags &= ~kPhysDebrisExplode; - break; - case 2: - flags &= ~kPhysDebrisVector; - flags |= kPhysDebrisExplode; - break; - case 3: - flags |= kPhysDebrisVector; - flags |= kPhysDebrisExplode; - break; - } + // third digit of data2: weapon physics flags + switch (digits[2]) + { + case 0: + flags &= ~kPhysDebrisVector; + flags &= ~kPhysDebrisExplode; + break; + case 1: + flags |= kPhysDebrisVector; + flags &= ~kPhysDebrisExplode; + break; + case 2: + flags &= ~kPhysDebrisVector; + flags |= kPhysDebrisExplode; + break; + case 3: + flags |= kPhysDebrisVector; + flags |= kPhysDebrisExplode; + break; + } - // fourth digit of data2: swimming / flying physics flags - switch (digits[3]) - { - case 0: - flags &= ~kPhysDebrisSwim; - flags &= ~kPhysDebrisFly; - flags &= ~kPhysDebrisFloat; - break; - case 1: - flags |= kPhysDebrisSwim; - flags &= ~kPhysDebrisFly; - flags &= ~kPhysDebrisFloat; - break; - case 2: - flags |= kPhysDebrisSwim; - flags |= kPhysDebrisFloat; - flags &= ~kPhysDebrisFly; - break; - case 3: - flags |= kPhysDebrisFly; - flags &= ~kPhysDebrisSwim; - flags &= ~kPhysDebrisFloat; - break; - case 4: - flags |= kPhysDebrisFly; - flags |= kPhysDebrisFloat; - flags &= ~kPhysDebrisSwim; - break; - case 5: - flags |= kPhysDebrisSwim; - flags |= kPhysDebrisFly; - flags &= ~kPhysDebrisFloat; - break; - case 6: - flags |= kPhysDebrisSwim; - flags |= kPhysDebrisFly; - flags |= kPhysDebrisFloat; - break; - } - } + // fourth digit of data2: swimming / flying physics flags + switch (digits[3]) + { + case 0: + flags &= ~kPhysDebrisSwim; + flags &= ~kPhysDebrisFly; + flags &= ~kPhysDebrisFloat; + break; + case 1: + flags |= kPhysDebrisSwim; + flags &= ~kPhysDebrisFly; + flags &= ~kPhysDebrisFloat; + break; + case 2: + flags |= kPhysDebrisSwim; + flags |= kPhysDebrisFloat; + flags &= ~kPhysDebrisFly; + break; + case 3: + flags |= kPhysDebrisFly; + flags &= ~kPhysDebrisSwim; + flags &= ~kPhysDebrisFloat; + break; + case 4: + flags |= kPhysDebrisFly; + flags |= kPhysDebrisFloat; + flags &= ~kPhysDebrisSwim; + break; + case 5: + flags |= kPhysDebrisSwim; + flags |= kPhysDebrisFly; + flags &= ~kPhysDebrisFloat; + break; + case 6: + flags |= kPhysDebrisSwim; + flags |= kPhysDebrisFly; + flags |= kPhysDebrisFloat; + break; + } + } - int nIndex = debrisGetIndex(targetactor); // check if there is no sprite in list + int nIndex = debrisGetIndex(targetactor); // check if there is no sprite in list - // adding physics sprite in list - if ((flags & kPhysGravity) != 0 || (flags & kPhysMove) != 0) - { + // adding physics sprite in list + if ((flags & kPhysGravity) != 0 || (flags & kPhysMove) != 0) + { - if (oldFlags == 0) - targetactor->xvel = targetactor->yvel = targetactor->zvel = 0; + if (oldFlags == 0) + targetactor->xvel = targetactor->yvel = targetactor->zvel = 0; - if (nIndex != -1) - { - targetactor->xspr.physAttr = flags; // just update physics attributes - } - else if ((nIndex = debrisGetFreeIndex()) < 0) - { - viewSetSystemMessage("Max (%d) Physics affected sprites reached!", kMaxSuperXSprites); - } - else - { - targetactor->xspr.physAttr = flags; // update physics attributes + if (nIndex != -1) + { + targetactor->xspr.physAttr = flags; // just update physics attributes + } + else if ((nIndex = debrisGetFreeIndex()) < 0) + { + viewSetSystemMessage("Max (%d) Physics affected sprites reached!", kMaxSuperXSprites); + } + else + { + targetactor->xspr.physAttr = flags; // update physics attributes - // allow things to became debris, so they use different physics... - if (targetactor->spr.statnum == kStatThing) ChangeActorStat(targetactor, 0); + // allow things to became debris, so they use different physics... + if (targetactor->spr.statnum == kStatThing) ChangeActorStat(targetactor, 0); - // set random goal ang for swimming so they start turning - if ((flags & kPhysDebrisSwim) && !targetactor->xvel && !targetactor->yvel && !targetactor->zvel) - targetactor->xspr.goalAng = (targetactor->spr.ang + Random3(kAng45)) & 2047; - - if (targetactor->xspr.physAttr & kPhysDebrisVector) - targetactor->spr.cstat |= CSTAT_SPRITE_BLOCK_HITSCAN; + // set random goal ang for swimming so they start turning + if ((flags & kPhysDebrisSwim) && !targetactor->xvel && !targetactor->yvel && !targetactor->zvel) + targetactor->xspr.goalAng = (targetactor->spr.ang + Random3(kAng45)) & 2047; - gPhysSpritesList[nIndex] = targetactor; - if (nIndex >= gPhysSpritesCount) gPhysSpritesCount++; - getSpriteMassBySize(targetactor); // create physics cache + if (targetactor->xspr.physAttr & kPhysDebrisVector) + targetactor->spr.cstat |= CSTAT_SPRITE_BLOCK_HITSCAN; - } + gPhysSpritesList[nIndex] = targetactor; + if (nIndex >= gPhysSpritesCount) gPhysSpritesCount++; + getSpriteMassBySize(targetactor); // create physics cache - // removing physics from sprite in list (don't remove sprite from list) - } - else if (nIndex != -1) - { + } - targetactor->xspr.physAttr = flags; - targetactor->xvel = targetactor->yvel = targetactor->zvel = 0; - if (targetactor->spr.lotag >= kThingBase && targetactor->spr.lotag < kThingMax) - ChangeActorStat(targetactor, kStatThing); // if it was a thing - restore statnum - } - break; - } - } + // removing physics from sprite in list (don't remove sprite from list) + } + else if (nIndex != -1) + { - // data4 = sprite cstat - if (valueIsBetween(sourceactor->xspr.data4, -1, 65535)) - { - auto oldstat = targetactor->spr.cstat; + targetactor->xspr.physAttr = flags; + targetactor->xvel = targetactor->yvel = targetactor->zvel = 0; + if (targetactor->spr.lotag >= kThingBase && targetactor->spr.lotag < kThingMax) + ChangeActorStat(targetactor, kStatThing); // if it was a thing - restore statnum + } + break; + } + } - // set new cstat - if ((sourceactor->spr.flags & kModernTypeFlag1)) targetactor->spr.cstat |= ESpriteFlags::FromInt(sourceactor->xspr.data4); // relative - else targetactor->spr.cstat = ESpriteFlags::FromInt(sourceactor->xspr.data4 & 0xffff); // absolute + // data4 = sprite cstat + if (valueIsBetween(sourceactor->xspr.data4, -1, 65535)) + { + auto oldstat = targetactor->spr.cstat; - // and handle exceptions - if ((oldstat & CSTAT_SPRITE_BLOOD_BIT1)) targetactor->spr.cstat |= CSTAT_SPRITE_BLOOD_BIT1; //kSpritePushable - if ((oldstat & CSTAT_SPRITE_YCENTER)) targetactor->spr.cstat |= CSTAT_SPRITE_YCENTER; + // set new cstat + if ((sourceactor->spr.flags & kModernTypeFlag1)) targetactor->spr.cstat |= ESpriteFlags::FromInt(sourceactor->xspr.data4); // relative + else targetactor->spr.cstat = ESpriteFlags::FromInt(sourceactor->xspr.data4 & 0xffff); // absolute - targetactor->spr.cstat |= (oldstat & CSTAT_SPRITE_MOVE_MASK); + // and handle exceptions + if ((oldstat & CSTAT_SPRITE_BLOOD_BIT1)) targetactor->spr.cstat |= CSTAT_SPRITE_BLOOD_BIT1; //kSpritePushable + if ((oldstat & CSTAT_SPRITE_YCENTER)) targetactor->spr.cstat |= CSTAT_SPRITE_YCENTER; + + targetactor->spr.cstat |= (oldstat & CSTAT_SPRITE_MOVE_MASK); #if 0 - // looks very broken. - if (old & 0x6000) - { - if (!(targetactor->spr.cstat & 0x6000)) - targetactor->spr.cstat |= 0x6000; // kSpriteMoveMask + // looks very broken. + if (old & 0x6000) + { + if (!(targetactor->spr.cstat & 0x6000)) + targetactor->spr.cstat |= 0x6000; // kSpriteMoveMask - if ((old & 0x0) && !(targetactor->spr.cstat & 0x0)) targetactor->spr.cstat |= 0x0; // kSpriteMoveNone - else if ((old & 0x2000) && !(targetactor->spr.cstat & 0x2000)) targetactor->spr.cstat |= 0x2000; // kSpriteMoveForward, kSpriteMoveFloor - else if ((old & 0x4000) && !(targetactor->spr.cstat & 0x4000)) targetactor->spr.cstat |= 0x4000; // kSpriteMoveReverse, kSpriteMoveCeiling - } + if ((old & 0x0) && !(targetactor->spr.cstat & 0x0)) targetactor->spr.cstat |= 0x0; // kSpriteMoveNone + else if ((old & 0x2000) && !(targetactor->spr.cstat & 0x2000)) targetactor->spr.cstat |= 0x2000; // kSpriteMoveForward, kSpriteMoveFloor + else if ((old & 0x4000) && !(targetactor->spr.cstat & 0x4000)) targetactor->spr.cstat |= 0x4000; // kSpriteMoveReverse, kSpriteMoveCeiling + } #endif - } - } - break; - case OBJ_SECTOR: - { - if (!pSector) return; - XSECTOR* pXSector = &pSector->xs(); + } + } + break; + case OBJ_SECTOR: + { + if (!pSector) return; + XSECTOR* pXSector = &pSector->xs(); - // data1 = sector underwater status and depth level - if (sourceactor->xspr.data1 >= 0 && sourceactor->xspr.data1 < 2) { - - pXSector->Underwater = (sourceactor->xspr.data1) ? true : false; + // data1 = sector underwater status and depth level + if (sourceactor->xspr.data1 >= 0 && sourceactor->xspr.data1 < 2) { - - auto aLower = barrier_cast(pSector->lowerLink); - DBloodActor* aUpper = nullptr; - if (aLower) - { - // must be sure we found exact same upper link - for (auto& sec: sector) - { - aUpper = barrier_cast(sec.upperLink); - if (aUpper == nullptr || aUpper->xspr.data1 != aLower->xspr.data1) - { - aUpper = nullptr; - continue; - } - break; - } - } - - // treat sectors that have links, so warp can detect underwater status properly - if (aLower) - { - if (pXSector->Underwater) - { - switch (aLower->spr.type) - { - case kMarkerLowStack: - case kMarkerLowLink: - aLower->xspr.sysData1 = aLower->spr.type; - aLower->spr.type = kMarkerLowWater; - break; - default: - if (pSector->ceilingpicnum < 4080 || pSector->ceilingpicnum > 4095) aLower->xspr.sysData1 = kMarkerLowLink; - else aLower->xspr.sysData1 = kMarkerLowStack; - break; - } - } - else if (aLower->xspr.sysData1 > 0) aLower->spr.type = aLower->xspr.sysData1; - else if (pSector->ceilingpicnum < 4080 || pSector->ceilingpicnum > 4095) aLower->spr.type = kMarkerLowLink; - else aLower->spr.type = kMarkerLowStack; - } - - if (aUpper) - { - if (pXSector->Underwater) - { - switch (aUpper->spr.type) - { - case kMarkerUpStack: - case kMarkerUpLink: - aUpper->xspr.sysData1 = aUpper->spr.type; - aUpper->spr.type = kMarkerUpWater; - break; - default: - if (pSector->floorpicnum < 4080 || pSector->floorpicnum > 4095) aUpper->xspr.sysData1 = kMarkerUpLink; - else aUpper->xspr.sysData1 = kMarkerUpStack; - break; - } - } - else if (aUpper->xspr.sysData1 > 0) aUpper->spr.type = aUpper->xspr.sysData1; - else if (pSector->floorpicnum < 4080 || pSector->floorpicnum > 4095) aUpper->spr.type = kMarkerUpLink; - else aUpper->spr.type = kMarkerUpStack; - } - - // search for dudes in this sector and change their underwater status - BloodSectIterator it(pSector); - while (auto iactor = it.Next()) - { - if (iactor->spr.statnum != kStatDude || !iactor->IsDudeActor() || ! iactor->hasX()) - continue; - - PLAYER* pPlayer = getPlayerById(iactor->spr.type); - if (pXSector->Underwater) - { - if (aLower) - iactor->xspr.medium = (aLower->spr.type == kMarkerUpGoo) ? kMediumGoo : kMediumWater; - - if (pPlayer) - { - int waterPal = kMediumWater; - if (aLower) - { - if (aLower->xspr.data2 > 0) waterPal = aLower->xspr.data2; - else if (aLower->spr.type == kMarkerUpGoo) waterPal = kMediumGoo; - } - - pPlayer->nWaterPal = waterPal; - pPlayer->posture = kPostureSwim; - pPlayer->actor->xspr.burnTime = 0; - } - - } - else - { - iactor->xspr.medium = kMediumNormal; - if (pPlayer) - { - pPlayer->posture = (!(pPlayer->input.actions & SB_CROUCH)) ? kPostureStand : kPostureCrouch; - pPlayer->nWaterPal = 0; - } - - } - } - } - else if (sourceactor->xspr.data1 > 9) pXSector->Depth = 7; - else if (sourceactor->xspr.data1 > 1) pXSector->Depth = sourceactor->xspr.data1 - 2; + pXSector->Underwater = (sourceactor->xspr.data1) ? true : false; - // data2 = sector visibility - if (valueIsBetween(sourceactor->xspr.data2, -1, 32767)) - pSector->visibility = ClipRange(sourceactor->xspr.data2, 0 , 234); + auto aLower = barrier_cast(pSector->lowerLink); + DBloodActor* aUpper = nullptr; + if (aLower) + { + // must be sure we found exact same upper link + for (auto& sec : sector) + { + aUpper = barrier_cast(sec.upperLink); + if (aUpper == nullptr || aUpper->xspr.data1 != aLower->xspr.data1) + { + aUpper = nullptr; + continue; + } + break; + } + } - // data3 = sector ceil cstat - if (valueIsBetween(sourceactor->xspr.data3, -1, 32767)) { - if ((sourceactor->spr.flags & kModernTypeFlag1)) pSector->ceilingstat |= ESectorFlags::FromInt(sourceactor->xspr.data3); - else pSector->ceilingstat = ESectorFlags::FromInt(sourceactor->xspr.data3); - } + // treat sectors that have links, so warp can detect underwater status properly + if (aLower) + { + if (pXSector->Underwater) + { + switch (aLower->spr.type) + { + case kMarkerLowStack: + case kMarkerLowLink: + aLower->xspr.sysData1 = aLower->spr.type; + aLower->spr.type = kMarkerLowWater; + break; + default: + if (pSector->ceilingpicnum < 4080 || pSector->ceilingpicnum > 4095) aLower->xspr.sysData1 = kMarkerLowLink; + else aLower->xspr.sysData1 = kMarkerLowStack; + break; + } + } + else if (aLower->xspr.sysData1 > 0) aLower->spr.type = aLower->xspr.sysData1; + else if (pSector->ceilingpicnum < 4080 || pSector->ceilingpicnum > 4095) aLower->spr.type = kMarkerLowLink; + else aLower->spr.type = kMarkerLowStack; + } - // data4 = sector floor cstat - if (valueIsBetween(sourceactor->xspr.data4, -1, 65535)) { - if ((sourceactor->spr.flags & kModernTypeFlag1)) pSector->floorstat |= ESectorFlags::FromInt(sourceactor->xspr.data4); - else pSector->floorstat = ESectorFlags::FromInt(sourceactor->xspr.data4); - } - } - break; - // no TX id - case -1: - // data2 = global visibility - if (valueIsBetween(sourceactor->xspr.data2, -1, 32767)) - gVisibility = ClipRange(sourceactor->xspr.data2, 0, 4096); - break; - } + if (aUpper) + { + if (pXSector->Underwater) + { + switch (aUpper->spr.type) + { + case kMarkerUpStack: + case kMarkerUpLink: + aUpper->xspr.sysData1 = aUpper->spr.type; + aUpper->spr.type = kMarkerUpWater; + break; + default: + if (pSector->floorpicnum < 4080 || pSector->floorpicnum > 4095) aUpper->xspr.sysData1 = kMarkerUpLink; + else aUpper->xspr.sysData1 = kMarkerUpStack; + break; + } + } + else if (aUpper->xspr.sysData1 > 0) aUpper->spr.type = aUpper->xspr.sysData1; + else if (pSector->floorpicnum < 4080 || pSector->floorpicnum > 4095) aUpper->spr.type = kMarkerUpLink; + else aUpper->spr.type = kMarkerUpStack; + } + + // search for dudes in this sector and change their underwater status + BloodSectIterator it(pSector); + while (auto iactor = it.Next()) + { + if (iactor->spr.statnum != kStatDude || !iactor->IsDudeActor() || !iactor->hasX()) + continue; + + PLAYER* pPlayer = getPlayerById(iactor->spr.type); + if (pXSector->Underwater) + { + if (aLower) + iactor->xspr.medium = (aLower->spr.type == kMarkerUpGoo) ? kMediumGoo : kMediumWater; + + if (pPlayer) + { + int waterPal = kMediumWater; + if (aLower) + { + if (aLower->xspr.data2 > 0) waterPal = aLower->xspr.data2; + else if (aLower->spr.type == kMarkerUpGoo) waterPal = kMediumGoo; + } + + pPlayer->nWaterPal = waterPal; + pPlayer->posture = kPostureSwim; + pPlayer->actor->xspr.burnTime = 0; + } + + } + else + { + iactor->xspr.medium = kMediumNormal; + if (pPlayer) + { + pPlayer->posture = (!(pPlayer->input.actions & SB_CROUCH)) ? kPostureStand : kPostureCrouch; + pPlayer->nWaterPal = 0; + } + + } + } + } + else if (sourceactor->xspr.data1 > 9) pXSector->Depth = 7; + else if (sourceactor->xspr.data1 > 1) pXSector->Depth = sourceactor->xspr.data1 - 2; + + + // data2 = sector visibility + if (valueIsBetween(sourceactor->xspr.data2, -1, 32767)) + pSector->visibility = ClipRange(sourceactor->xspr.data2, 0, 234); + + // data3 = sector ceil cstat + if (valueIsBetween(sourceactor->xspr.data3, -1, 32767)) { + if ((sourceactor->spr.flags & kModernTypeFlag1)) pSector->ceilingstat |= ESectorFlags::FromInt(sourceactor->xspr.data3); + else pSector->ceilingstat = ESectorFlags::FromInt(sourceactor->xspr.data3); + } + + // data4 = sector floor cstat + if (valueIsBetween(sourceactor->xspr.data4, -1, 65535)) { + if ((sourceactor->spr.flags & kModernTypeFlag1)) pSector->floorstat |= ESectorFlags::FromInt(sourceactor->xspr.data4); + else pSector->floorstat = ESectorFlags::FromInt(sourceactor->xspr.data4); + } + } + break; + // no TX id + case -1: + // data2 = global visibility + if (valueIsBetween(sourceactor->xspr.data2, -1, 32767)) + gVisibility = ClipRange(sourceactor->xspr.data2, 0, 4096); + break; + } } @@ -2929,126 +2930,126 @@ void usePropertiesChanger(DBloodActor* sourceactor, int objType, sectortype* pSe // //--------------------------------------------------------------------------- -void useTeleportTarget(DBloodActor* sourceactor, DBloodActor* actor) +void useTeleportTarget(DBloodActor* sourceactor, DBloodActor* actor) { - PLAYER* pPlayer = getPlayerById(actor->spr.type); - XSECTOR* pXSector = (sourceactor->spr.sector()->hasX()) ? &sourceactor->spr.sector()->xs() : nullptr; - bool isDude = (!pPlayer && actor->IsDudeActor()); + PLAYER* pPlayer = getPlayerById(actor->spr.type); + XSECTOR* pXSector = (sourceactor->spr.sector()->hasX()) ? &sourceactor->spr.sector()->xs() : nullptr; + bool isDude = (!pPlayer && actor->IsDudeActor()); - if (actor->spr.sector() != sourceactor->spr.sector()) - ChangeActorSect(actor, sourceactor->spr.sector()); + if (actor->spr.sector() != sourceactor->spr.sector()) + ChangeActorSect(actor, sourceactor->spr.sector()); - actor->spr.pos.X = sourceactor->spr.pos.X; actor->spr.pos.Y = sourceactor->spr.pos.Y; - int zTop, zBot; - GetActorExtents(sourceactor, &zTop, &zBot); - actor->spr.pos.Z = zBot; + actor->spr.pos.X = sourceactor->spr.pos.X; actor->spr.pos.Y = sourceactor->spr.pos.Y; + int zTop, zBot; + GetActorExtents(sourceactor, &zTop, &zBot); + actor->spr.pos.Z = zBot; - clampSprite(actor, 0x01); + clampSprite(actor, 0x01); - if (sourceactor->spr.flags & kModernTypeFlag1) // force telefrag - TeleFrag(actor, sourceactor->spr.sector()); + if (sourceactor->spr.flags & kModernTypeFlag1) // force telefrag + TeleFrag(actor, sourceactor->spr.sector()); - if (actor->spr.flags & kPhysGravity) - actor->spr.flags |= kPhysFalling; + if (actor->spr.flags & kPhysGravity) + actor->spr.flags |= kPhysFalling; - if (pXSector) - { + if (pXSector) + { - if (pXSector->Enter && (pPlayer || (isDude && !pXSector->dudeLockout))) - trTriggerSector(sourceactor->spr.sector(), kCmdSectorEnter); + if (pXSector->Enter && (pPlayer || (isDude && !pXSector->dudeLockout))) + trTriggerSector(sourceactor->spr.sector(), kCmdSectorEnter); - if (pXSector->Underwater) - { - DBloodActor* aUpper = nullptr; - auto aLink = barrier_cast(sourceactor->spr.sector()->lowerLink); - if (aLink) - { - // must be sure we found exact same upper link - for(auto& sec: sector) - { - aUpper = barrier_cast(sec.upperLink); - if (aUpper == nullptr || aUpper->xspr.data1 != aLink->xspr.data1) - { - aUpper = nullptr; - continue; - } - break; - } - } + if (pXSector->Underwater) + { + DBloodActor* aUpper = nullptr; + auto aLink = barrier_cast(sourceactor->spr.sector()->lowerLink); + if (aLink) + { + // must be sure we found exact same upper link + for (auto& sec : sector) + { + aUpper = barrier_cast(sec.upperLink); + if (aUpper == nullptr || aUpper->xspr.data1 != aLink->xspr.data1) + { + aUpper = nullptr; + continue; + } + break; + } + } - if (aUpper) - actor->xspr.medium = (aLink->spr.type == kMarkerUpGoo) ? kMediumGoo : kMediumWater; + if (aUpper) + actor->xspr.medium = (aLink->spr.type == kMarkerUpGoo) ? kMediumGoo : kMediumWater; - if (pPlayer) - { - int waterPal = kMediumWater; - if (aUpper) - { - if (aLink->xspr.data2 > 0) waterPal = aLink->xspr.data2; - else if (aLink->spr.type == kMarkerUpGoo) waterPal = kMediumGoo; - } + if (pPlayer) + { + int waterPal = kMediumWater; + if (aUpper) + { + if (aLink->xspr.data2 > 0) waterPal = aLink->xspr.data2; + else if (aLink->spr.type == kMarkerUpGoo) waterPal = kMediumGoo; + } - pPlayer->nWaterPal = waterPal; - pPlayer->posture = kPostureSwim; - pPlayer->actor->xspr.burnTime = 0; - } - } - else - { - actor->xspr.medium = kMediumNormal; - if (pPlayer) - { - pPlayer->posture = (!(pPlayer->input.actions & SB_CROUCH)) ? kPostureStand : kPostureCrouch; - pPlayer->nWaterPal = 0; - } + pPlayer->nWaterPal = waterPal; + pPlayer->posture = kPostureSwim; + pPlayer->actor->xspr.burnTime = 0; + } + } + else + { + actor->xspr.medium = kMediumNormal; + if (pPlayer) + { + pPlayer->posture = (!(pPlayer->input.actions & SB_CROUCH)) ? kPostureStand : kPostureCrouch; + pPlayer->nWaterPal = 0; + } - } - } + } + } - if (actor->spr.statnum == kStatDude && actor->IsDudeActor() && !actor->IsPlayerActor()) - { - int x = actor->xspr.targetX; - int y = actor->xspr.targetY; - int z = actor->xspr.targetZ; - auto target = actor->GetTarget(); - - aiInitSprite(actor); + if (actor->spr.statnum == kStatDude && actor->IsDudeActor() && !actor->IsPlayerActor()) + { + int x = actor->xspr.targetX; + int y = actor->xspr.targetY; + int z = actor->xspr.targetZ; + auto target = actor->GetTarget(); - if (target != nullptr) - { - actor->xspr.targetX = x; - actor->xspr.targetY = y; - actor->xspr.targetZ = z; - actor->SetTarget(target); - aiActivateDude(actor); - } - } + aiInitSprite(actor); - if (sourceactor->xspr.data2 == 1) - { - if (pPlayer) - { - pPlayer->angle.settarget(sourceactor->spr.ang); - pPlayer->angle.lockinput(); - } - else if (isDude) sourceactor->xspr.goalAng = actor->spr.ang = sourceactor->spr.ang; - else actor->spr.ang = sourceactor->spr.ang; - } + if (target != nullptr) + { + actor->xspr.targetX = x; + actor->xspr.targetY = y; + actor->xspr.targetZ = z; + actor->SetTarget(target); + aiActivateDude(actor); + } + } - if (sourceactor->xspr.data3 == 1) - actor->xvel = actor->yvel = actor->zvel = 0; + if (sourceactor->xspr.data2 == 1) + { + if (pPlayer) + { + pPlayer->angle.settarget(sourceactor->spr.ang); + pPlayer->angle.lockinput(); + } + else if (isDude) sourceactor->xspr.goalAng = actor->spr.ang = sourceactor->spr.ang; + else actor->spr.ang = sourceactor->spr.ang; + } - viewBackupSpriteLoc(actor); + if (sourceactor->xspr.data3 == 1) + actor->xvel = actor->yvel = actor->zvel = 0; - if (sourceactor->xspr.data4 > 0) - sfxPlay3DSound(sourceactor, sourceactor->xspr.data4, -1, 0); + viewBackupSpriteLoc(actor); - if (pPlayer) - { - playerResetInertia(pPlayer); - if (sourceactor->xspr.data2 == 1) - pPlayer->zViewVel = pPlayer->zWeaponVel = 0; - } + if (sourceactor->xspr.data4 > 0) + sfxPlay3DSound(sourceactor, sourceactor->xspr.data4, -1, 0); + + if (pPlayer) + { + playerResetInertia(pPlayer); + if (sourceactor->xspr.data2 == 1) + pPlayer->zViewVel = pPlayer->zWeaponVel = 0; + } } //--------------------------------------------------------------------------- @@ -3059,73 +3060,73 @@ void useTeleportTarget(DBloodActor* sourceactor, DBloodActor* actor) void useEffectGen(DBloodActor* sourceactor, DBloodActor* actor) { - if (!actor) actor = sourceactor; + if (!actor) actor = sourceactor; - int fxId = (sourceactor->xspr.data3 <= 0) ? sourceactor->xspr.data2 : sourceactor->xspr.data2 + Random(sourceactor->xspr.data3 + 1); + int fxId = (sourceactor->xspr.data3 <= 0) ? sourceactor->xspr.data2 : sourceactor->xspr.data2 + Random(sourceactor->xspr.data3 + 1); - if (!actor->hasX()) return; - else if (fxId >= kEffectGenCallbackBase) - { - int length = sizeof(gEffectGenCallbacks) / sizeof(gEffectGenCallbacks[0]); - if (fxId < kEffectGenCallbackBase + length) - { - fxId = gEffectGenCallbacks[fxId - kEffectGenCallbackBase]; - evKillActor(actor, (CALLBACK_ID)fxId); - evPostActor(actor, 0, (CALLBACK_ID)fxId); - } - - } - else if (valueIsBetween(fxId, 0, kFXMax)) - { - int pos, top, bottom; - GetActorExtents(actor, &top, &bottom); - DBloodActor* pEffect = nullptr; + if (!actor->hasX()) return; + else if (fxId >= kEffectGenCallbackBase) + { + int length = sizeof(gEffectGenCallbacks) / sizeof(gEffectGenCallbacks[0]); + if (fxId < kEffectGenCallbackBase + length) + { + fxId = gEffectGenCallbacks[fxId - kEffectGenCallbackBase]; + evKillActor(actor, (CALLBACK_ID)fxId); + evPostActor(actor, 0, (CALLBACK_ID)fxId); + } - // select where exactly effect should be spawned - switch (sourceactor->xspr.data4) - { - case 1: - pos = bottom; - break; - case 2: // middle - pos = actor->spr.pos.Z + (tileHeight(actor->spr.picnum) / 2 + tileTopOffset(actor->spr.picnum)); - break; - case 3: - case 4: - if (!actor->spr.insector()) pos = top; - else pos = (sourceactor->xspr.data4 == 3) ? actor->spr.sector()->floorz : actor->spr.sector()->ceilingz; - break; - default: - pos = top; - break; - } + } + else if (valueIsBetween(fxId, 0, kFXMax)) + { + int pos, top, bottom; + GetActorExtents(actor, &top, &bottom); + DBloodActor* pEffect = nullptr; - if ((pEffect = gFX.fxSpawnActor((FX_ID)fxId, actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y, pos, 0)) != NULL) - { - pEffect->SetOwner(sourceactor); + // select where exactly effect should be spawned + switch (sourceactor->xspr.data4) + { + case 1: + pos = bottom; + break; + case 2: // middle + pos = actor->spr.pos.Z + (tileHeight(actor->spr.picnum) / 2 + tileTopOffset(actor->spr.picnum)); + break; + case 3: + case 4: + if (!actor->spr.insector()) pos = top; + else pos = (sourceactor->xspr.data4 == 3) ? actor->spr.sector()->floorz : actor->spr.sector()->ceilingz; + break; + default: + pos = top; + break; + } - if (sourceactor->spr.flags & kModernTypeFlag1) - { - pEffect->spr.pal = sourceactor->spr.pal; - pEffect->spr.xoffset = sourceactor->spr.xoffset; - pEffect->spr.yoffset = sourceactor->spr.yoffset; - pEffect->spr.xrepeat = sourceactor->spr.xrepeat; - pEffect->spr.yrepeat = sourceactor->spr.yrepeat; - pEffect->spr.shade = sourceactor->spr.shade; - } + if ((pEffect = gFX.fxSpawnActor((FX_ID)fxId, actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y, pos, 0)) != NULL) + { + pEffect->SetOwner(sourceactor); - if (sourceactor->spr.flags & kModernTypeFlag2) - { - pEffect->spr.cstat = sourceactor->spr.cstat; - if (pEffect->spr.cstat & CSTAT_SPRITE_INVISIBLE) - pEffect->spr.cstat &= ~CSTAT_SPRITE_INVISIBLE; - } + if (sourceactor->spr.flags & kModernTypeFlag1) + { + pEffect->spr.pal = sourceactor->spr.pal; + pEffect->spr.xoffset = sourceactor->spr.xoffset; + pEffect->spr.yoffset = sourceactor->spr.yoffset; + pEffect->spr.xrepeat = sourceactor->spr.xrepeat; + pEffect->spr.yrepeat = sourceactor->spr.yrepeat; + pEffect->spr.shade = sourceactor->spr.shade; + } - if (pEffect->spr.cstat & CSTAT_SPRITE_ONE_SIDE) - pEffect->spr.cstat &= ~CSTAT_SPRITE_ONE_SIDE; - } - } + if (sourceactor->spr.flags & kModernTypeFlag2) + { + pEffect->spr.cstat = sourceactor->spr.cstat; + if (pEffect->spr.cstat & CSTAT_SPRITE_INVISIBLE) + pEffect->spr.cstat &= ~CSTAT_SPRITE_INVISIBLE; + } + + if (pEffect->spr.cstat & CSTAT_SPRITE_ONE_SIDE) + pEffect->spr.cstat &= ~CSTAT_SPRITE_ONE_SIDE; + } + } } //--------------------------------------------------------------------------- @@ -3134,105 +3135,105 @@ void useEffectGen(DBloodActor* sourceactor, DBloodActor* actor) // //--------------------------------------------------------------------------- -void useSectorWindGen(DBloodActor* sourceactor, sectortype* pSector) +void useSectorWindGen(DBloodActor* sourceactor, sectortype* pSector) { - XSECTOR* pXSector = nullptr; - - if (pSector != nullptr) - { - pXSector = &pSector->xs(); - } - else if (sourceactor->spr.sector()->hasX()) - { - pSector = sourceactor->spr.sector(); - pXSector = &pSector->xs(); - } - else - { - pSector = sourceactor->spr.sector(); - pSector->allocX(); - pXSector = &pSector->xs(); - pXSector->windAlways = 1; - } + XSECTOR* pXSector = nullptr; - int windVel = ClipRange(sourceactor->xspr.data2, 0, 32767); - if ((sourceactor->xspr.data1 & 0x0001)) - windVel = nnExtRandom(0, windVel); - - // process vertical wind in nnExtProcessSuperSprites(); - if ((sourceactor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_FLOOR)) - { - sourceactor->xspr.sysData2 = windVel << 1; - return; - } + if (pSector != nullptr) + { + pXSector = &pSector->xs(); + } + else if (sourceactor->spr.sector()->hasX()) + { + pSector = sourceactor->spr.sector(); + pXSector = &pSector->xs(); + } + else + { + pSector = sourceactor->spr.sector(); + pSector->allocX(); + pXSector = &pSector->xs(); + pXSector->windAlways = 1; + } - pXSector->windVel = windVel; - if ((sourceactor->spr.flags & kModernTypeFlag1)) - pXSector->panAlways = pXSector->windAlways = 1; + int windVel = ClipRange(sourceactor->xspr.data2, 0, 32767); + if ((sourceactor->xspr.data1 & 0x0001)) + windVel = nnExtRandom(0, windVel); - int ang = sourceactor->spr.ang; - if (sourceactor->xspr.data4 <= 0) - { - if ((sourceactor->xspr.data1 & 0x0002)) - { - while (sourceactor->spr.ang == ang) - sourceactor->spr.ang = nnExtRandom(-kAng360, kAng360) & 2047; - } - } - else if (sourceactor->spr.cstat & CSTAT_SPRITE_MOVE_FORWARD) sourceactor->spr.ang += sourceactor->xspr.data4; - else if (sourceactor->spr.cstat & CSTAT_SPRITE_MOVE_REVERSE) sourceactor->spr.ang -= sourceactor->xspr.data4; - else if (sourceactor->xspr.sysData1 == 0) - { - if ((ang += sourceactor->xspr.data4) >= kAng180) sourceactor->xspr.sysData1 = 1; - sourceactor->spr.ang = ClipHigh(ang, kAng180); - } - else - { - if ((ang -= sourceactor->xspr.data4) <= -kAng180) sourceactor->xspr.sysData1 = 0; - sourceactor->spr.ang = ClipLow(ang, -kAng180); - } + // process vertical wind in nnExtProcessSuperSprites(); + if ((sourceactor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_FLOOR)) + { + sourceactor->xspr.sysData2 = windVel << 1; + return; + } - pXSector->windAng = sourceactor->spr.ang; + pXSector->windVel = windVel; + if ((sourceactor->spr.flags & kModernTypeFlag1)) + pXSector->panAlways = pXSector->windAlways = 1; - if (sourceactor->xspr.data3 > 0 && sourceactor->xspr.data3 < 4) - { - switch (sourceactor->xspr.data3) - { - case 1: - pXSector->panFloor = true; - pXSector->panCeiling = false; - break; - case 2: - pXSector->panFloor = false; - pXSector->panCeiling = true; - break; - case 3: - pXSector->panFloor = true; - pXSector->panCeiling = true; - break; - } - if (pXSector->panCeiling) - { - StartInterpolation(pSector, Interp_Sect_CeilingPanX); - StartInterpolation(pSector, Interp_Sect_CeilingPanY); - } - if (pXSector->panFloor) - { - StartInterpolation(pSector, Interp_Sect_FloorPanX); - StartInterpolation(pSector, Interp_Sect_FloorPanY); - } + int ang = sourceactor->spr.ang; + if (sourceactor->xspr.data4 <= 0) + { + if ((sourceactor->xspr.data1 & 0x0002)) + { + while (sourceactor->spr.ang == ang) + sourceactor->spr.ang = nnExtRandom(-kAng360, kAng360) & 2047; + } + } + else if (sourceactor->spr.cstat & CSTAT_SPRITE_MOVE_FORWARD) sourceactor->spr.ang += sourceactor->xspr.data4; + else if (sourceactor->spr.cstat & CSTAT_SPRITE_MOVE_REVERSE) sourceactor->spr.ang -= sourceactor->xspr.data4; + else if (sourceactor->xspr.sysData1 == 0) + { + if ((ang += sourceactor->xspr.data4) >= kAng180) sourceactor->xspr.sysData1 = 1; + sourceactor->spr.ang = ClipHigh(ang, kAng180); + } + else + { + if ((ang -= sourceactor->xspr.data4) <= -kAng180) sourceactor->xspr.sysData1 = 0; + sourceactor->spr.ang = ClipLow(ang, -kAng180); + } - int oldPan = pXSector->panVel; - pXSector->panAngle = pXSector->windAng; - pXSector->panVel = pXSector->windVel; + pXSector->windAng = sourceactor->spr.ang; - // add to panList if panVel was set to 0 previously - if (oldPan == 0 && pXSector->panVel != 0) - { - if (!panList.Contains(pSector)) - panList.Push(pSector); - } - } + if (sourceactor->xspr.data3 > 0 && sourceactor->xspr.data3 < 4) + { + switch (sourceactor->xspr.data3) + { + case 1: + pXSector->panFloor = true; + pXSector->panCeiling = false; + break; + case 2: + pXSector->panFloor = false; + pXSector->panCeiling = true; + break; + case 3: + pXSector->panFloor = true; + pXSector->panCeiling = true; + break; + } + if (pXSector->panCeiling) + { + StartInterpolation(pSector, Interp_Sect_CeilingPanX); + StartInterpolation(pSector, Interp_Sect_CeilingPanY); + } + if (pXSector->panFloor) + { + StartInterpolation(pSector, Interp_Sect_FloorPanX); + StartInterpolation(pSector, Interp_Sect_FloorPanY); + } + + int oldPan = pXSector->panVel; + pXSector->panAngle = pXSector->windAng; + pXSector->panVel = pXSector->windVel; + + // add to panList if panVel was set to 0 previously + if (oldPan == 0 && pXSector->panVel != 0) + { + if (!panList.Contains(pSector)) + panList.Push(pSector); + } + } } //--------------------------------------------------------------------------- @@ -3243,65 +3244,65 @@ void useSectorWindGen(DBloodActor* sourceactor, sectortype* pSector) void useSpriteDamager(DBloodActor* sourceactor, int objType, sectortype* targSect, DBloodActor* targetactor) { - sectortype* pSector = sourceactor->spr.sector(); + sectortype* pSector = sourceactor->spr.sector(); - int top, bottom; - bool floor, ceil, wall, enter; + int top, bottom; + bool floor, ceil, wall, enter; - switch (objType) - { - case OBJ_SPRITE: - damageSprites(sourceactor, targetactor); - break; - case OBJ_SECTOR: - { - GetActorExtents(sourceactor, &top, &bottom); - floor = (bottom >= pSector->floorz); - ceil = (top <= pSector->ceilingz); - wall = (sourceactor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_WALL); - enter = (!floor && !ceil && !wall); - BloodSectIterator it(targSect); - while (auto iactor = it.Next()) - { - auto& hit = iactor->hit; + switch (objType) + { + case OBJ_SPRITE: + damageSprites(sourceactor, targetactor); + break; + case OBJ_SECTOR: + { + GetActorExtents(sourceactor, &top, &bottom); + floor = (bottom >= pSector->floorz); + ceil = (top <= pSector->ceilingz); + wall = (sourceactor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_WALL); + enter = (!floor && !ceil && !wall); + BloodSectIterator it(targSect); + while (auto iactor = it.Next()) + { + auto& hit = iactor->hit; - if (!iactor->IsDudeActor() || !iactor->hasX()) - continue; - else if (enter) - damageSprites(sourceactor, iactor); - else if (floor && hit.florhit.type == kHitSector && hit.florhit.hitSector == targSect) - damageSprites(sourceactor, iactor); - else if (ceil && hit.ceilhit.type == kHitSector && hit.ceilhit.hitSector == targSect) - damageSprites(sourceactor, iactor); - else if (wall && hit.hit.type == kHitWall && hit.hit.hitWall->sectorp() == targSect) - damageSprites(sourceactor, iactor); - } - break; - } - case -1: - { - BloodStatIterator it(kStatDude); - while (auto iactor = it.Next()) - { - if (iactor->spr.statnum != kStatDude) continue; - switch (sourceactor->xspr.data1) - { - case 667: - if (iactor->IsPlayerActor()) continue; - damageSprites(sourceactor, iactor); - break; - case 668: - if (iactor->IsPlayerActor()) continue; - damageSprites(sourceactor, iactor); - break; - default: - damageSprites(sourceactor, iactor); - break; - } - } - break; - } - } + if (!iactor->IsDudeActor() || !iactor->hasX()) + continue; + else if (enter) + damageSprites(sourceactor, iactor); + else if (floor && hit.florhit.type == kHitSector && hit.florhit.hitSector == targSect) + damageSprites(sourceactor, iactor); + else if (ceil && hit.ceilhit.type == kHitSector && hit.ceilhit.hitSector == targSect) + damageSprites(sourceactor, iactor); + else if (wall && hit.hit.type == kHitWall && hit.hit.hitWall->sectorp() == targSect) + damageSprites(sourceactor, iactor); + } + break; + } + case -1: + { + BloodStatIterator it(kStatDude); + while (auto iactor = it.Next()) + { + if (iactor->spr.statnum != kStatDude) continue; + switch (sourceactor->xspr.data1) + { + case 667: + if (iactor->IsPlayerActor()) continue; + damageSprites(sourceactor, iactor); + break; + case 668: + if (iactor->IsPlayerActor()) continue; + damageSprites(sourceactor, iactor); + break; + default: + damageSprites(sourceactor, iactor); + break; + } + } + break; + } + } } //--------------------------------------------------------------------------- @@ -3311,105 +3312,105 @@ void useSpriteDamager(DBloodActor* sourceactor, int objType, sectortype* targSec //--------------------------------------------------------------------------- -void damageSprites(DBloodActor* sourceactor, DBloodActor* actor) +void damageSprites(DBloodActor* sourceactor, DBloodActor* actor) { - if (!actor->IsDudeActor() || !actor->hasX() || actor->xspr.health <= 0 || sourceactor->xspr.data3 < 0) - return; - + if (!actor->IsDudeActor() || !actor->hasX() || actor->xspr.health <= 0 || sourceactor->xspr.data3 < 0) + return; - int health = 0; - PLAYER* pPlayer = getPlayerById(actor->spr.type); - int dmgType = (sourceactor->xspr.data2 >= kDmgFall) ? ClipHigh(sourceactor->xspr.data2, kDmgElectric) : -1; - int dmg = actor->xspr.health << 4; - int armor[3]; + int health = 0; - bool godMode = (pPlayer && ((dmgType >= 0 && pPlayer->damageControl[dmgType]) || powerupCheck(pPlayer, kPwUpDeathMask) || pPlayer->godMode)); // kneeling + PLAYER* pPlayer = getPlayerById(actor->spr.type); + int dmgType = (sourceactor->xspr.data2 >= kDmgFall) ? ClipHigh(sourceactor->xspr.data2, kDmgElectric) : -1; + int dmg = actor->xspr.health << 4; + int armor[3]; - if (godMode || actor->xspr.locked) return; - else if (sourceactor->xspr.data3) - { - if (sourceactor->spr.flags & kModernTypeFlag1) dmg = ClipHigh(sourceactor->xspr.data3 << 1, 65535); - else if (actor->xspr.sysData2 > 0) dmg = (ClipHigh(actor->xspr.sysData2 << 4, 65535) * sourceactor->xspr.data3) / kPercFull; - else dmg = ((getDudeInfo(actor->spr.type)->startHealth << 4) * sourceactor->xspr.data3) / kPercFull; + bool godMode = (pPlayer && ((dmgType >= 0 && pPlayer->damageControl[dmgType]) || powerupCheck(pPlayer, kPwUpDeathMask) || pPlayer->godMode)); // kneeling - health = actor->xspr.health - dmg; - } + if (godMode || actor->xspr.locked) return; + else if (sourceactor->xspr.data3) + { + if (sourceactor->spr.flags & kModernTypeFlag1) dmg = ClipHigh(sourceactor->xspr.data3 << 1, 65535); + else if (actor->xspr.sysData2 > 0) dmg = (ClipHigh(actor->xspr.sysData2 << 4, 65535) * sourceactor->xspr.data3) / kPercFull; + else dmg = ((getDudeInfo(actor->spr.type)->startHealth << 4) * sourceactor->xspr.data3) / kPercFull; - if (dmgType >= kDmgFall) - { - if (dmg < (int)actor->xspr.health << 4) - { - if (!nnExtIsImmune(actor, dmgType, 0)) - { - if (pPlayer) - { - playerDamageArmor(pPlayer, (DAMAGE_TYPE)dmgType, dmg); - for (int i = 0; i < 3; armor[i] = pPlayer->armor[i], pPlayer->armor[i] = 0, i++); - actDamageSprite(sourceactor, actor, (DAMAGE_TYPE)dmgType, dmg); - for (int i = 0; i < 3; pPlayer->armor[i] = armor[i], i++); + health = actor->xspr.health - dmg; + } - } - else - { - actDamageSprite(sourceactor, actor, (DAMAGE_TYPE)dmgType, dmg); - } - } - else - { - //Printf(PRINT_HIGH, "Dude type %d is immune to damage type %d!", actor->spr.type, dmgType); - } - } - else if (!pPlayer) actKillDude(sourceactor, actor, (DAMAGE_TYPE)dmgType, dmg); - else playerDamageSprite(sourceactor, pPlayer, (DAMAGE_TYPE)dmgType, dmg); - } - else if ((actor->xspr.health = ClipLow(health, 1)) > 16); - else if (!pPlayer) actKillDude(sourceactor, actor, kDamageBullet, dmg); - else playerDamageSprite(sourceactor, pPlayer, kDamageBullet, dmg); + if (dmgType >= kDmgFall) + { + if (dmg < (int)actor->xspr.health << 4) + { + if (!nnExtIsImmune(actor, dmgType, 0)) + { + if (pPlayer) + { + playerDamageArmor(pPlayer, (DAMAGE_TYPE)dmgType, dmg); + for (int i = 0; i < 3; armor[i] = pPlayer->armor[i], pPlayer->armor[i] = 0, i++); + actDamageSprite(sourceactor, actor, (DAMAGE_TYPE)dmgType, dmg); + for (int i = 0; i < 3; pPlayer->armor[i] = armor[i], i++); - if (actor->xspr.health > 0) - { - if (!(sourceactor->spr.flags & kModernTypeFlag8)) - actor->xspr.health = health; - - bool showEffects = !(sourceactor->spr.flags & kModernTypeFlag2); // show it by default - bool forceRecoil = (sourceactor->spr.flags & kModernTypeFlag4); - - if (showEffects) - { - switch (dmgType) - { - case kDmgBurn: - if (actor->xspr.burnTime > 0) break; - actBurnSprite(sourceactor, actor, ClipLow(dmg >> 1, 128)); - evKillActor(actor, kCallbackFXFlameLick); - evPostActor(actor, 0, kCallbackFXFlameLick); // show flames - break; - case kDmgElectric: - forceRecoil = true; // show tesla recoil animation - break; - case kDmgBullet: - evKillActor(actor, kCallbackFXBloodSpurt); - for (int i = 1; i < 6; i++) - { - if (Chance(0x16000 >> i)) - fxSpawnBlood(actor, dmg << 4); - } - break; - case kDmgChoke: - if (!pPlayer || !Chance(0x2000)) break; - else pPlayer->blindEffect += dmg << 2; - } - } + } + else + { + actDamageSprite(sourceactor, actor, (DAMAGE_TYPE)dmgType, dmg); + } + } + else + { + //Printf(PRINT_HIGH, "Dude type %d is immune to damage type %d!", actor->spr.type, dmgType); + } + } + else if (!pPlayer) actKillDude(sourceactor, actor, (DAMAGE_TYPE)dmgType, dmg); + else playerDamageSprite(sourceactor, pPlayer, (DAMAGE_TYPE)dmgType, dmg); + } + else if ((actor->xspr.health = ClipLow(health, 1)) > 16); + else if (!pPlayer) actKillDude(sourceactor, actor, kDamageBullet, dmg); + else playerDamageSprite(sourceactor, pPlayer, kDamageBullet, dmg); - if (forceRecoil && !pPlayer) - { - actor->xspr.data3 = 32767; - actor->dudeExtra.teslaHit = (dmgType == kDmgElectric) ? 1 : 0; - if (actor->xspr.aiState->stateType != kAiStateRecoil) - RecoilDude(actor); - } - } + if (actor->xspr.health > 0) + { + if (!(sourceactor->spr.flags & kModernTypeFlag8)) + actor->xspr.health = health; + + bool showEffects = !(sourceactor->spr.flags & kModernTypeFlag2); // show it by default + bool forceRecoil = (sourceactor->spr.flags & kModernTypeFlag4); + + if (showEffects) + { + switch (dmgType) + { + case kDmgBurn: + if (actor->xspr.burnTime > 0) break; + actBurnSprite(sourceactor, actor, ClipLow(dmg >> 1, 128)); + evKillActor(actor, kCallbackFXFlameLick); + evPostActor(actor, 0, kCallbackFXFlameLick); // show flames + break; + case kDmgElectric: + forceRecoil = true; // show tesla recoil animation + break; + case kDmgBullet: + evKillActor(actor, kCallbackFXBloodSpurt); + for (int i = 1; i < 6; i++) + { + if (Chance(0x16000 >> i)) + fxSpawnBlood(actor, dmg << 4); + } + break; + case kDmgChoke: + if (!pPlayer || !Chance(0x2000)) break; + else pPlayer->blindEffect += dmg << 2; + } + } + + if (forceRecoil && !pPlayer) + { + actor->xspr.data3 = 32767; + actor->dudeExtra.teslaHit = (dmgType == kDmgElectric) ? 1 : 0; + if (actor->xspr.aiState->stateType != kAiStateRecoil) + RecoilDude(actor); + } + } } //--------------------------------------------------------------------------- @@ -3418,149 +3419,149 @@ void damageSprites(DBloodActor* sourceactor, DBloodActor* actor) // //--------------------------------------------------------------------------- -void useSeqSpawnerGen(DBloodActor* sourceactor, int objType, sectortype* pSector, walltype* pWall, DBloodActor* iactor) +void useSeqSpawnerGen(DBloodActor* sourceactor, int objType, sectortype* pSector, walltype* pWall, DBloodActor* iactor) { - if (sourceactor->xspr.data2 > 0 && !getSequence(sourceactor->xspr.data2)) - { - Printf(PRINT_HIGH, "Missing sequence #%d", sourceactor->xspr.data2); - return; - } + if (sourceactor->xspr.data2 > 0 && !getSequence(sourceactor->xspr.data2)) + { + Printf(PRINT_HIGH, "Missing sequence #%d", sourceactor->xspr.data2); + return; + } - switch (objType) - { - case OBJ_SECTOR: - { - if (sourceactor->xspr.data2 <= 0) - { - if (sourceactor->xspr.data3 == 3 || sourceactor->xspr.data3 == 1) - seqKill(SS_FLOOR, pSector); - if (sourceactor->xspr.data3 == 3 || sourceactor->xspr.data3 == 2) - seqKill(SS_CEILING, pSector); - } - else - { - if (sourceactor->xspr.data3 == 3 || sourceactor->xspr.data3 == 1) - seqSpawn(sourceactor->xspr.data2, SS_FLOOR, pSector, -1); - if (sourceactor->xspr.data3 == 3 || sourceactor->xspr.data3 == 2) - seqSpawn(sourceactor->xspr.data2, SS_CEILING, pSector, -1); - } - return; - } - case OBJ_WALL: - { - if (sourceactor->xspr.data2 <= 0) - { - if (sourceactor->xspr.data3 == 3 || sourceactor->xspr.data3 == 1) - seqKill(SS_WALL, pWall); - if ((sourceactor->xspr.data3 == 3 || sourceactor->xspr.data3 == 2) && (pWall->cstat & CSTAT_WALL_MASKED)) - seqKill(SS_MASKED, pWall); - } - else - { - if (sourceactor->xspr.data3 == 3 || sourceactor->xspr.data3 == 1) - seqSpawn(sourceactor->xspr.data2, SS_WALL, pWall, -1); + switch (objType) + { + case OBJ_SECTOR: + { + if (sourceactor->xspr.data2 <= 0) + { + if (sourceactor->xspr.data3 == 3 || sourceactor->xspr.data3 == 1) + seqKill(SS_FLOOR, pSector); + if (sourceactor->xspr.data3 == 3 || sourceactor->xspr.data3 == 2) + seqKill(SS_CEILING, pSector); + } + else + { + if (sourceactor->xspr.data3 == 3 || sourceactor->xspr.data3 == 1) + seqSpawn(sourceactor->xspr.data2, SS_FLOOR, pSector, -1); + if (sourceactor->xspr.data3 == 3 || sourceactor->xspr.data3 == 2) + seqSpawn(sourceactor->xspr.data2, SS_CEILING, pSector, -1); + } + return; + } + case OBJ_WALL: + { + if (sourceactor->xspr.data2 <= 0) + { + if (sourceactor->xspr.data3 == 3 || sourceactor->xspr.data3 == 1) + seqKill(SS_WALL, pWall); + if ((sourceactor->xspr.data3 == 3 || sourceactor->xspr.data3 == 2) && (pWall->cstat & CSTAT_WALL_MASKED)) + seqKill(SS_MASKED, pWall); + } + else + { + if (sourceactor->xspr.data3 == 3 || sourceactor->xspr.data3 == 1) + seqSpawn(sourceactor->xspr.data2, SS_WALL, pWall, -1); - if (sourceactor->xspr.data3 == 3 || sourceactor->xspr.data3 == 2) { + if (sourceactor->xspr.data3 == 3 || sourceactor->xspr.data3 == 2) { - if (!pWall->twoSided()) { - if (sourceactor->xspr.data3 == 3) - seqSpawn(sourceactor->xspr.data2, SS_WALL, pWall, -1); + if (!pWall->twoSided()) { + if (sourceactor->xspr.data3 == 3) + seqSpawn(sourceactor->xspr.data2, SS_WALL, pWall, -1); - } - else { - if (!(pWall->cstat & CSTAT_WALL_MASKED)) - pWall->cstat |= CSTAT_WALL_MASKED; + } + else { + if (!(pWall->cstat & CSTAT_WALL_MASKED)) + pWall->cstat |= CSTAT_WALL_MASKED; - seqSpawn(sourceactor->xspr.data2, SS_MASKED, pWall, -1); - } - } + seqSpawn(sourceactor->xspr.data2, SS_MASKED, pWall, -1); + } + } - if (sourceactor->xspr.data4 > 0) - { - int cx, cy, cz; - cx = (pWall->pos.X + pWall->point2Wall()->pos.X) >> 1; - cy = (pWall->pos.Y + pWall->point2Wall()->pos.Y) >> 1; - auto pMySector = pWall->sectorp(); - int32_t ceilZ, floorZ; - getzsofslopeptr(pSector, cx, cy, &ceilZ, &floorZ); - int32_t ceilZ2, floorZ2; - getzsofslopeptr(pWall->nextSector(), cx, cy, &ceilZ2, &floorZ2); - ceilZ = ClipLow(ceilZ, ceilZ2); - floorZ = ClipHigh(floorZ, floorZ2); - cz = (ceilZ + floorZ) >> 1; + if (sourceactor->xspr.data4 > 0) + { + int cx, cy, cz; + cx = (pWall->pos.X + pWall->point2Wall()->pos.X) >> 1; + cy = (pWall->pos.Y + pWall->point2Wall()->pos.Y) >> 1; + auto pMySector = pWall->sectorp(); + int32_t ceilZ, floorZ; + getzsofslopeptr(pSector, cx, cy, &ceilZ, &floorZ); + int32_t ceilZ2, floorZ2; + getzsofslopeptr(pWall->nextSector(), cx, cy, &ceilZ2, &floorZ2); + ceilZ = ClipLow(ceilZ, ceilZ2); + floorZ = ClipHigh(floorZ, floorZ2); + cz = (ceilZ + floorZ) >> 1; - sfxPlay3DSound(cx, cy, cz, sourceactor->xspr.data4, pSector); - } - } - return; - } - case OBJ_SPRITE: - { - if (sourceactor->xspr.data2 <= 0) seqKill(iactor); - else if (iactor->spr.insector()) - { - if (sourceactor->xspr.data3 > 0) - { - auto spawned = InsertSprite(iactor->spr.sector(), kStatDecoration); - int top, bottom; GetActorExtents(spawned, &top, &bottom); - spawned->spr.pos.X = iactor->spr.pos.X; - spawned->spr.pos.Y = iactor->spr.pos.Y; - switch (sourceactor->xspr.data3) - { - default: - spawned->spr.pos.Z = iactor->spr.pos.Z; - break; - case 2: - spawned->spr.pos.Z = bottom; - break; - case 3: - spawned->spr.pos.Z = top; - break; - case 4: - spawned->spr.pos.Z = iactor->spr.pos.Z + tileHeight(iactor->spr.picnum) / 2 + tileTopOffset(iactor->spr.picnum); - break; - case 5: - case 6: - if (!iactor->spr.insector()) spawned->spr.pos.Z = top; - else spawned->spr.pos.Z = (sourceactor->xspr.data3 == 5) ? spawned->sector()->floorz : spawned->sector()->ceilingz; - break; - } + sfxPlay3DSound(cx, cy, cz, sourceactor->xspr.data4, pSector); + } + } + return; + } + case OBJ_SPRITE: + { + if (sourceactor->xspr.data2 <= 0) seqKill(iactor); + else if (iactor->spr.insector()) + { + if (sourceactor->xspr.data3 > 0) + { + auto spawned = InsertSprite(iactor->spr.sector(), kStatDecoration); + int top, bottom; GetActorExtents(spawned, &top, &bottom); + spawned->spr.pos.X = iactor->spr.pos.X; + spawned->spr.pos.Y = iactor->spr.pos.Y; + switch (sourceactor->xspr.data3) + { + default: + spawned->spr.pos.Z = iactor->spr.pos.Z; + break; + case 2: + spawned->spr.pos.Z = bottom; + break; + case 3: + spawned->spr.pos.Z = top; + break; + case 4: + spawned->spr.pos.Z = iactor->spr.pos.Z + tileHeight(iactor->spr.picnum) / 2 + tileTopOffset(iactor->spr.picnum); + break; + case 5: + case 6: + if (!iactor->spr.insector()) spawned->spr.pos.Z = top; + else spawned->spr.pos.Z = (sourceactor->xspr.data3 == 5) ? spawned->sector()->floorz : spawned->sector()->ceilingz; + break; + } - if (spawned != nullptr) - { + if (spawned != nullptr) + { - spawned->addX(); - seqSpawn(sourceactor->xspr.data2, spawned, -1); - if (sourceactor->spr.flags & kModernTypeFlag1) - { - spawned->spr.pal = sourceactor->spr.pal; - spawned->spr.shade = sourceactor->spr.shade; - spawned->spr.xrepeat = sourceactor->spr.xrepeat; - spawned->spr.yrepeat = sourceactor->spr.yrepeat; - spawned->spr.xoffset = sourceactor->spr.xoffset; - spawned->spr.yoffset = sourceactor->spr.yoffset; - } + spawned->addX(); + seqSpawn(sourceactor->xspr.data2, spawned, -1); + if (sourceactor->spr.flags & kModernTypeFlag1) + { + spawned->spr.pal = sourceactor->spr.pal; + spawned->spr.shade = sourceactor->spr.shade; + spawned->spr.xrepeat = sourceactor->spr.xrepeat; + spawned->spr.yrepeat = sourceactor->spr.yrepeat; + spawned->spr.xoffset = sourceactor->spr.xoffset; + spawned->spr.yoffset = sourceactor->spr.yoffset; + } - if (sourceactor->spr.flags & kModernTypeFlag2) - { - spawned->spr.cstat |= sourceactor->spr.cstat; - } + if (sourceactor->spr.flags & kModernTypeFlag2) + { + spawned->spr.cstat |= sourceactor->spr.cstat; + } - // should be: the more is seqs, the shorter is timer - evPostActor(spawned, 1000, kCallbackRemove); - } - } - else - { - seqSpawn(sourceactor->xspr.data2, iactor, -1); - } + // should be: the more is seqs, the shorter is timer + evPostActor(spawned, 1000, kCallbackRemove); + } + } + else + { + seqSpawn(sourceactor->xspr.data2, iactor, -1); + } - if (sourceactor->xspr.data4 > 0) - sfxPlay3DSound(iactor, sourceactor->xspr.data4, -1, 0); - } - return; - } - } + if (sourceactor->xspr.data4 > 0) + sfxPlay3DSound(iactor, sourceactor->xspr.data4, -1, 0); + } + return; + } + } } //--------------------------------------------------------------------------- @@ -3577,25 +3578,25 @@ EventObject condGet(DBloodActor* actor) { return actor->condition[0]; } void condBackup(DBloodActor* actor) { - actor->condition[1] = actor->condition[0]; + actor->condition[1] = actor->condition[0]; } void condRestore(DBloodActor* actor) { - actor->condition[0] = actor->condition[1]; + actor->condition[0] = actor->condition[1]; } // normal comparison -bool condCmp(int val, int arg1, int arg2, int comOp) +bool condCmp(int val, int arg1, int arg2, int comOp) { - if (comOp & 0x2000) return (comOp & CSTAT_SPRITE_BLOCK) ? (val > arg1) : (val >= arg1); // blue sprite - else if (comOp & 0x4000) return (comOp & CSTAT_SPRITE_BLOCK) ? (val < arg1) : (val <= arg1); // green sprite - else if (comOp & CSTAT_SPRITE_BLOCK) - { - if (arg1 > arg2) I_Error("Value of argument #1 (%d) must be less than value of argument #2 (%d)", arg1, arg2); - return (val >= arg1 && val <= arg2); - } - else return (val == arg1); + if (comOp & 0x2000) return (comOp & CSTAT_SPRITE_BLOCK) ? (val > arg1) : (val >= arg1); // blue sprite + else if (comOp & 0x4000) return (comOp & CSTAT_SPRITE_BLOCK) ? (val < arg1) : (val <= arg1); // green sprite + else if (comOp & CSTAT_SPRITE_BLOCK) + { + if (arg1 > arg2) I_Error("Value of argument #1 (%d) must be less than value of argument #2 (%d)", arg1, arg2); + return (val >= arg1 && val <= arg2); + } + else return (val == arg1); } //--------------------------------------------------------------------------- @@ -3606,22 +3607,22 @@ bool condCmp(int val, int arg1, int arg2, int comOp) void condError(DBloodActor* aCond, const char* pzFormat, ...) { - char buffer[256]; - char buffer2[512]; - FString condType = "Unknown"; - for (int i = 0; i < 7; i++) - { - if (aCond->xspr.data1 < gCondTypeNames[i].rng1 || aCond->xspr.data1 >= gCondTypeNames[i].rng2) continue; - condType = gCondTypeNames[i].name; - condType.ToUpper(); - break; - } - - snprintf(buffer, 256, "\n\n%s CONDITION RX: %d, TX: %d, SPRITE: #%d RETURNS:\n", condType.GetChars(), aCond->xspr.rxID, aCond->xspr.txID, aCond->GetIndex()); - va_list args; - va_start(args, pzFormat); - vsnprintf(buffer2, 512, pzFormat, args); - I_Error("%s%s", buffer, buffer2); + char buffer[256]; + char buffer2[512]; + FString condType = "Unknown"; + for (int i = 0; i < 7; i++) + { + if (aCond->xspr.data1 < gCondTypeNames[i].rng1 || aCond->xspr.data1 >= gCondTypeNames[i].rng2) continue; + condType = gCondTypeNames[i].name; + condType.ToUpper(); + break; + } + + snprintf(buffer, 256, "\n\n%s CONDITION RX: %d, TX: %d, SPRITE: #%d RETURNS:\n", condType.GetChars(), aCond->xspr.rxID, aCond->xspr.txID, aCond->GetIndex()); + va_list args; + va_start(args, pzFormat); + vsnprintf(buffer2, 512, pzFormat, args); + I_Error("%s%s", buffer, buffer2); } //--------------------------------------------------------------------------- @@ -3632,38 +3633,38 @@ void condError(DBloodActor* aCond, const char* pzFormat, ...) bool condCheckGame(DBloodActor* aCond, const EVENT& event, int cmpOp, bool PUSH) { - int cond = aCond->xspr.data1 - kCondGameBase; - int arg1 = aCond->xspr.data2; - int arg2 = aCond->xspr.data3; - int arg3 = aCond->xspr.data4; + int cond = aCond->xspr.data1 - kCondGameBase; + int arg1 = aCond->xspr.data2; + int arg2 = aCond->xspr.data3; + int arg3 = aCond->xspr.data4; - switch (cond) { - case 1: return condCmp(gFrameCount / (kTicsPerSec * 60), arg1, arg2, cmpOp); // compare level minutes - case 2: return condCmp((gFrameCount / kTicsPerSec) % 60, arg1, arg2, cmpOp); // compare level seconds - case 3: return condCmp(((gFrameCount % kTicsPerSec) * 33) / 10, arg1, arg2, cmpOp); // compare level mseconds - case 4: return condCmp(gFrameCount, arg1, arg2, cmpOp); // compare level time (unsafe) - case 5: return condCmp(gKillMgr.Kills, arg1, arg2, cmpOp); // compare current global kills counter - case 6: return condCmp(gKillMgr.TotalKills, arg1, arg2, cmpOp); // compare total global kills counter - case 7: return condCmp(gSecretMgr.Founds, arg1, arg2, cmpOp); // compare how many secrets found - case 8: return condCmp(gSecretMgr.Total, arg1, arg2, cmpOp); // compare total secrets - /*----------------------------------------------------------------------------------------------------------------------------------*/ - case 20: return condCmp(gVisibility, arg1, arg2, cmpOp); // compare global visibility value - /*----------------------------------------------------------------------------------------------------------------------------------*/ - case 30: return Chance((0x10000 * arg3) / kPercFull); // check chance - case 31: return condCmp(nnExtRandom(arg1, arg2), arg1, arg2, cmpOp); - /*----------------------------------------------------------------------------------------------------------------------------------*/ - case 47: - { - BloodStatIterator it(ClipRange(arg3, 0, kMaxStatus)); - int c = 0; - while (it.Next()) c++; - return condCmp(c, arg1, arg2, cmpOp); // compare counter of specific statnum sprites - } - case 48: return condCmp(Numsprites, arg1, arg2, cmpOp); // compare counter of total sprites - } + switch (cond) { + case 1: return condCmp(gFrameCount / (kTicsPerSec * 60), arg1, arg2, cmpOp); // compare level minutes + case 2: return condCmp((gFrameCount / kTicsPerSec) % 60, arg1, arg2, cmpOp); // compare level seconds + case 3: return condCmp(((gFrameCount % kTicsPerSec) * 33) / 10, arg1, arg2, cmpOp); // compare level mseconds + case 4: return condCmp(gFrameCount, arg1, arg2, cmpOp); // compare level time (unsafe) + case 5: return condCmp(gKillMgr.Kills, arg1, arg2, cmpOp); // compare current global kills counter + case 6: return condCmp(gKillMgr.TotalKills, arg1, arg2, cmpOp); // compare total global kills counter + case 7: return condCmp(gSecretMgr.Founds, arg1, arg2, cmpOp); // compare how many secrets found + case 8: return condCmp(gSecretMgr.Total, arg1, arg2, cmpOp); // compare total secrets + /*----------------------------------------------------------------------------------------------------------------------------------*/ + case 20: return condCmp(gVisibility, arg1, arg2, cmpOp); // compare global visibility value + /*----------------------------------------------------------------------------------------------------------------------------------*/ + case 30: return Chance((0x10000 * arg3) / kPercFull); // check chance + case 31: return condCmp(nnExtRandom(arg1, arg2), arg1, arg2, cmpOp); + /*----------------------------------------------------------------------------------------------------------------------------------*/ + case 47: + { + BloodStatIterator it(ClipRange(arg3, 0, kMaxStatus)); + int c = 0; + while (it.Next()) c++; + return condCmp(c, arg1, arg2, cmpOp); // compare counter of specific statnum sprites + } + case 48: return condCmp(Numsprites, arg1, arg2, cmpOp); // compare counter of total sprites + } - condError(aCond, "Unexpected condition id (%d)!", cond); - return false; + condError(aCond, "Unexpected condition id (%d)!", cond); + return false; } //--------------------------------------------------------------------------- @@ -3674,236 +3675,236 @@ bool condCheckGame(DBloodActor* aCond, const EVENT& event, int cmpOp, bool PUSH) bool condCheckMixed(DBloodActor* aCond, const EVENT& event, int cmpOp, bool PUSH) { - //int var = -1; - int cond = aCond->xspr.data1 - kCondMixedBase; int arg1 = aCond->xspr.data2; - int arg2 = aCond->xspr.data3; int arg3 = aCond->xspr.data4; - - auto eob = condGet(aCond); + //int var = -1; + int cond = aCond->xspr.data1 - kCondMixedBase; int arg1 = aCond->xspr.data2; + int arg2 = aCond->xspr.data3; int arg3 = aCond->xspr.data4; - switch (cond) - { - case 0: return (eob.isSector()); - case 5: return (eob.isWall()); - case 10: return (eob.isActor() && eob.actor()); - case 15: // x-index is fine? - if (eob.isWall()) return eob.wall()->hasX(); - if (eob.isSector()) return eob.sector()->hasX(); - if (eob.isActor()) return eob.actor() && eob.actor()->hasX(); - break; - case 20: // type in a range? - if (eob.isWall()) return condCmp(eob.wall()->type, arg1, arg2, cmpOp); - if (eob.isSector()) return condCmp(eob.sector()->type, arg1, arg2, cmpOp); - if (eob.isActor()) return eob.actor() && condCmp(eob.actor()->spr.type, arg1, arg2, cmpOp); - break; - case 24: - case 25: case 26: case 27: - case 28: case 29: case 30: - case 31: case 32: case 33: - if (eob.isWall()) - { - walltype* pObj = eob.wall(); - switch (cond) - { - case 24: return condCmp(surfType[pObj->picnum], arg1, arg2, cmpOp); - case 25: return condCmp(pObj->picnum, arg1, arg2, cmpOp); - case 26: return condCmp(pObj->pal, arg1, arg2, cmpOp); - case 27: return condCmp(pObj->shade, arg1, arg2, cmpOp); - case 28: return (pObj->cstat & EWallFlags::FromInt(arg1)); - case 29: return (pObj->hitag & arg1); - case 30: return condCmp(pObj->xrepeat, arg1, arg2, cmpOp); - case 31: return condCmp(pObj->xpan(), arg1, arg2, cmpOp); - case 32: return condCmp(pObj->yrepeat, arg1, arg2, cmpOp); - case 33: return condCmp(pObj->ypan(), arg1, arg2, cmpOp); - } - } - else if (eob.isActor()) - { - auto actor = eob.actor(); - if (!actor) break; - switch (cond) - { - case 24: return condCmp(surfType[actor->spr.picnum], arg1, arg2, cmpOp); - case 25: return condCmp(actor->spr.picnum, arg1, arg2, cmpOp); - case 26: return condCmp(actor->spr.pal, arg1, arg2, cmpOp); - case 27: return condCmp(actor->spr.shade, arg1, arg2, cmpOp); - case 28: return (actor->spr.cstat & ESpriteFlags::FromInt(arg1)); - case 29: return (actor->spr.flags & arg1); - case 30: return condCmp(actor->spr.xrepeat, arg1, arg2, cmpOp); - case 31: return condCmp(actor->spr.xoffset, arg1, arg2, cmpOp); - case 32: return condCmp(actor->spr.yrepeat, arg1, arg2, cmpOp); - case 33: return condCmp(actor->spr.yoffset, arg1, arg2, cmpOp); - } - } - else if (eob.sector()) - { - sectortype* pObj = eob.sector(); - switch (cond) - { - case 24: - switch (arg3) - { - default: return (condCmp(surfType[pObj->floorpicnum], arg1, arg2, cmpOp) || condCmp(surfType[pObj->ceilingpicnum], arg1, arg2, cmpOp)); - case 1: return condCmp(surfType[pObj->floorpicnum], arg1, arg2, cmpOp); - case 2: return condCmp(surfType[pObj->ceilingpicnum], arg1, arg2, cmpOp); - } - break; - case 25: - switch (arg3) - { - default: return (condCmp(pObj->floorpicnum, arg1, arg2, cmpOp) || condCmp(pObj->ceilingpicnum, arg1, arg2, cmpOp)); - case 1: return condCmp(pObj->floorpicnum, arg1, arg2, cmpOp); - case 2: return condCmp(pObj->ceilingpicnum, arg1, arg2, cmpOp); - } - break; - case 26: - switch (arg3) - { - default: return (condCmp(pObj->floorpal, arg1, arg2, cmpOp) || condCmp(pObj->ceilingpal, arg1, arg2, cmpOp)); - case 1: return condCmp(pObj->floorpal, arg1, arg2, cmpOp); - case 2: return condCmp(pObj->ceilingpal, arg1, arg2, cmpOp); - } - break; - case 27: - switch (arg3) - { - default: return (condCmp(pObj->floorshade, arg1, arg2, cmpOp) || condCmp(pObj->ceilingshade, arg1, arg2, cmpOp)); - case 1: return condCmp(pObj->floorshade, arg1, arg2, cmpOp); - case 2: return condCmp(pObj->ceilingshade, arg1, arg2, cmpOp); - } - break; - case 28: - { - auto a = ESectorFlags::FromInt(arg1); - switch (arg3) - { - default: return ((pObj->floorstat & a) || (pObj->ceilingstat & a)); - case 1: return (pObj->floorstat & a); - case 2: return (pObj->ceilingstat & a); - } - break; - } - case 29: return (pObj->hitag & arg1); - case 30: return condCmp(pObj->floorxpan(), arg1, arg2, cmpOp); - case 31: return condCmp(pObj->ceilingxpan(), arg1, arg2, cmpOp); - case 32: return condCmp(pObj->floorypan(), arg1, arg2, cmpOp); - case 33: return condCmp(pObj->ceilingypan(), arg1, arg2, cmpOp); - } - } - break; - case 41: case 42: case 43: - case 44: case 50: case 51: - case 52: case 53: case 54: - case 55: case 56: case 57: - case 58: case 59: case 70: - case 71: - if (eob.isWall()) - { - auto pObj = eob.wall(); - if (!pObj->hasX()) - return condCmp(0, arg1, arg2, cmpOp); - - XWALL* pXObj = &pObj->xw(); - switch (cond) - { - case 41: return condCmp(pXObj->data, arg1, arg2, cmpOp); - case 50: return condCmp(pXObj->rxID, arg1, arg2, cmpOp); - case 51: return condCmp(pXObj->txID, arg1, arg2, cmpOp); - case 52: return pXObj->locked; - case 53: return pXObj->triggerOn; - case 54: return pXObj->triggerOff; - case 55: return pXObj->triggerOnce; - case 56: return pXObj->isTriggered; - case 57: return pXObj->state; - case 58: return condCmp((kPercFull * pXObj->busy) / 65536, arg1, arg2, cmpOp); - case 59: return pXObj->dudeLockout; - case 70: - switch (arg3) - { - default: return (condCmp(seqGetID(SS_WALL, pObj), arg1, arg2, cmpOp) || condCmp(seqGetID(SS_MASKED, pObj), arg1, arg2, cmpOp)); - case 1: return condCmp(seqGetID(SS_WALL, pObj), arg1, arg2, cmpOp); - case 2: return condCmp(seqGetID(SS_MASKED, pObj), arg1, arg2, cmpOp); - } - break; - case 71: - switch (arg3) - { - default: return (condCmp(seqGetStatus(SS_WALL, pObj), arg1, arg2, cmpOp) || condCmp(seqGetStatus(SS_MASKED, pObj), arg1, arg2, cmpOp)); - case 1: return condCmp(seqGetStatus(SS_WALL, pObj), arg1, arg2, cmpOp); - case 2: return condCmp(seqGetStatus(SS_MASKED, pObj), arg1, arg2, cmpOp); - } - break; - } - } - else if (eob.isActor()) - { - auto objActor = eob.actor(); - if (!objActor) break; - if (!objActor->hasX()) - return condCmp(0, arg1, arg2, cmpOp); - - switch (cond) - { - case 41: case 42: - case 43: case 44: - return condCmp(getDataFieldOfObject(eob, 1 + cond - 41), arg1, arg2, cmpOp); - case 50: return condCmp(objActor->xspr.rxID, arg1, arg2, cmpOp); - case 51: return condCmp(objActor->xspr.txID, arg1, arg2, cmpOp); - case 52: return objActor->xspr.locked; - case 53: return objActor->xspr.triggerOn; - case 54: return objActor->xspr.triggerOff; - case 55: return objActor->xspr.triggerOnce; - case 56: return objActor->xspr.isTriggered; - case 57: return objActor->xspr.state; - case 58: return condCmp((kPercFull * objActor->xspr.busy) / 65536, arg1, arg2, cmpOp); - case 59: return objActor->xspr.DudeLockout; - case 70: return condCmp(seqGetID(objActor), arg1, arg2, cmpOp); - case 71: return condCmp(seqGetStatus(objActor), arg1, arg2, cmpOp); - } - } - else if (eob.isSector()) - { - auto pObj = eob.sector(); - if (!pObj->hasX()) - return condCmp(0, arg1, arg2, cmpOp); - - XSECTOR* pXObj = &pObj->xs(); - switch (cond) { - case 41: return condCmp(pXObj->data, arg1, arg2, cmpOp); - case 50: return condCmp(pXObj->rxID, arg1, arg2, cmpOp); - case 51: return condCmp(pXObj->txID, arg1, arg2, cmpOp); - case 52: return pXObj->locked; - case 53: return pXObj->triggerOn; - case 54: return pXObj->triggerOff; - case 55: return pXObj->triggerOnce; - case 56: return pXObj->isTriggered; - case 57: return pXObj->state; - case 58: return condCmp((kPercFull * pXObj->busy) / 65536, arg1, arg2, cmpOp); - case 59: return pXObj->dudeLockout; - case 70: - // wall??? - switch (arg3) - { - default: return (condCmp(seqGetID(SS_CEILING, pObj), arg1, arg2, cmpOp) || condCmp(seqGetID(SS_FLOOR, pObj), arg1, arg2, cmpOp)); - case 1: return condCmp(seqGetID(SS_CEILING, pObj), arg1, arg2, cmpOp); - case 2: return condCmp(seqGetID(SS_FLOOR, pObj), arg1, arg2, cmpOp); - } - break; - case 71: - switch (arg3) - { - default: return (condCmp(seqGetStatus(SS_CEILING, pObj), arg1, arg2, cmpOp) || condCmp(seqGetStatus(SS_FLOOR, pObj), arg1, arg2, cmpOp)); - case 1: return condCmp(seqGetStatus(SS_CEILING, pObj), arg1, arg2, cmpOp); - case 2: return condCmp(seqGetStatus(SS_FLOOR, pObj), arg1, arg2, cmpOp); - } - break; - } - } - break; - case 99: return condCmp(event.cmd, arg1, arg2, cmpOp); // this codition received specified command? - } + auto eob = condGet(aCond); - condError(aCond, "Unexpected condition id (%d)!", cond); - return false; + switch (cond) + { + case 0: return (eob.isSector()); + case 5: return (eob.isWall()); + case 10: return (eob.isActor() && eob.actor()); + case 15: // x-index is fine? + if (eob.isWall()) return eob.wall()->hasX(); + if (eob.isSector()) return eob.sector()->hasX(); + if (eob.isActor()) return eob.actor() && eob.actor()->hasX(); + break; + case 20: // type in a range? + if (eob.isWall()) return condCmp(eob.wall()->type, arg1, arg2, cmpOp); + if (eob.isSector()) return condCmp(eob.sector()->type, arg1, arg2, cmpOp); + if (eob.isActor()) return eob.actor() && condCmp(eob.actor()->spr.type, arg1, arg2, cmpOp); + break; + case 24: + case 25: case 26: case 27: + case 28: case 29: case 30: + case 31: case 32: case 33: + if (eob.isWall()) + { + walltype* pObj = eob.wall(); + switch (cond) + { + case 24: return condCmp(surfType[pObj->picnum], arg1, arg2, cmpOp); + case 25: return condCmp(pObj->picnum, arg1, arg2, cmpOp); + case 26: return condCmp(pObj->pal, arg1, arg2, cmpOp); + case 27: return condCmp(pObj->shade, arg1, arg2, cmpOp); + case 28: return (pObj->cstat & EWallFlags::FromInt(arg1)); + case 29: return (pObj->hitag & arg1); + case 30: return condCmp(pObj->xrepeat, arg1, arg2, cmpOp); + case 31: return condCmp(pObj->xpan(), arg1, arg2, cmpOp); + case 32: return condCmp(pObj->yrepeat, arg1, arg2, cmpOp); + case 33: return condCmp(pObj->ypan(), arg1, arg2, cmpOp); + } + } + else if (eob.isActor()) + { + auto actor = eob.actor(); + if (!actor) break; + switch (cond) + { + case 24: return condCmp(surfType[actor->spr.picnum], arg1, arg2, cmpOp); + case 25: return condCmp(actor->spr.picnum, arg1, arg2, cmpOp); + case 26: return condCmp(actor->spr.pal, arg1, arg2, cmpOp); + case 27: return condCmp(actor->spr.shade, arg1, arg2, cmpOp); + case 28: return (actor->spr.cstat & ESpriteFlags::FromInt(arg1)); + case 29: return (actor->spr.flags & arg1); + case 30: return condCmp(actor->spr.xrepeat, arg1, arg2, cmpOp); + case 31: return condCmp(actor->spr.xoffset, arg1, arg2, cmpOp); + case 32: return condCmp(actor->spr.yrepeat, arg1, arg2, cmpOp); + case 33: return condCmp(actor->spr.yoffset, arg1, arg2, cmpOp); + } + } + else if (eob.sector()) + { + sectortype* pObj = eob.sector(); + switch (cond) + { + case 24: + switch (arg3) + { + default: return (condCmp(surfType[pObj->floorpicnum], arg1, arg2, cmpOp) || condCmp(surfType[pObj->ceilingpicnum], arg1, arg2, cmpOp)); + case 1: return condCmp(surfType[pObj->floorpicnum], arg1, arg2, cmpOp); + case 2: return condCmp(surfType[pObj->ceilingpicnum], arg1, arg2, cmpOp); + } + break; + case 25: + switch (arg3) + { + default: return (condCmp(pObj->floorpicnum, arg1, arg2, cmpOp) || condCmp(pObj->ceilingpicnum, arg1, arg2, cmpOp)); + case 1: return condCmp(pObj->floorpicnum, arg1, arg2, cmpOp); + case 2: return condCmp(pObj->ceilingpicnum, arg1, arg2, cmpOp); + } + break; + case 26: + switch (arg3) + { + default: return (condCmp(pObj->floorpal, arg1, arg2, cmpOp) || condCmp(pObj->ceilingpal, arg1, arg2, cmpOp)); + case 1: return condCmp(pObj->floorpal, arg1, arg2, cmpOp); + case 2: return condCmp(pObj->ceilingpal, arg1, arg2, cmpOp); + } + break; + case 27: + switch (arg3) + { + default: return (condCmp(pObj->floorshade, arg1, arg2, cmpOp) || condCmp(pObj->ceilingshade, arg1, arg2, cmpOp)); + case 1: return condCmp(pObj->floorshade, arg1, arg2, cmpOp); + case 2: return condCmp(pObj->ceilingshade, arg1, arg2, cmpOp); + } + break; + case 28: + { + auto a = ESectorFlags::FromInt(arg1); + switch (arg3) + { + default: return ((pObj->floorstat & a) || (pObj->ceilingstat & a)); + case 1: return (pObj->floorstat & a); + case 2: return (pObj->ceilingstat & a); + } + break; + } + case 29: return (pObj->hitag & arg1); + case 30: return condCmp(pObj->floorxpan(), arg1, arg2, cmpOp); + case 31: return condCmp(pObj->ceilingxpan(), arg1, arg2, cmpOp); + case 32: return condCmp(pObj->floorypan(), arg1, arg2, cmpOp); + case 33: return condCmp(pObj->ceilingypan(), arg1, arg2, cmpOp); + } + } + break; + case 41: case 42: case 43: + case 44: case 50: case 51: + case 52: case 53: case 54: + case 55: case 56: case 57: + case 58: case 59: case 70: + case 71: + if (eob.isWall()) + { + auto pObj = eob.wall(); + if (!pObj->hasX()) + return condCmp(0, arg1, arg2, cmpOp); + + XWALL* pXObj = &pObj->xw(); + switch (cond) + { + case 41: return condCmp(pXObj->data, arg1, arg2, cmpOp); + case 50: return condCmp(pXObj->rxID, arg1, arg2, cmpOp); + case 51: return condCmp(pXObj->txID, arg1, arg2, cmpOp); + case 52: return pXObj->locked; + case 53: return pXObj->triggerOn; + case 54: return pXObj->triggerOff; + case 55: return pXObj->triggerOnce; + case 56: return pXObj->isTriggered; + case 57: return pXObj->state; + case 58: return condCmp((kPercFull * pXObj->busy) / 65536, arg1, arg2, cmpOp); + case 59: return pXObj->dudeLockout; + case 70: + switch (arg3) + { + default: return (condCmp(seqGetID(SS_WALL, pObj), arg1, arg2, cmpOp) || condCmp(seqGetID(SS_MASKED, pObj), arg1, arg2, cmpOp)); + case 1: return condCmp(seqGetID(SS_WALL, pObj), arg1, arg2, cmpOp); + case 2: return condCmp(seqGetID(SS_MASKED, pObj), arg1, arg2, cmpOp); + } + break; + case 71: + switch (arg3) + { + default: return (condCmp(seqGetStatus(SS_WALL, pObj), arg1, arg2, cmpOp) || condCmp(seqGetStatus(SS_MASKED, pObj), arg1, arg2, cmpOp)); + case 1: return condCmp(seqGetStatus(SS_WALL, pObj), arg1, arg2, cmpOp); + case 2: return condCmp(seqGetStatus(SS_MASKED, pObj), arg1, arg2, cmpOp); + } + break; + } + } + else if (eob.isActor()) + { + auto objActor = eob.actor(); + if (!objActor) break; + if (!objActor->hasX()) + return condCmp(0, arg1, arg2, cmpOp); + + switch (cond) + { + case 41: case 42: + case 43: case 44: + return condCmp(getDataFieldOfObject(eob, 1 + cond - 41), arg1, arg2, cmpOp); + case 50: return condCmp(objActor->xspr.rxID, arg1, arg2, cmpOp); + case 51: return condCmp(objActor->xspr.txID, arg1, arg2, cmpOp); + case 52: return objActor->xspr.locked; + case 53: return objActor->xspr.triggerOn; + case 54: return objActor->xspr.triggerOff; + case 55: return objActor->xspr.triggerOnce; + case 56: return objActor->xspr.isTriggered; + case 57: return objActor->xspr.state; + case 58: return condCmp((kPercFull * objActor->xspr.busy) / 65536, arg1, arg2, cmpOp); + case 59: return objActor->xspr.DudeLockout; + case 70: return condCmp(seqGetID(objActor), arg1, arg2, cmpOp); + case 71: return condCmp(seqGetStatus(objActor), arg1, arg2, cmpOp); + } + } + else if (eob.isSector()) + { + auto pObj = eob.sector(); + if (!pObj->hasX()) + return condCmp(0, arg1, arg2, cmpOp); + + XSECTOR* pXObj = &pObj->xs(); + switch (cond) { + case 41: return condCmp(pXObj->data, arg1, arg2, cmpOp); + case 50: return condCmp(pXObj->rxID, arg1, arg2, cmpOp); + case 51: return condCmp(pXObj->txID, arg1, arg2, cmpOp); + case 52: return pXObj->locked; + case 53: return pXObj->triggerOn; + case 54: return pXObj->triggerOff; + case 55: return pXObj->triggerOnce; + case 56: return pXObj->isTriggered; + case 57: return pXObj->state; + case 58: return condCmp((kPercFull * pXObj->busy) / 65536, arg1, arg2, cmpOp); + case 59: return pXObj->dudeLockout; + case 70: + // wall??? + switch (arg3) + { + default: return (condCmp(seqGetID(SS_CEILING, pObj), arg1, arg2, cmpOp) || condCmp(seqGetID(SS_FLOOR, pObj), arg1, arg2, cmpOp)); + case 1: return condCmp(seqGetID(SS_CEILING, pObj), arg1, arg2, cmpOp); + case 2: return condCmp(seqGetID(SS_FLOOR, pObj), arg1, arg2, cmpOp); + } + break; + case 71: + switch (arg3) + { + default: return (condCmp(seqGetStatus(SS_CEILING, pObj), arg1, arg2, cmpOp) || condCmp(seqGetStatus(SS_FLOOR, pObj), arg1, arg2, cmpOp)); + case 1: return condCmp(seqGetStatus(SS_CEILING, pObj), arg1, arg2, cmpOp); + case 2: return condCmp(seqGetStatus(SS_FLOOR, pObj), arg1, arg2, cmpOp); + } + break; + } + } + break; + case 99: return condCmp(event.cmd, arg1, arg2, cmpOp); // this codition received specified command? + } + + condError(aCond, "Unexpected condition id (%d)!", cond); + return false; } //--------------------------------------------------------------------------- @@ -3912,87 +3913,87 @@ bool condCheckMixed(DBloodActor* aCond, const EVENT& event, int cmpOp, bool PUSH // //--------------------------------------------------------------------------- -bool condCheckSector(DBloodActor* aCond, int cmpOp, bool PUSH) +bool condCheckSector(DBloodActor* aCond, int cmpOp, bool PUSH) { - int cond = aCond->xspr.data1 - kCondSectorBase; - int arg1 = aCond->xspr.data2; - int arg2 = aCond->xspr.data3; //int arg3 = aCond->xspr.data4; - - auto eob = condGet(aCond); + int cond = aCond->xspr.data1 - kCondSectorBase; + int arg1 = aCond->xspr.data2; + int arg2 = aCond->xspr.data3; //int arg3 = aCond->xspr.data4; - if (!eob.isSector()) - condError(aCond, "Sector expected, got %s", eob.description().GetChars()); + auto eob = condGet(aCond); - sectortype* pSect = eob.sector(); - XSECTOR* pXSect = pSect->hasX()? &pSect->xs() : nullptr; + if (!eob.isSector()) + condError(aCond, "Sector expected, got %s", eob.description().GetChars()); - if (cond < (kCondRange >> 1)) - { - switch (cond) - { - default: break; - case 0: return condCmp(pSect->visibility, arg1, arg2, cmpOp); - case 5: return condCmp(pSect->floorheinum, arg1, arg2, cmpOp); - case 6: return condCmp(pSect->ceilingheinum, arg1, arg2, cmpOp); - case 10: // required sprite type is in current sector? - BloodSectIterator it(pSect); - while (auto iactor = it.Next()) - { - if (!condCmp(iactor->spr.type, arg1, arg2, cmpOp)) continue; - else if (PUSH) condPush(aCond, iactor); - return true; - } - return false; - } - } - else if (pXSect) - { - switch (cond) - { - default: break; - case 50: return pXSect->Underwater; - case 51: return condCmp(pXSect->Depth, arg1, arg2, cmpOp); - case 55: // compare floor height (in %) - case 56: { // compare ceil height (in %) - int h = 0; int curH = 0; - switch (pSect->type) - { - case kSectorZMotion: - case kSectorRotate: - case kSectorSlide: - if (cond == 60) - { - h = ClipLow(abs(pXSect->onFloorZ - pXSect->offFloorZ), 1); - curH = abs(pSect->floorz - pXSect->offFloorZ); - } - else - { - h = ClipLow(abs(pXSect->onCeilZ - pXSect->offCeilZ), 1); - curH = abs(pSect->ceilingz - pXSect->offCeilZ); - } - return condCmp((kPercFull * curH) / h, arg1, arg2, cmpOp); - default: - condError(aCond, "Usupported sector type %d", pSect->type); - return false; - } - } - case 57: // this sector in movement? - return !pXSect->unused1; - } - } - else - { - switch (cond) - { - default: return false; - case 55: - case 56: - return condCmp(0, arg1, arg2, cmpOp); - } - } - - condError(aCond, "Unexpected condition id (%d)!", cond); - return false; + sectortype* pSect = eob.sector(); + XSECTOR* pXSect = pSect->hasX() ? &pSect->xs() : nullptr; + + if (cond < (kCondRange >> 1)) + { + switch (cond) + { + default: break; + case 0: return condCmp(pSect->visibility, arg1, arg2, cmpOp); + case 5: return condCmp(pSect->floorheinum, arg1, arg2, cmpOp); + case 6: return condCmp(pSect->ceilingheinum, arg1, arg2, cmpOp); + case 10: // required sprite type is in current sector? + BloodSectIterator it(pSect); + while (auto iactor = it.Next()) + { + if (!condCmp(iactor->spr.type, arg1, arg2, cmpOp)) continue; + else if (PUSH) condPush(aCond, iactor); + return true; + } + return false; + } + } + else if (pXSect) + { + switch (cond) + { + default: break; + case 50: return pXSect->Underwater; + case 51: return condCmp(pXSect->Depth, arg1, arg2, cmpOp); + case 55: // compare floor height (in %) + case 56: { // compare ceil height (in %) + int h = 0; int curH = 0; + switch (pSect->type) + { + case kSectorZMotion: + case kSectorRotate: + case kSectorSlide: + if (cond == 60) + { + h = ClipLow(abs(pXSect->onFloorZ - pXSect->offFloorZ), 1); + curH = abs(pSect->floorz - pXSect->offFloorZ); + } + else + { + h = ClipLow(abs(pXSect->onCeilZ - pXSect->offCeilZ), 1); + curH = abs(pSect->ceilingz - pXSect->offCeilZ); + } + return condCmp((kPercFull * curH) / h, arg1, arg2, cmpOp); + default: + condError(aCond, "Usupported sector type %d", pSect->type); + return false; + } + } + case 57: // this sector in movement? + return !pXSect->unused1; + } + } + else + { + switch (cond) + { + default: return false; + case 55: + case 56: + return condCmp(0, arg1, arg2, cmpOp); + } + } + + condError(aCond, "Unexpected condition id (%d)!", cond); + return false; } //--------------------------------------------------------------------------- @@ -4001,47 +4002,47 @@ bool condCheckSector(DBloodActor* aCond, int cmpOp, bool PUSH) // //--------------------------------------------------------------------------- -bool condCheckWall(DBloodActor* aCond, int cmpOp, bool PUSH) +bool condCheckWall(DBloodActor* aCond, int cmpOp, bool PUSH) { - int var = -1; - int cond = aCond->xspr.data1 - kCondWallBase; int arg1 = aCond->xspr.data2; - int arg2 = aCond->xspr.data3; //int arg3 = aCond->xspr.data4; + int var = -1; + int cond = aCond->xspr.data1 - kCondWallBase; int arg1 = aCond->xspr.data2; + int arg2 = aCond->xspr.data3; //int arg3 = aCond->xspr.data4; - auto eob = condGet(aCond); - if (!eob.isWall()) - condError(aCond, "Wall expected, got %s", eob.description().GetChars()); - - walltype* pWall = eob.wall(); - - if (cond < (kCondRange >> 1)) - { - switch (cond) - { - default: break; - case 0: - return condCmp(pWall->overpicnum, arg1, arg2, cmpOp); - case 5: - if (PUSH) condPush(aCond, pWall->sectorp()); - return true; - case 10: // this wall is a mirror? // must be as constants here - return (pWall->type != kWallStack && condCmp(pWall->picnum, 4080, (4080 + 16) - 1, 0)); - case 15: - if (!pWall->twoSided()) return false; - else if (PUSH) condPush(aCond, pWall->nextSector()); - return true; - case 20: - if (!pWall->twoSided()) return false; - else if (PUSH) condPush(aCond, pWall->nextWall()); - return true; - case 25: // next wall belongs to sector? (Note: This was 'sector of next wall' which is same as case 15 because we do not allow bad links!) - if (!pWall->twoSided()) return false; - else if (PUSH) condPush(aCond, pWall->nextSector()); - return true; - } - } + auto eob = condGet(aCond); + if (!eob.isWall()) + condError(aCond, "Wall expected, got %s", eob.description().GetChars()); - condError(aCond, "Unexpected condition id (%d)!", cond); - return false; + walltype* pWall = eob.wall(); + + if (cond < (kCondRange >> 1)) + { + switch (cond) + { + default: break; + case 0: + return condCmp(pWall->overpicnum, arg1, arg2, cmpOp); + case 5: + if (PUSH) condPush(aCond, pWall->sectorp()); + return true; + case 10: // this wall is a mirror? // must be as constants here + return (pWall->type != kWallStack && condCmp(pWall->picnum, 4080, (4080 + 16) - 1, 0)); + case 15: + if (!pWall->twoSided()) return false; + else if (PUSH) condPush(aCond, pWall->nextSector()); + return true; + case 20: + if (!pWall->twoSided()) return false; + else if (PUSH) condPush(aCond, pWall->nextWall()); + return true; + case 25: // next wall belongs to sector? (Note: This was 'sector of next wall' which is same as case 15 because we do not allow bad links!) + if (!pWall->twoSided()) return false; + else if (PUSH) condPush(aCond, pWall->nextSector()); + return true; + } + } + + condError(aCond, "Unexpected condition id (%d)!", cond); + return false; } //--------------------------------------------------------------------------- @@ -4050,85 +4051,85 @@ bool condCheckWall(DBloodActor* aCond, int cmpOp, bool PUSH) // //--------------------------------------------------------------------------- -bool condCheckPlayer(DBloodActor* aCond, int cmpOp, bool PUSH) +bool condCheckPlayer(DBloodActor* aCond, int cmpOp, bool PUSH) { - int var = -1; - PLAYER* pPlayer = NULL; - int cond = aCond->xspr.data1 - kCondPlayerBase; - int arg1 = aCond->xspr.data2; - int arg2 = aCond->xspr.data3; - int arg3 = aCond->xspr.data4; + int var = -1; + PLAYER* pPlayer = NULL; + int cond = aCond->xspr.data1 - kCondPlayerBase; + int arg1 = aCond->xspr.data2; + int arg2 = aCond->xspr.data3; + int arg3 = aCond->xspr.data4; - auto eob = condGet(aCond); + auto eob = condGet(aCond); - if (!eob.isActor() || !eob.actor()) - condError(aCond, "Sprite expected, got %s", eob.description().GetChars()); + if (!eob.isActor() || !eob.actor()) + condError(aCond, "Sprite expected, got %s", eob.description().GetChars()); - auto objActor = eob.actor(); - for (int i = 0; i < kMaxPlayers; i++) - { - if (objActor != gPlayer[i].actor) continue; - pPlayer = &gPlayer[i]; - break; - } - - if (!pPlayer) - { - condError(aCond, "Player expected, got %s", eob.description().GetChars()); - return false; - } + auto objActor = eob.actor(); + for (int i = 0; i < kMaxPlayers; i++) + { + if (objActor != gPlayer[i].actor) continue; + pPlayer = &gPlayer[i]; + break; + } - switch (cond) { - case 0: // check if this player is connected - if (!condCmp(pPlayer->nPlayer + 1, arg1, arg2, cmpOp) || pPlayer->actor == nullptr) return false; - else if (PUSH) condPush(aCond, pPlayer->actor); - return (pPlayer->nPlayer >= 0); - case 1: return condCmp((gGameOptions.nGameType != 3) ? 0 : pPlayer->teamId + 1, arg1, arg2, cmpOp); // compare team - case 2: return (arg1 > 0 && arg1 < 8 && pPlayer->hasKey[arg1 - 1]); - case 3: return (arg1 > 0 && arg1 < 15 && pPlayer->hasWeapon[arg1 - 1]); - case 4: return condCmp(pPlayer->curWeapon, arg1, arg2, cmpOp); - case 5: return (arg1 > 0 && arg1 < 6 && condCmp(pPlayer->packSlots[arg1 - 1].curAmount, arg2, arg3, cmpOp)); - case 6: return (arg1 > 0 && arg1 < 6 && pPlayer->packSlots[arg1 - 1].isActive); - case 7: return condCmp(pPlayer->packItemId + 1, arg1, arg2, cmpOp); - case 8: // check for powerup amount in seconds - if (arg3 > 0 && arg3 <= (kMaxAllowedPowerup - (kMinAllowedPowerup << 1) + 1)) { - var = (kMinAllowedPowerup + arg3) - 1; // allowable powerups - return condCmp(pPlayer->pwUpTime[var] / 100, arg1, arg2, cmpOp); - } - condError(aCond, "Unexpected powerup #%d", arg3); - return false; - case 9: - if (!pPlayer->fragger) return false; - else if (PUSH) condPush(aCond, pPlayer->fragger); - return true; - case 10: // check keys pressed - switch (arg1) { - case 1: return (pPlayer->input.fvel > 0); // forward - case 2: return (pPlayer->input.fvel < 0); // backward - case 3: return (pPlayer->input.svel > 0); // left - case 4: return (pPlayer->input.svel < 0); // right - case 5: return !!(pPlayer->input.actions & SB_JUMP); // jump - case 6: return !!(pPlayer->input.actions & SB_CROUCH); // crouch - case 7: return !!(pPlayer->input.actions & SB_FIRE); // normal fire weapon - case 8: return !!(pPlayer->input.actions & SB_ALTFIRE); // alt fire weapon - case 9: return !!(pPlayer->input.actions & SB_OPEN); // use - default: - condError(aCond, "Specify a correct key!"); - break; - } - return false; - case 11: return (pPlayer->isRunning); - case 12: return (pPlayer->fallScream); // falling in abyss? - case 13: return condCmp(pPlayer->lifeMode + 1, arg1, arg2, cmpOp); - case 14: return condCmp(pPlayer->posture + 1, arg1, arg2, cmpOp); - case 46: return condCmp(pPlayer->sceneQav, arg1, arg2, cmpOp); - case 47: return (pPlayer->godMode || powerupCheck(pPlayer, kPwUpDeathMask)); - case 48: return isShrinked(pPlayer->actor); - case 49: return isGrown(pPlayer->actor); - } + if (!pPlayer) + { + condError(aCond, "Player expected, got %s", eob.description().GetChars()); + return false; + } - condError(aCond, "Unexpected condition #%d!", cond); - return false; + switch (cond) { + case 0: // check if this player is connected + if (!condCmp(pPlayer->nPlayer + 1, arg1, arg2, cmpOp) || pPlayer->actor == nullptr) return false; + else if (PUSH) condPush(aCond, pPlayer->actor); + return (pPlayer->nPlayer >= 0); + case 1: return condCmp((gGameOptions.nGameType != 3) ? 0 : pPlayer->teamId + 1, arg1, arg2, cmpOp); // compare team + case 2: return (arg1 > 0 && arg1 < 8 && pPlayer->hasKey[arg1 - 1]); + case 3: return (arg1 > 0 && arg1 < 15 && pPlayer->hasWeapon[arg1 - 1]); + case 4: return condCmp(pPlayer->curWeapon, arg1, arg2, cmpOp); + case 5: return (arg1 > 0 && arg1 < 6 && condCmp(pPlayer->packSlots[arg1 - 1].curAmount, arg2, arg3, cmpOp)); + case 6: return (arg1 > 0 && arg1 < 6 && pPlayer->packSlots[arg1 - 1].isActive); + case 7: return condCmp(pPlayer->packItemId + 1, arg1, arg2, cmpOp); + case 8: // check for powerup amount in seconds + if (arg3 > 0 && arg3 <= (kMaxAllowedPowerup - (kMinAllowedPowerup << 1) + 1)) { + var = (kMinAllowedPowerup + arg3) - 1; // allowable powerups + return condCmp(pPlayer->pwUpTime[var] / 100, arg1, arg2, cmpOp); + } + condError(aCond, "Unexpected powerup #%d", arg3); + return false; + case 9: + if (!pPlayer->fragger) return false; + else if (PUSH) condPush(aCond, pPlayer->fragger); + return true; + case 10: // check keys pressed + switch (arg1) { + case 1: return (pPlayer->input.fvel > 0); // forward + case 2: return (pPlayer->input.fvel < 0); // backward + case 3: return (pPlayer->input.svel > 0); // left + case 4: return (pPlayer->input.svel < 0); // right + case 5: return !!(pPlayer->input.actions & SB_JUMP); // jump + case 6: return !!(pPlayer->input.actions & SB_CROUCH); // crouch + case 7: return !!(pPlayer->input.actions & SB_FIRE); // normal fire weapon + case 8: return !!(pPlayer->input.actions & SB_ALTFIRE); // alt fire weapon + case 9: return !!(pPlayer->input.actions & SB_OPEN); // use + default: + condError(aCond, "Specify a correct key!"); + break; + } + return false; + case 11: return (pPlayer->isRunning); + case 12: return (pPlayer->fallScream); // falling in abyss? + case 13: return condCmp(pPlayer->lifeMode + 1, arg1, arg2, cmpOp); + case 14: return condCmp(pPlayer->posture + 1, arg1, arg2, cmpOp); + case 46: return condCmp(pPlayer->sceneQav, arg1, arg2, cmpOp); + case 47: return (pPlayer->godMode || powerupCheck(pPlayer, kPwUpDeathMask)); + case 48: return isShrinked(pPlayer->actor); + case 49: return isGrown(pPlayer->actor); + } + + condError(aCond, "Unexpected condition #%d!", cond); + return false; } //--------------------------------------------------------------------------- @@ -4137,155 +4138,155 @@ bool condCheckPlayer(DBloodActor* aCond, int cmpOp, bool PUSH) // //--------------------------------------------------------------------------- -bool condCheckDude(DBloodActor* aCond, int cmpOp, bool PUSH) +bool condCheckDude(DBloodActor* aCond, int cmpOp, bool PUSH) { - int var = -1; - int cond = aCond->xspr.data1 - kCondDudeBase; int arg1 = aCond->xspr.data2; - int arg2 = aCond->xspr.data3; int arg3 = aCond->xspr.data4; - - auto eob = condGet(aCond); + int var = -1; + int cond = aCond->xspr.data1 - kCondDudeBase; int arg1 = aCond->xspr.data2; + int arg2 = aCond->xspr.data3; int arg3 = aCond->xspr.data4; - if (!eob.isActor() || !eob.actor()) - condError(aCond, "Sprite expected, got %s", eob.description().GetChars()); + auto eob = condGet(aCond); - auto objActor = eob.actor(); + if (!eob.isActor() || !eob.actor()) + condError(aCond, "Sprite expected, got %s", eob.description().GetChars()); - if (!objActor->hasX() || objActor->spr.type == kThingBloodChunks) - condError(aCond, "Sprite #%d is dead!", objActor->GetIndex()); - - if (!objActor->IsDudeActor() || objActor->IsPlayerActor()) - condError(aCond, "Object #%d is not an enemy!", objActor->GetIndex()); + auto objActor = eob.actor(); - auto targ = objActor->GetTarget(); - switch (cond) - { - default: break; - case 0: // dude have any targets? - if (!targ) return false; - else if (!targ->IsDudeActor() && targ->spr.type != kMarkerPath) return false; - else if (PUSH) condPush(aCond, targ); - return true; - case 1: return aiFightDudeIsAffected(objActor); // dude affected by ai fight? - case 2: // distance to the target in a range? - case 3: // is the target visible? - case 4: // is the target visible with periphery? - { + if (!objActor->hasX() || objActor->spr.type == kThingBloodChunks) + condError(aCond, "Sprite #%d is dead!", objActor->GetIndex()); - if (!targ) - condError(aCond, "Dude #%d has no target!", objActor->GetIndex()); + if (!objActor->IsDudeActor() || objActor->IsPlayerActor()) + condError(aCond, "Object #%d is not an enemy!", objActor->GetIndex()); - DUDEINFO* pInfo = getDudeInfo(objActor->spr.type); - int eyeAboveZ = pInfo->eyeHeight * objActor->spr.yrepeat << 2; - int dx = targ->spr.pos.X - objActor->spr.pos.X; - int dy = targ->spr.pos.Y - objActor->spr.pos.Y; + auto targ = objActor->GetTarget(); + switch (cond) + { + default: break; + case 0: // dude have any targets? + if (!targ) return false; + else if (!targ->IsDudeActor() && targ->spr.type != kMarkerPath) return false; + else if (PUSH) condPush(aCond, targ); + return true; + case 1: return aiFightDudeIsAffected(objActor); // dude affected by ai fight? + case 2: // distance to the target in a range? + case 3: // is the target visible? + case 4: // is the target visible with periphery? + { - switch (cond) - { - case 2: - var = condCmp(approxDist(dx, dy), arg1 * 512, arg2 * 512, cmpOp); - break; - case 3: - case 4: - var = cansee(objActor->spr.pos.X, objActor->spr.pos.Y, objActor->spr.pos.Z, objActor->spr.sector(), targ->spr.pos.X, targ->spr.pos.Y, targ->spr.pos.Z - eyeAboveZ, targ->spr.sector()); - if (cond == 4 && var > 0) - { - var = ((1024 + getangle(dx, dy) - objActor->spr.ang) & 2047) - 1024; - var = (abs(var) < ((arg1 <= 0) ? pInfo->periphery : ClipHigh(arg1, 2048))); - } - break; - } + if (!targ) + condError(aCond, "Dude #%d has no target!", objActor->GetIndex()); - if (var <= 0) return false; - else if (PUSH) condPush(aCond, targ); - return true; + DUDEINFO* pInfo = getDudeInfo(objActor->spr.type); + int eyeAboveZ = pInfo->eyeHeight * objActor->spr.yrepeat << 2; + int dx = targ->spr.pos.X - objActor->spr.pos.X; + int dy = targ->spr.pos.Y - objActor->spr.pos.Y; - } - case 5: return objActor->xspr.dudeFlag4; - case 6: return objActor->xspr.dudeDeaf; - case 7: return objActor->xspr.dudeGuard; - case 8: return objActor->xspr.dudeAmbush; - case 9: return (objActor->xspr.unused1 & kDudeFlagStealth); - case 10: // check if the marker is busy with another dude - case 11: // check if the marker is reached - if (!objActor->xspr.dudeFlag4 || !targ || targ->spr.type != kMarkerPath) return false; - switch (cond) { - case 10: - { - auto check = aiPatrolMarkerBusy(objActor, targ); - if (!check) return false; - else if (PUSH) condPush(aCond, check); - break; - } - case 11: - if (!aiPatrolMarkerReached(objActor)) return false; - else if (PUSH) condPush(aCond, targ); - break; - } - return true; - case 12: // compare spot progress value in % - if (!objActor->xspr.dudeFlag4 || !targ || targ->spr.type != kMarkerPath) var = 0; - else if (!(objActor->xspr.unused1 & kDudeFlagStealth) || objActor->xspr.data3 < 0 || objActor->xspr.data3 > kMaxPatrolSpotValue) var = 0; - else var = (kPercFull * objActor->xspr.data3) / kMaxPatrolSpotValue; - return condCmp(var, arg1, arg2, cmpOp); - case 15: return getDudeInfo(objActor->spr.type)->lockOut; // dude allowed to interact with objects? - case 16: return condCmp(objActor->xspr.aiState->stateType, arg1, arg2, cmpOp); - case 17: return condCmp(objActor->xspr.stateTimer, arg1, arg2, cmpOp); - case 20: // kDudeModernCustom conditions - case 21: - case 22: - case 23: - case 24: - switch (objActor->spr.type) - { - case kDudeModernCustom: - case kDudeModernCustomBurning: - switch (cond) { - case 20: // life leech is thrown? - { - DBloodActor* act = objActor->genDudeExtra.pLifeLeech; - if (!act) return false; - else if (PUSH) condPush(aCond, act); - return true; - } + switch (cond) + { + case 2: + var = condCmp(approxDist(dx, dy), arg1 * 512, arg2 * 512, cmpOp); + break; + case 3: + case 4: + var = cansee(objActor->spr.pos.X, objActor->spr.pos.Y, objActor->spr.pos.Z, objActor->spr.sector(), targ->spr.pos.X, targ->spr.pos.Y, targ->spr.pos.Z - eyeAboveZ, targ->spr.sector()); + if (cond == 4 && var > 0) + { + var = ((1024 + getangle(dx, dy) - objActor->spr.ang) & 2047) - 1024; + var = (abs(var) < ((arg1 <= 0) ? pInfo->periphery : ClipHigh(arg1, 2048))); + } + break; + } - case 21: // life leech is destroyed? - { - DBloodActor* act = objActor->genDudeExtra.pLifeLeech; - if (!act) return false; - if (objActor->GetSpecialOwner()) return true; - else if (PUSH) condPush(aCond, act); - return false; - } + if (var <= 0) return false; + else if (PUSH) condPush(aCond, targ); + return true; - case 22: // are required amount of dudes is summoned? - return condCmp(objActor->genDudeExtra.slaveCount, arg1, arg2, cmpOp); + } + case 5: return objActor->xspr.dudeFlag4; + case 6: return objActor->xspr.dudeDeaf; + case 7: return objActor->xspr.dudeGuard; + case 8: return objActor->xspr.dudeAmbush; + case 9: return (objActor->xspr.unused1 & kDudeFlagStealth); + case 10: // check if the marker is busy with another dude + case 11: // check if the marker is reached + if (!objActor->xspr.dudeFlag4 || !targ || targ->spr.type != kMarkerPath) return false; + switch (cond) { + case 10: + { + auto check = aiPatrolMarkerBusy(objActor, targ); + if (!check) return false; + else if (PUSH) condPush(aCond, check); + break; + } + case 11: + if (!aiPatrolMarkerReached(objActor)) return false; + else if (PUSH) condPush(aCond, targ); + break; + } + return true; + case 12: // compare spot progress value in % + if (!objActor->xspr.dudeFlag4 || !targ || targ->spr.type != kMarkerPath) var = 0; + else if (!(objActor->xspr.unused1 & kDudeFlagStealth) || objActor->xspr.data3 < 0 || objActor->xspr.data3 > kMaxPatrolSpotValue) var = 0; + else var = (kPercFull * objActor->xspr.data3) / kMaxPatrolSpotValue; + return condCmp(var, arg1, arg2, cmpOp); + case 15: return getDudeInfo(objActor->spr.type)->lockOut; // dude allowed to interact with objects? + case 16: return condCmp(objActor->xspr.aiState->stateType, arg1, arg2, cmpOp); + case 17: return condCmp(objActor->xspr.stateTimer, arg1, arg2, cmpOp); + case 20: // kDudeModernCustom conditions + case 21: + case 22: + case 23: + case 24: + switch (objActor->spr.type) + { + case kDudeModernCustom: + case kDudeModernCustomBurning: + switch (cond) { + case 20: // life leech is thrown? + { + DBloodActor* act = objActor->genDudeExtra.pLifeLeech; + if (!act) return false; + else if (PUSH) condPush(aCond, act); + return true; + } - case 23: // check if dude can... - switch (arg3) - { - case 1: return objActor->genDudeExtra.canAttack; - case 2: return objActor->genDudeExtra.canBurn; - case 3: return objActor->genDudeExtra.canDuck; - case 4: return objActor->genDudeExtra.canElectrocute; - case 5: return objActor->genDudeExtra.canFly; - case 6: return objActor->genDudeExtra.canRecoil; - case 7: return objActor->genDudeExtra.canSwim; - case 8: return objActor->genDudeExtra.canWalk; - default: condError(aCond, "Invalid argument %d", arg3); break; - } - break; - case 24: // compare weapon dispersion - return condCmp(objActor->genDudeExtra.baseDispersion, arg1, arg2, cmpOp); - } - break; - default: - condError(aCond, "Dude #%d is not a Custom Dude!", objActor->GetIndex()); - return false; - } - } + case 21: // life leech is destroyed? + { + DBloodActor* act = objActor->genDudeExtra.pLifeLeech; + if (!act) return false; + if (objActor->GetSpecialOwner()) return true; + else if (PUSH) condPush(aCond, act); + return false; + } - condError(aCond, "Unexpected condition #%d!", cond); - return false; + case 22: // are required amount of dudes is summoned? + return condCmp(objActor->genDudeExtra.slaveCount, arg1, arg2, cmpOp); + + case 23: // check if dude can... + switch (arg3) + { + case 1: return objActor->genDudeExtra.canAttack; + case 2: return objActor->genDudeExtra.canBurn; + case 3: return objActor->genDudeExtra.canDuck; + case 4: return objActor->genDudeExtra.canElectrocute; + case 5: return objActor->genDudeExtra.canFly; + case 6: return objActor->genDudeExtra.canRecoil; + case 7: return objActor->genDudeExtra.canSwim; + case 8: return objActor->genDudeExtra.canWalk; + default: condError(aCond, "Invalid argument %d", arg3); break; + } + break; + case 24: // compare weapon dispersion + return condCmp(objActor->genDudeExtra.baseDispersion, arg1, arg2, cmpOp); + } + break; + default: + condError(aCond, "Dude #%d is not a Custom Dude!", objActor->GetIndex()); + return false; + } + } + + condError(aCond, "Unexpected condition #%d!", cond); + return false; } //--------------------------------------------------------------------------- @@ -4296,231 +4297,231 @@ bool condCheckDude(DBloodActor* aCond, int cmpOp, bool PUSH) bool condCheckSprite(DBloodActor* aCond, int cmpOp, bool PUSH) { - int var = -1, var2 = -1, var3 = -1; PLAYER* pPlayer = NULL; bool retn = false; - int cond = aCond->xspr.data1 - kCondSpriteBase; int arg1 = aCond->xspr.data2; - int arg2 = aCond->xspr.data3; int arg3 = aCond->xspr.data4; - - auto eob = condGet(aCond); + int var = -1, var2 = -1, var3 = -1; PLAYER* pPlayer = NULL; bool retn = false; + int cond = aCond->xspr.data1 - kCondSpriteBase; int arg1 = aCond->xspr.data2; + int arg2 = aCond->xspr.data3; int arg3 = aCond->xspr.data4; - if (!eob.isActor() || !eob.actor()) - condError(aCond, "Sprite expected, got %s", eob.description().GetChars()); + auto eob = condGet(aCond); - auto objActor = eob.actor(); + if (!eob.isActor() || !eob.actor()) + condError(aCond, "Sprite expected, got %s", eob.description().GetChars()); - if (cond < (kCondRange >> 1)) - { - switch (cond) - { - default: break; - case 0: return condCmp((objActor->spr.ang & 2047), arg1, arg2, cmpOp); - case 5: return condCmp(objActor->spr.statnum, arg1, arg2, cmpOp); - case 6: return ((objActor->spr.flags & kHitagRespawn) || objActor->spr.statnum == kStatRespawn); - case 7: return condCmp(spriteGetSlope(&objActor->spr), arg1, arg2, cmpOp); - case 10: return condCmp(objActor->spr.clipdist, arg1, arg2, cmpOp); - case 15: - if (!objActor->GetOwner()) return false; - else if (PUSH) condPush(aCond, objActor->GetOwner()); - return true; - case 20: // stays in a sector? - if (!objActor->spr.insector()) return false; - else if (PUSH) condPush(aCond, objActor->spr.sector()); - return true; - case 25: - switch (arg1) - { - case 0: return (objActor->xvel || objActor->yvel || objActor->zvel); - case 1: return (objActor->xvel); - case 2: return (objActor->yvel); - case 3: return (objActor->zvel); - } - break; - case 30: - if (!spriteIsUnderwater(objActor) && !spriteIsUnderwater(objActor, true)) return false; - else if (PUSH) condPush(aCond, objActor->spr.sector()); - return true; - case 31: - if (arg1 == -1) - { - for (var = 0; var < kDmgMax; var++) - { - if (!nnExtIsImmune(objActor, arg1, 0)) - return false; - } - return true; - } - return nnExtIsImmune(objActor, arg1, 0); + auto objActor = eob.actor(); - case 35: // hitscan: ceil? - case 36: // hitscan: floor? - case 37: // hitscan: wall? - case 38: // hitscan: sprite? - switch (arg1) - { - case 0: arg1 = CLIPMASK0 | CLIPMASK1; break; - case 1: arg1 = CLIPMASK0; break; - case 2: arg1 = CLIPMASK1; break; - } + if (cond < (kCondRange >> 1)) + { + switch (cond) + { + default: break; + case 0: return condCmp((objActor->spr.ang & 2047), arg1, arg2, cmpOp); + case 5: return condCmp(objActor->spr.statnum, arg1, arg2, cmpOp); + case 6: return ((objActor->spr.flags & kHitagRespawn) || objActor->spr.statnum == kStatRespawn); + case 7: return condCmp(spriteGetSlope(&objActor->spr), arg1, arg2, cmpOp); + case 10: return condCmp(objActor->spr.clipdist, arg1, arg2, cmpOp); + case 15: + if (!objActor->GetOwner()) return false; + else if (PUSH) condPush(aCond, objActor->GetOwner()); + return true; + case 20: // stays in a sector? + if (!objActor->spr.insector()) return false; + else if (PUSH) condPush(aCond, objActor->spr.sector()); + return true; + case 25: + switch (arg1) + { + case 0: return (objActor->xvel || objActor->yvel || objActor->zvel); + case 1: return (objActor->xvel); + case 2: return (objActor->yvel); + case 3: return (objActor->zvel); + } + break; + case 30: + if (!spriteIsUnderwater(objActor) && !spriteIsUnderwater(objActor, true)) return false; + else if (PUSH) condPush(aCond, objActor->spr.sector()); + return true; + case 31: + if (arg1 == -1) + { + for (var = 0; var < kDmgMax; var++) + { + if (!nnExtIsImmune(objActor, arg1, 0)) + return false; + } + return true; + } + return nnExtIsImmune(objActor, arg1, 0); - if ((pPlayer = getPlayerById(objActor->spr.type)) != NULL) - var = HitScan(objActor, pPlayer->zWeapon, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, arg1, arg3 << 1); - else if (objActor->IsDudeActor()) - var = HitScan(objActor, objActor->spr.pos.Z, bcos(objActor->spr.ang), bsin(objActor->spr.ang), (!objActor->hasX()) ? 0 : objActor->dudeSlope, arg1, arg3 << 1); - else if ((var2 & CSTAT_SPRITE_ALIGNMENT_MASK) == CSTAT_SPRITE_ALIGNMENT_FLOOR) - { - var3 = (var2 & 0x0008) ? 0x10000 << 1 : -(0x10000 << 1); - var = HitScan(objActor, objActor->spr.pos.Z, Cos(objActor->spr.ang) >> 16, Sin(objActor->spr.ang) >> 16, var3, arg1, arg3 << 1); - } - else - { - var = HitScan(objActor, objActor->spr.pos.Z, bcos(objActor->spr.ang), bsin(objActor->spr.ang), 0, arg1, arg3 << 1); - } + case 35: // hitscan: ceil? + case 36: // hitscan: floor? + case 37: // hitscan: wall? + case 38: // hitscan: sprite? + switch (arg1) + { + case 0: arg1 = CLIPMASK0 | CLIPMASK1; break; + case 1: arg1 = CLIPMASK0; break; + case 2: arg1 = CLIPMASK1; break; + } - if (var >= 0) - { - switch (cond) - { - case 35: retn = (var == 1); break; - case 36: retn = (var == 2); break; - case 37: retn = (var == 0 || var == 4); break; - case 38: retn = (var == 3); break; - } + if ((pPlayer = getPlayerById(objActor->spr.type)) != NULL) + var = HitScan(objActor, pPlayer->zWeapon, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, arg1, arg3 << 1); + else if (objActor->IsDudeActor()) + var = HitScan(objActor, objActor->spr.pos.Z, bcos(objActor->spr.ang), bsin(objActor->spr.ang), (!objActor->hasX()) ? 0 : objActor->dudeSlope, arg1, arg3 << 1); + else if ((var2 & CSTAT_SPRITE_ALIGNMENT_MASK) == CSTAT_SPRITE_ALIGNMENT_FLOOR) + { + var3 = (var2 & 0x0008) ? 0x10000 << 1 : -(0x10000 << 1); + var = HitScan(objActor, objActor->spr.pos.Z, Cos(objActor->spr.ang) >> 16, Sin(objActor->spr.ang) >> 16, var3, arg1, arg3 << 1); + } + else + { + var = HitScan(objActor, objActor->spr.pos.Z, bcos(objActor->spr.ang), bsin(objActor->spr.ang), 0, arg1, arg3 << 1); + } - if (!PUSH) return retn; - switch (var) - { - case 0: case 4: condPush(aCond, gHitInfo.hitWall); break; - case 1: case 2: condPush(aCond, gHitInfo.hitSector); break; - case 3: condPush(aCond, gHitInfo.actor()); break; - } + if (var >= 0) + { + switch (cond) + { + case 35: retn = (var == 1); break; + case 36: retn = (var == 2); break; + case 37: retn = (var == 0 || var == 4); break; + case 38: retn = (var == 3); break; + } - } - return retn; + if (!PUSH) return retn; + switch (var) + { + case 0: case 4: condPush(aCond, gHitInfo.hitWall); break; + case 1: case 2: condPush(aCond, gHitInfo.hitSector); break; + case 3: condPush(aCond, gHitInfo.actor()); break; + } - case 45: // this sprite is a target of some dude? - BloodStatIterator it(kStatDude); - while (auto iactor = it.Next()) - { - if (objActor == iactor) continue; + } + return retn; - if (iactor->IsDudeActor() && iactor->hasX()) - { - if (iactor->xspr.health <= 0 || iactor->GetTarget() != objActor) continue; - else if (PUSH) condPush(aCond, iactor); - return true; - } - } - return false; - } - } - else if (objActor->hasX()) - { - switch (cond) - { - default: break; - case 50: // compare hp (in %) - if (objActor->IsDudeActor()) var = (objActor->xspr.sysData2 > 0) ? ClipRange(objActor->xspr.sysData2 << 4, 1, 65535) : getDudeInfo(objActor->spr.type)->startHealth << 4; - else if (objActor->spr.type == kThingBloodChunks) return condCmp(0, arg1, arg2, cmpOp); - else if (objActor->spr.type >= kThingBase && objActor->spr.type < kThingMax) var = thingInfo[objActor->spr.type - kThingBase].startHealth << 4; - return condCmp((kPercFull * objActor->xspr.health) / ClipLow(var, 1), arg1, arg2, cmpOp); - case 55: // touching ceil of sector? - if (objActor->hit.ceilhit.type != kHitSector) return false; - else if (PUSH) condPush(aCond, objActor->hit.ceilhit.hitSector); - return true; - case 56: // touching floor of sector? - if (objActor->hit.florhit.type != kHitSector) return false; - else if (PUSH) condPush(aCond, objActor->hit.florhit.hitSector); - return true; - case 57: // touching walls of sector? - if (objActor->hit.hit.type != kHitWall) return false; - else if (PUSH) condPush(aCond, objActor->hit.hit.hitWall); - return true; - case 58: // touching another sprite? - { - DBloodActor* actorvar = nullptr; - // Caution: The hit pointers here may be stale, so be careful with them. - switch (arg3) - { - case 0: - case 1: - if (objActor->hit.florhit.type == kHitSprite) actorvar = objActor->hit.florhit.safeActor(); - if (arg3 || var >= 0) break; - [[fallthrough]]; - case 2: - if (objActor->hit.hit.type == kHitSprite) actorvar = objActor->hit.hit.safeActor(); - if (arg3 || var >= 0) break; - [[fallthrough]]; - case 3: - if (objActor->hit.ceilhit.type == kHitSprite) actorvar = objActor->hit.ceilhit.safeActor(); - break; - } - if (actorvar == nullptr) - { - // check if something is touching this sprite - BloodSpriteIterator it; - while (auto iactor = it.Next()) - { - if (iactor->spr.flags & kHitagRespawn) continue; - auto& hit = iactor->hit; - switch (arg3) - { - case 0: - case 1: - if (hit.ceilhit.type == kHitSprite && hit.ceilhit.safeActor() == objActor) actorvar = iactor; - if (arg3 || actorvar) break; - [[fallthrough]]; - case 2: - if (hit.hit.type == kHitSprite && hit.hit.safeActor() == objActor) actorvar = iactor; - if (arg3 || actorvar) break; - [[fallthrough]]; - case 3: - if (hit.florhit.type == kHitSprite && hit.florhit.safeActor() == objActor) actorvar = iactor; - break; - } - } - } - if (actorvar == nullptr) return false; - else if (PUSH) condPush(aCond, actorvar); - return true; - } + case 45: // this sprite is a target of some dude? + BloodStatIterator it(kStatDude); + while (auto iactor = it.Next()) + { + if (objActor == iactor) continue; - case 65: // compare burn time (in %) - var = (objActor->IsDudeActor()) ? 2400 : 1200; - if (!condCmp((kPercFull * objActor->xspr.burnTime) / var, arg1, arg2, cmpOp)) return false; - else if (PUSH && objActor->GetBurnSource()) condPush(aCond, objActor->GetBurnSource()); - return true; + if (iactor->IsDudeActor() && iactor->hasX()) + { + if (iactor->xspr.health <= 0 || iactor->GetTarget() != objActor) continue; + else if (PUSH) condPush(aCond, iactor); + return true; + } + } + return false; + } + } + else if (objActor->hasX()) + { + switch (cond) + { + default: break; + case 50: // compare hp (in %) + if (objActor->IsDudeActor()) var = (objActor->xspr.sysData2 > 0) ? ClipRange(objActor->xspr.sysData2 << 4, 1, 65535) : getDudeInfo(objActor->spr.type)->startHealth << 4; + else if (objActor->spr.type == kThingBloodChunks) return condCmp(0, arg1, arg2, cmpOp); + else if (objActor->spr.type >= kThingBase && objActor->spr.type < kThingMax) var = thingInfo[objActor->spr.type - kThingBase].startHealth << 4; + return condCmp((kPercFull * objActor->xspr.health) / ClipLow(var, 1), arg1, arg2, cmpOp); + case 55: // touching ceil of sector? + if (objActor->hit.ceilhit.type != kHitSector) return false; + else if (PUSH) condPush(aCond, objActor->hit.ceilhit.hitSector); + return true; + case 56: // touching floor of sector? + if (objActor->hit.florhit.type != kHitSector) return false; + else if (PUSH) condPush(aCond, objActor->hit.florhit.hitSector); + return true; + case 57: // touching walls of sector? + if (objActor->hit.hit.type != kHitWall) return false; + else if (PUSH) condPush(aCond, objActor->hit.hit.hitWall); + return true; + case 58: // touching another sprite? + { + DBloodActor* actorvar = nullptr; + // Caution: The hit pointers here may be stale, so be careful with them. + switch (arg3) + { + case 0: + case 1: + if (objActor->hit.florhit.type == kHitSprite) actorvar = objActor->hit.florhit.safeActor(); + if (arg3 || var >= 0) break; + [[fallthrough]]; + case 2: + if (objActor->hit.hit.type == kHitSprite) actorvar = objActor->hit.hit.safeActor(); + if (arg3 || var >= 0) break; + [[fallthrough]]; + case 3: + if (objActor->hit.ceilhit.type == kHitSprite) actorvar = objActor->hit.ceilhit.safeActor(); + break; + } + if (actorvar == nullptr) + { + // check if something is touching this sprite + BloodSpriteIterator it; + while (auto iactor = it.Next()) + { + if (iactor->spr.flags & kHitagRespawn) continue; + auto& hit = iactor->hit; + switch (arg3) + { + case 0: + case 1: + if (hit.ceilhit.type == kHitSprite && hit.ceilhit.safeActor() == objActor) actorvar = iactor; + if (arg3 || actorvar) break; + [[fallthrough]]; + case 2: + if (hit.hit.type == kHitSprite && hit.hit.safeActor() == objActor) actorvar = iactor; + if (arg3 || actorvar) break; + [[fallthrough]]; + case 3: + if (hit.florhit.type == kHitSprite && hit.florhit.safeActor() == objActor) actorvar = iactor; + break; + } + } + } + if (actorvar == nullptr) return false; + else if (PUSH) condPush(aCond, actorvar); + return true; + } - case 66: // any flares stuck in this sprite? - { - BloodStatIterator it(kStatFlare); - while (auto flareactor = it.Next()) - { - if (!flareactor->hasX() || (flareactor->spr.flags & kHitagFree)) - continue; + case 65: // compare burn time (in %) + var = (objActor->IsDudeActor()) ? 2400 : 1200; + if (!condCmp((kPercFull * objActor->xspr.burnTime) / var, arg1, arg2, cmpOp)) return false; + else if (PUSH && objActor->GetBurnSource()) condPush(aCond, objActor->GetBurnSource()); + return true; - if (flareactor->GetTarget() != objActor) continue; - else if (PUSH) condPush(aCond, flareactor); - return true; - } - return false; - } - case 70: - return condCmp(getSpriteMassBySize(objActor), arg1, arg2, cmpOp); // mass of the sprite in a range? - } - } - else -{ - switch (cond) - { - default: return false; - case 50: - case 65: - case 70: - return condCmp(0, arg1, arg2, cmpOp); - } - } + case 66: // any flares stuck in this sprite? + { + BloodStatIterator it(kStatFlare); + while (auto flareactor = it.Next()) + { + if (!flareactor->hasX() || (flareactor->spr.flags & kHitagFree)) + continue; - condError(aCond, "Unexpected condition id (%d)!", cond); - return false; + if (flareactor->GetTarget() != objActor) continue; + else if (PUSH) condPush(aCond, flareactor); + return true; + } + return false; + } + case 70: + return condCmp(getSpriteMassBySize(objActor), arg1, arg2, cmpOp); // mass of the sprite in a range? + } + } + else + { + switch (cond) + { + default: return false; + case 50: + case 65: + case 70: + return condCmp(0, arg1, arg2, cmpOp); + } + } + + condError(aCond, "Unexpected condition id (%d)!", cond); + return false; } //--------------------------------------------------------------------------- @@ -4530,32 +4531,32 @@ bool condCheckSprite(DBloodActor* aCond, int cmpOp, bool PUSH) // //--------------------------------------------------------------------------- -void condUpdateObjectIndex(DBloodActor* oldActor, DBloodActor* newActor) +void condUpdateObjectIndex(DBloodActor* oldActor, DBloodActor* newActor) { - // update index in tracking conditions first - for (int i = 0; i < gTrackingCondsCount; i++) - { - TRCONDITION* pCond = &gCondition[i]; - for (unsigned k = 0; k < pCond->length; k++) - { - if (!pCond->obj[k].obj.isActor() || pCond->obj[k].obj.actor() != oldActor) continue; - pCond->obj[k].obj = EventObject(newActor); - break; - } - } + // update index in tracking conditions first + for (int i = 0; i < gTrackingCondsCount; i++) + { + TRCONDITION* pCond = &gCondition[i]; + for (unsigned k = 0; k < pCond->length; k++) + { + if (!pCond->obj[k].obj.isActor() || pCond->obj[k].obj.actor() != oldActor) continue; + pCond->obj[k].obj = EventObject(newActor); + break; + } + } - // puke... - auto oldSerial = EventObject(oldActor); - auto newSerial = EventObject(newActor); + // puke... + auto oldSerial = EventObject(oldActor); + auto newSerial = EventObject(newActor); - // then update serials - BloodStatIterator it(kStatModernCondition); - while (auto iActor = it.Next()) - { - if (iActor->condition[0] == oldSerial) iActor->condition[0] = newSerial; - if (iActor->condition[1] == oldSerial) iActor->condition[1] = newSerial; + // then update serials + BloodStatIterator it(kStatModernCondition); + while (auto iActor = it.Next()) + { + if (iActor->condition[0] == oldSerial) iActor->condition[0] = newSerial; + if (iActor->condition[1] == oldSerial) iActor->condition[1] = newSerial; - } + } } //--------------------------------------------------------------------------- @@ -4564,22 +4565,22 @@ void condUpdateObjectIndex(DBloodActor* oldActor, DBloodActor* newActor) // //--------------------------------------------------------------------------- -bool modernTypeSetSpriteState(DBloodActor* actor, int nState) +bool modernTypeSetSpriteState(DBloodActor* actor, int nState) { - if ((actor->xspr.busy & 0xffff) == 0 && actor->xspr.state == nState) - return false; + if ((actor->xspr.busy & 0xffff) == 0 && actor->xspr.state == nState) + return false; - actor->xspr.busy = IntToFixed(nState); - actor->xspr.state = nState; - - evKillActor(actor); - if (actor->xspr.restState != nState && actor->xspr.waitTime > 0) - evPostActor(actor, (actor->xspr.waitTime * 120) / 10, actor->xspr.restState ? kCmdOn : kCmdOff); + actor->xspr.busy = IntToFixed(nState); + actor->xspr.state = nState; - if (actor->xspr.txID != 0 && ((actor->xspr.triggerOn && actor->xspr.state) || (actor->xspr.triggerOff && !actor->xspr.state))) - modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + evKillActor(actor); + if (actor->xspr.restState != nState && actor->xspr.waitTime > 0) + evPostActor(actor, (actor->xspr.waitTime * 120) / 10, actor->xspr.restState ? kCmdOn : kCmdOff); - return true; + if (actor->xspr.txID != 0 && ((actor->xspr.triggerOn && actor->xspr.state) || (actor->xspr.triggerOff && !actor->xspr.state))) + modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + + return true; } //--------------------------------------------------------------------------- @@ -4588,22 +4589,22 @@ bool modernTypeSetSpriteState(DBloodActor* actor, int nState) // //--------------------------------------------------------------------------- -void modernTypeSendCommand(DBloodActor* actor, int destChannel, COMMAND_ID command) +void modernTypeSendCommand(DBloodActor* actor, int destChannel, COMMAND_ID command) { - switch (command) - { - case kCmdLink: - evSendActor(actor, destChannel, kCmdModernUse); // just send command to change properties - return; - case kCmdUnlock: - evSendActor(actor, destChannel, command); // send normal command first - evSendActor(actor, destChannel, kCmdModernUse); // then send command to change properties - return; - default: - evSendActor(actor, destChannel, kCmdModernUse); // send first command to change properties - evSendActor(actor, destChannel, command); // then send normal command - return; - } + switch (command) + { + case kCmdLink: + evSendActor(actor, destChannel, kCmdModernUse); // just send command to change properties + return; + case kCmdUnlock: + evSendActor(actor, destChannel, command); // send normal command first + evSendActor(actor, destChannel, kCmdModernUse); // then send command to change properties + return; + default: + evSendActor(actor, destChannel, kCmdModernUse); // send first command to change properties + evSendActor(actor, destChannel, command); // then send normal command + return; + } } //--------------------------------------------------------------------------- @@ -4612,148 +4613,148 @@ void modernTypeSendCommand(DBloodActor* actor, int destChannel, COMMAND_ID comma // //--------------------------------------------------------------------------- -void modernTypeTrigger(int destObjType, sectortype* destSect, walltype* destWall, DBloodActor* destactor, EVENT& event) +void modernTypeTrigger(int destObjType, sectortype* destSect, walltype* destWall, DBloodActor* destactor, EVENT& event) { - if (!event.isActor()) return; - auto sourceactor = event.getActor(); - if (!sourceactor || !sourceactor->hasX()) return; + if (!event.isActor()) return; + auto sourceactor = event.getActor(); + if (!sourceactor || !sourceactor->hasX()) return; - switch (destObjType) { - case OBJ_SECTOR: - if (!destSect || !destSect->hasX()) return; - break; - case OBJ_WALL: - if (!destWall || !destWall->hasX()) return; - break; - case OBJ_SPRITE: - { - if (!destactor) return; - if (destactor->spr.flags & kHitagFree) return; + switch (destObjType) { + case OBJ_SECTOR: + if (!destSect || !destSect->hasX()) return; + break; + case OBJ_WALL: + if (!destWall || !destWall->hasX()) return; + break; + case OBJ_SPRITE: + { + if (!destactor) return; + if (destactor->spr.flags & kHitagFree) return; - // allow redirect events received from some modern types. - // example: it allows to spawn FX effect if event was received from kModernEffectGen - // on many TX channels instead of just one. - switch (destactor->spr.type) - { - case kModernRandomTX: - case kModernSequentialTX: - if (destactor->xspr.command != kCmdLink || destactor->xspr.locked) break; // no redirect mode detected - switch (destactor->spr.type) - { - case kModernRandomTX: - useRandomTx(destactor, (COMMAND_ID)sourceactor->xspr.command, false); // set random TX id - break; - case kModernSequentialTX: - if (destactor->spr.flags & kModernTypeFlag1) - { - seqTxSendCmdAll(destactor, sourceactor, (COMMAND_ID)sourceactor->xspr.command, true); - return; - } - useSequentialTx(destactor, (COMMAND_ID)sourceactor->xspr.command, false); // set next TX id - break; - } - if (destactor->xspr.txID <= 0 || destactor->xspr.txID >= kChannelUserMax) return; - modernTypeSendCommand(sourceactor, destactor->xspr.txID, (COMMAND_ID)sourceactor->xspr.command); - return; - } - break; - } - default: - return; - } + // allow redirect events received from some modern types. + // example: it allows to spawn FX effect if event was received from kModernEffectGen + // on many TX channels instead of just one. + switch (destactor->spr.type) + { + case kModernRandomTX: + case kModernSequentialTX: + if (destactor->xspr.command != kCmdLink || destactor->xspr.locked) break; // no redirect mode detected + switch (destactor->spr.type) + { + case kModernRandomTX: + useRandomTx(destactor, (COMMAND_ID)sourceactor->xspr.command, false); // set random TX id + break; + case kModernSequentialTX: + if (destactor->spr.flags & kModernTypeFlag1) + { + seqTxSendCmdAll(destactor, sourceactor, (COMMAND_ID)sourceactor->xspr.command, true); + return; + } + useSequentialTx(destactor, (COMMAND_ID)sourceactor->xspr.command, false); // set next TX id + break; + } + if (destactor->xspr.txID <= 0 || destactor->xspr.txID >= kChannelUserMax) return; + modernTypeSendCommand(sourceactor, destactor->xspr.txID, (COMMAND_ID)sourceactor->xspr.command); + return; + } + break; + } + default: + return; + } - switch (sourceactor->spr.type) - { - // allows teleport any sprite from any location to the source destination - case kMarkerWarpDest: - if (destObjType != OBJ_SPRITE) break; - useTeleportTarget(sourceactor, destactor); - break; - // changes slope of sprite or sector - case kModernSlopeChanger: - switch (destObjType) - { - case OBJ_SPRITE: - case OBJ_SECTOR: - useSlopeChanger(sourceactor, destObjType, destSect, destactor); - break; - } - break; - case kModernSpriteDamager: - // damages xsprite via TX ID or xsprites in a sector - switch (destObjType) - { - case OBJ_SPRITE: - case OBJ_SECTOR: - useSpriteDamager(sourceactor, destObjType, destSect, destactor); - break; - } - break; - // can spawn any effect passed in data2 on it's or txID sprite - case kModernEffectSpawner: - if (destObjType != OBJ_SPRITE) break; - useEffectGen(sourceactor, destactor); - break; - // takes data2 as SEQ ID and spawns it on it's or TX ID object - case kModernSeqSpawner: - useSeqSpawnerGen(sourceactor, destObjType, destSect, destWall, destactor); - break; - // creates wind on TX ID sector - case kModernWindGenerator: - if (destObjType != OBJ_SECTOR || sourceactor->xspr.data2 < 0) break; - useSectorWindGen(sourceactor, destSect); - break; - // size and pan changer of sprite/wall/sector via TX ID - case kModernObjSizeChanger: - useObjResizer(sourceactor, destObjType, destSect, destWall, destactor); - break; - // iterate data filed value of destination object - case kModernObjDataAccumulator: - useIncDecGen(sourceactor, destObjType, destSect, destWall, destactor); - break; - // change data field value of destination object - case kModernObjDataChanger: - useDataChanger(sourceactor, destObjType, destSect, destWall, destactor); - break; - // change sector lighting dynamically - case kModernSectorFXChanger: - if (destObjType != OBJ_SECTOR) break; - useSectorLightChanger(sourceactor, destSect); - break; - // change target of dudes and make it fight - case kModernDudeTargetChanger: - if (destObjType != OBJ_SPRITE) break; - useTargetChanger(sourceactor, destactor); - break; - // change picture and palette of TX ID object - case kModernObjPicnumChanger: - usePictureChanger(sourceactor, destObjType, destSect, destWall, destactor); - break; - // change various properties - case kModernObjPropertiesChanger: - usePropertiesChanger(sourceactor, destObjType, destSect, destWall, destactor); - break; - // updated vanilla sound gen that now allows to play sounds on TX ID sprites - case kGenModernSound: - if (destObjType != OBJ_SPRITE) break; - useSoundGen(sourceactor, destactor); - break; - // updated ecto skull gen that allows to fire missile from TX ID sprites - case kGenModernMissileUniversal: - if (destObjType != OBJ_SPRITE) break; - useUniMissileGen(sourceactor, destactor); - break; - // spawn enemies on TX ID sprites - case kMarkerDudeSpawn: - if (destObjType != OBJ_SPRITE) break; - useDudeSpawn(sourceactor, destactor); - break; - // spawn custom dude on TX ID sprites - case kModernCustomDudeSpawn: - if (destObjType != OBJ_SPRITE) break; - useCustomDudeSpawn(sourceactor, destactor); - break; - } + switch (sourceactor->spr.type) + { + // allows teleport any sprite from any location to the source destination + case kMarkerWarpDest: + if (destObjType != OBJ_SPRITE) break; + useTeleportTarget(sourceactor, destactor); + break; + // changes slope of sprite or sector + case kModernSlopeChanger: + switch (destObjType) + { + case OBJ_SPRITE: + case OBJ_SECTOR: + useSlopeChanger(sourceactor, destObjType, destSect, destactor); + break; + } + break; + case kModernSpriteDamager: + // damages xsprite via TX ID or xsprites in a sector + switch (destObjType) + { + case OBJ_SPRITE: + case OBJ_SECTOR: + useSpriteDamager(sourceactor, destObjType, destSect, destactor); + break; + } + break; + // can spawn any effect passed in data2 on it's or txID sprite + case kModernEffectSpawner: + if (destObjType != OBJ_SPRITE) break; + useEffectGen(sourceactor, destactor); + break; + // takes data2 as SEQ ID and spawns it on it's or TX ID object + case kModernSeqSpawner: + useSeqSpawnerGen(sourceactor, destObjType, destSect, destWall, destactor); + break; + // creates wind on TX ID sector + case kModernWindGenerator: + if (destObjType != OBJ_SECTOR || sourceactor->xspr.data2 < 0) break; + useSectorWindGen(sourceactor, destSect); + break; + // size and pan changer of sprite/wall/sector via TX ID + case kModernObjSizeChanger: + useObjResizer(sourceactor, destObjType, destSect, destWall, destactor); + break; + // iterate data filed value of destination object + case kModernObjDataAccumulator: + useIncDecGen(sourceactor, destObjType, destSect, destWall, destactor); + break; + // change data field value of destination object + case kModernObjDataChanger: + useDataChanger(sourceactor, destObjType, destSect, destWall, destactor); + break; + // change sector lighting dynamically + case kModernSectorFXChanger: + if (destObjType != OBJ_SECTOR) break; + useSectorLightChanger(sourceactor, destSect); + break; + // change target of dudes and make it fight + case kModernDudeTargetChanger: + if (destObjType != OBJ_SPRITE) break; + useTargetChanger(sourceactor, destactor); + break; + // change picture and palette of TX ID object + case kModernObjPicnumChanger: + usePictureChanger(sourceactor, destObjType, destSect, destWall, destactor); + break; + // change various properties + case kModernObjPropertiesChanger: + usePropertiesChanger(sourceactor, destObjType, destSect, destWall, destactor); + break; + // updated vanilla sound gen that now allows to play sounds on TX ID sprites + case kGenModernSound: + if (destObjType != OBJ_SPRITE) break; + useSoundGen(sourceactor, destactor); + break; + // updated ecto skull gen that allows to fire missile from TX ID sprites + case kGenModernMissileUniversal: + if (destObjType != OBJ_SPRITE) break; + useUniMissileGen(sourceactor, destactor); + break; + // spawn enemies on TX ID sprites + case kMarkerDudeSpawn: + if (destObjType != OBJ_SPRITE) break; + useDudeSpawn(sourceactor, destactor); + break; + // spawn custom dude on TX ID sprites + case kModernCustomDudeSpawn: + if (destObjType != OBJ_SPRITE) break; + useCustomDudeSpawn(sourceactor, destactor); + break; + } } //--------------------------------------------------------------------------- @@ -4762,34 +4763,34 @@ void modernTypeTrigger(int destObjType, sectortype* destSect, walltype* destWall // //--------------------------------------------------------------------------- -DBloodActor* aiFightGetTargetInRange(DBloodActor* actor, int minDist, int maxDist, int data, int teamMode) +DBloodActor* aiFightGetTargetInRange(DBloodActor* actor, int minDist, int maxDist, int data, int teamMode) { - DUDEINFO* pDudeInfo = getDudeInfo(actor->spr.type); - - BloodStatIterator it(kStatDude); - while (auto targactor = it.Next()) - { - if (!aiFightDudeCanSeeTarget(actor, pDudeInfo, targactor)) continue; + DUDEINFO* pDudeInfo = getDudeInfo(actor->spr.type); - int dist = aiFightGetTargetDist(actor, pDudeInfo, targactor); - if (dist < minDist || dist > maxDist) continue; - else if (actor->GetTarget() == targactor) return targactor; - else if (!targactor->IsDudeActor() || targactor == actor || targactor->IsPlayerActor()) continue; - else if (IsBurningDude(targactor) || !IsKillableDude(targactor) || targactor->GetOwner() == actor) continue; - else if ((teamMode == 1 && actor->xspr.rxID == targactor->xspr.rxID) || aiFightMatesHaveSameTarget(actor, targactor, 1)) continue; - else if (data == 666 || targactor->xspr.data1 == data) - { - if (actor->GetTarget()) - { - int fineDist1 = aiFightGetFineTargetDist(actor, actor->GetTarget()); - int fineDist2 = aiFightGetFineTargetDist(actor, targactor); - if (fineDist1 < fineDist2) - continue; - } - return targactor; - } - } - return nullptr; + BloodStatIterator it(kStatDude); + while (auto targactor = it.Next()) + { + if (!aiFightDudeCanSeeTarget(actor, pDudeInfo, targactor)) continue; + + int dist = aiFightGetTargetDist(actor, pDudeInfo, targactor); + if (dist < minDist || dist > maxDist) continue; + else if (actor->GetTarget() == targactor) return targactor; + else if (!targactor->IsDudeActor() || targactor == actor || targactor->IsPlayerActor()) continue; + else if (IsBurningDude(targactor) || !IsKillableDude(targactor) || targactor->GetOwner() == actor) continue; + else if ((teamMode == 1 && actor->xspr.rxID == targactor->xspr.rxID) || aiFightMatesHaveSameTarget(actor, targactor, 1)) continue; + else if (data == 666 || targactor->xspr.data1 == data) + { + if (actor->GetTarget()) + { + int fineDist1 = aiFightGetFineTargetDist(actor, actor->GetTarget()); + int fineDist2 = aiFightGetFineTargetDist(actor, targactor); + if (fineDist1 < fineDist2) + continue; + } + return targactor; + } + } + return nullptr; } //--------------------------------------------------------------------------- @@ -4800,9 +4801,9 @@ DBloodActor* aiFightGetTargetInRange(DBloodActor* actor, int minDist, int maxDis DBloodActor* aiFightTargetIsPlayer(DBloodActor* actor) { - auto targ = actor->GetTarget(); - if (targ && targ->IsPlayerActor()) return targ; - return nullptr; + auto targ = actor->GetTarget(); + if (targ && targ->IsPlayerActor()) return targ; + return nullptr; } //--------------------------------------------------------------------------- @@ -4813,24 +4814,24 @@ DBloodActor* aiFightTargetIsPlayer(DBloodActor* actor) DBloodActor* aiFightGetMateTargets(DBloodActor* actor) { - int rx = actor->xspr.rxID; + int rx = actor->xspr.rxID; - for (int i = bucketHead[rx]; i < bucketHead[rx + 1]; i++) - { - if (rxBucket[i].isActor()) - { - auto mate = rxBucket[i].actor(); - if (!mate || !mate->hasX() || mate == actor || !mate->IsDudeActor()) - continue; + for (int i = bucketHead[rx]; i < bucketHead[rx + 1]; i++) + { + if (rxBucket[i].isActor()) + { + auto mate = rxBucket[i].actor(); + if (!mate || !mate->hasX() || mate == actor || !mate->IsDudeActor()) + continue; - if (mate->GetTarget()) - { - if (!mate->GetTarget()->IsPlayerActor()) - return mate->GetTarget(); - } - } - } - return nullptr; + if (mate->GetTarget()) + { + if (!mate->GetTarget()->IsPlayerActor()) + return mate->GetTarget(); + } + } + } + return nullptr; } //--------------------------------------------------------------------------- @@ -4839,22 +4840,22 @@ DBloodActor* aiFightGetMateTargets(DBloodActor* actor) // //--------------------------------------------------------------------------- -bool aiFightMatesHaveSameTarget(DBloodActor* leaderactor, DBloodActor* targetactor, int allow) +bool aiFightMatesHaveSameTarget(DBloodActor* leaderactor, DBloodActor* targetactor, int allow) { - int rx = leaderactor->xspr.rxID; + int rx = leaderactor->xspr.rxID; - for (int i = bucketHead[rx]; i < bucketHead[rx + 1]; i++) - { - if (!rxBucket[i].isActor()) continue; - auto mate = rxBucket[i].actor(); + for (int i = bucketHead[rx]; i < bucketHead[rx + 1]; i++) + { + if (!rxBucket[i].isActor()) continue; + auto mate = rxBucket[i].actor(); - if (!mate || !mate->hasX() || mate == leaderactor || !mate->IsDudeActor()) - continue; + if (!mate || !mate->hasX() || mate == leaderactor || !mate->IsDudeActor()) + continue; - if (mate->GetTarget() == targetactor && allow-- <= 0) - return true; - } - return false; + if (mate->GetTarget() == targetactor && allow-- <= 0) + return true; + } + return false; } //--------------------------------------------------------------------------- @@ -4863,29 +4864,29 @@ bool aiFightMatesHaveSameTarget(DBloodActor* leaderactor, DBloodActor* targetact // //--------------------------------------------------------------------------- -bool aiFightDudeCanSeeTarget(DBloodActor* dudeactor, DUDEINFO* pDudeInfo, DBloodActor* targetactor) +bool aiFightDudeCanSeeTarget(DBloodActor* dudeactor, DUDEINFO* pDudeInfo, DBloodActor* targetactor) { - int dx = targetactor->spr.pos.X - dudeactor->spr.pos.X; int dy = targetactor->spr.pos.Y - dudeactor->spr.pos.Y; + int dx = targetactor->spr.pos.X - dudeactor->spr.pos.X; int dy = targetactor->spr.pos.Y - dudeactor->spr.pos.Y; - // check target - if (approxDist(dx, dy) < pDudeInfo->seeDist) - { - int eyeAboveZ = pDudeInfo->eyeHeight * dudeactor->spr.yrepeat << 2; + // check target + if (approxDist(dx, dy) < pDudeInfo->seeDist) + { + int eyeAboveZ = pDudeInfo->eyeHeight * dudeactor->spr.yrepeat << 2; - // is there a line of sight to the target? - if (cansee(dudeactor->spr.pos.X, dudeactor->spr.pos.Y, dudeactor->spr.pos.Z, dudeactor->spr.sector(), targetactor->spr.pos.X, targetactor->spr.pos.Y, targetactor->spr.pos.Z - eyeAboveZ, targetactor->spr.sector())) - { - /*int nAngle = getangle(dx, dy); - int losAngle = ((1024 + nAngle - dudeactor->spr.ang) & 2047) - 1024; + // is there a line of sight to the target? + if (cansee(dudeactor->spr.pos.X, dudeactor->spr.pos.Y, dudeactor->spr.pos.Z, dudeactor->spr.sector(), targetactor->spr.pos.X, targetactor->spr.pos.Y, targetactor->spr.pos.Z - eyeAboveZ, targetactor->spr.sector())) + { + /*int nAngle = getangle(dx, dy); + int losAngle = ((1024 + nAngle - dudeactor->spr.ang) & 2047) - 1024; - // is the target visible? - if (abs(losAngle) < 2048) // 360 deg periphery here*/ - return true; - } + // is the target visible? + if (abs(losAngle) < 2048) // 360 deg periphery here*/ + return true; + } - } + } - return false; + return false; } @@ -4896,16 +4897,16 @@ bool aiFightDudeCanSeeTarget(DBloodActor* dudeactor, DUDEINFO* pDudeInfo, DBlood // //--------------------------------------------------------------------------- -void aiFightActivateDudes(int rx) +void aiFightActivateDudes(int rx) { - for (int i = bucketHead[rx]; i < bucketHead[rx + 1]; i++) - { - if (!rxBucket[i].isActor()) continue; - auto dudeactor = rxBucket[i].actor(); + for (int i = bucketHead[rx]; i < bucketHead[rx + 1]; i++) + { + if (!rxBucket[i].isActor()) continue; + auto dudeactor = rxBucket[i].actor(); - if (!dudeactor || !dudeactor->hasX() || !dudeactor->IsDudeActor() || dudeactor->xspr.aiState->stateType != kAiStateGenIdle) continue; - aiInitSprite(dudeactor); - } + if (!dudeactor || !dudeactor->hasX() || !dudeactor->IsDudeActor() || dudeactor->xspr.aiState->stateType != kAiStateGenIdle) continue; + aiInitSprite(dudeactor); + } } //--------------------------------------------------------------------------- @@ -4914,15 +4915,15 @@ void aiFightActivateDudes(int rx) // //--------------------------------------------------------------------------- -void aiFightFreeTargets(DBloodActor* actor) +void aiFightFreeTargets(DBloodActor* actor) { - BloodStatIterator it(kStatDude); - while (auto targetactor = it.Next()) - { - if (!targetactor->IsDudeActor() || !targetactor->hasX()) continue; - else if (targetactor->GetTarget() == actor) - aiSetTarget(targetactor, targetactor->spr.pos.X, targetactor->spr.pos.Y, targetactor->spr.pos.Z); - } + BloodStatIterator it(kStatDude); + while (auto targetactor = it.Next()) + { + if (!targetactor->IsDudeActor() || !targetactor->hasX()) continue; + else if (targetactor->GetTarget() == actor) + aiSetTarget(targetactor, targetactor->spr.pos.X, targetactor->spr.pos.Y, targetactor->spr.pos.Z); + } } //--------------------------------------------------------------------------- @@ -4931,18 +4932,18 @@ void aiFightFreeTargets(DBloodActor* actor) // //--------------------------------------------------------------------------- -void aiFightFreeAllTargets(DBloodActor* sourceactor) +void aiFightFreeAllTargets(DBloodActor* sourceactor) { - auto txID = sourceactor->xspr.txID; - if (txID <= 0) return; - for (int i = bucketHead[txID]; i < bucketHead[txID + 1]; i++) - { - if (!rxBucket[i].isActor()) continue; - auto actor = rxBucket[i].actor(); + auto txID = sourceactor->xspr.txID; + if (txID <= 0) return; + for (int i = bucketHead[txID]; i < bucketHead[txID + 1]; i++) + { + if (!rxBucket[i].isActor()) continue; + auto actor = rxBucket[i].actor(); - if (actor && actor->hasX()) - aiFightFreeTargets(actor); - } + if (actor && actor->hasX()) + aiFightFreeTargets(actor); + } } //--------------------------------------------------------------------------- @@ -4951,24 +4952,24 @@ void aiFightFreeAllTargets(DBloodActor* sourceactor) // //--------------------------------------------------------------------------- -bool aiFightDudeIsAffected(DBloodActor* dudeactor) +bool aiFightDudeIsAffected(DBloodActor* dudeactor) { - if (dudeactor->xspr.rxID <= 0 || dudeactor->xspr.locked == 1) return false; - BloodStatIterator it(kStatModernDudeTargetChanger); - while (auto actor = it.Next()) - { - if (!actor->hasX()) continue; - if (actor->xspr.txID <= 0 || actor->xspr.state != 1) continue; - for (int i = bucketHead[actor->xspr.txID]; i < bucketHead[actor->xspr.txID + 1]; i++) - { - if (!rxBucket[i].isActor()) continue; - auto rxactor = rxBucket[i].actor(); + if (dudeactor->xspr.rxID <= 0 || dudeactor->xspr.locked == 1) return false; + BloodStatIterator it(kStatModernDudeTargetChanger); + while (auto actor = it.Next()) + { + if (!actor->hasX()) continue; + if (actor->xspr.txID <= 0 || actor->xspr.state != 1) continue; + for (int i = bucketHead[actor->xspr.txID]; i < bucketHead[actor->xspr.txID + 1]; i++) + { + if (!rxBucket[i].isActor()) continue; + auto rxactor = rxBucket[i].actor(); - if (!rxactor || !rxactor->hasX() || !rxactor->IsDudeActor()) continue; - else if (rxactor == dudeactor) return true; - } - } - return false; + if (!rxactor || !rxactor->hasX() || !rxactor->IsDudeActor()) continue; + else if (rxactor == dudeactor) return true; + } + } + return false; } //--------------------------------------------------------------------------- @@ -4977,31 +4978,31 @@ bool aiFightDudeIsAffected(DBloodActor* dudeactor) // //--------------------------------------------------------------------------- -bool aiFightGetDudesForBattle(DBloodActor* actor) +bool aiFightGetDudesForBattle(DBloodActor* actor) { - auto txID = actor->xspr.txID; - for (int i = bucketHead[txID]; i < bucketHead[txID + 1]; i++) - { - if (!rxBucket[i].isActor()) continue; - auto rxactor = rxBucket[i].actor(); - if (!rxactor || !rxactor->hasX() || !rxactor->IsDudeActor()) continue; - if (rxactor->xspr.health > 0) return true; - } + auto txID = actor->xspr.txID; + for (int i = bucketHead[txID]; i < bucketHead[txID + 1]; i++) + { + if (!rxBucket[i].isActor()) continue; + auto rxactor = rxBucket[i].actor(); + if (!rxactor || !rxactor->hasX() || !rxactor->IsDudeActor()) continue; + if (rxactor->xspr.health > 0) return true; + } - // check redirected TX buckets - int rx = -1; - DBloodActor* pXRedir = nullptr; - while ((pXRedir = evrListRedirectors(OBJ_SPRITE, nullptr, nullptr, actor, pXRedir, &rx)) != nullptr) - { - for (int i = bucketHead[rx]; i < bucketHead[rx + 1]; i++) - { - if (!rxBucket[i].isActor()) continue; - auto rxactor = rxBucket[i].actor(); - if (!rxactor || !rxactor->hasX() || !rxactor->IsDudeActor()) continue; - if (rxactor->xspr.health > 0) return true; - } - } - return false; + // check redirected TX buckets + int rx = -1; + DBloodActor* pXRedir = nullptr; + while ((pXRedir = evrListRedirectors(OBJ_SPRITE, nullptr, nullptr, actor, pXRedir, &rx)) != nullptr) + { + for (int i = bucketHead[rx]; i < bucketHead[rx + 1]; i++) + { + if (!rxBucket[i].isActor()) continue; + auto rxactor = rxBucket[i].actor(); + if (!rxactor || !rxactor->hasX() || !rxactor->IsDudeActor()) continue; + if (rxactor->xspr.health > 0) return true; + } + } + return false; } //--------------------------------------------------------------------------- @@ -5010,27 +5011,27 @@ bool aiFightGetDudesForBattle(DBloodActor* actor) // //--------------------------------------------------------------------------- -void aiFightAlarmDudesInSight(DBloodActor* actor, int max) +void aiFightAlarmDudesInSight(DBloodActor* actor, int max) { - DUDEINFO* pDudeInfo = getDudeInfo(actor->spr.type); + DUDEINFO* pDudeInfo = getDudeInfo(actor->spr.type); - BloodStatIterator it(kStatDude); - while (auto dudeactor = it.Next()) - { - if (dudeactor == actor || !dudeactor->IsDudeActor() || !dudeactor->hasX()) - continue; + BloodStatIterator it(kStatDude); + while (auto dudeactor = it.Next()) + { + if (dudeactor == actor || !dudeactor->IsDudeActor() || !dudeactor->hasX()) + continue; - if (aiFightDudeCanSeeTarget(actor, pDudeInfo, dudeactor)) - { - if (dudeactor->GetTarget() != nullptr || dudeactor->xspr.rxID > 0) - continue; + if (aiFightDudeCanSeeTarget(actor, pDudeInfo, dudeactor)) + { + if (dudeactor->GetTarget() != nullptr || dudeactor->xspr.rxID > 0) + continue; - aiSetTarget(dudeactor, dudeactor->spr.pos.X, dudeactor->spr.pos.Y, dudeactor->spr.pos.Z); - aiActivateDude(dudeactor); - if (max-- < 1) - break; - } - } + aiSetTarget(dudeactor, dudeactor->spr.pos.X, dudeactor->spr.pos.Y, dudeactor->spr.pos.Z); + aiActivateDude(dudeactor); + if (max-- < 1) + break; + } + } } //--------------------------------------------------------------------------- @@ -5039,15 +5040,15 @@ void aiFightAlarmDudesInSight(DBloodActor* actor, int max) // //--------------------------------------------------------------------------- -bool aiFightUnitCanFly(DBloodActor* dude) +bool aiFightUnitCanFly(DBloodActor* dude) { - return (dude->IsDudeActor() && gDudeInfoExtra[dude->spr.type - kDudeBase].flying); + return (dude->IsDudeActor() && gDudeInfoExtra[dude->spr.type - kDudeBase].flying); } bool aiFightIsMeleeUnit(DBloodActor* dude) { - if (dude->spr.type == kDudeModernCustom) return (dude->hasX() && dudeIsMelee(dude)); - else return (dude->IsDudeActor() && gDudeInfoExtra[dude->spr.type - kDudeBase].melee); + if (dude->spr.type == kDudeModernCustom) return (dude->hasX() && dudeIsMelee(dude)); + else return (dude->IsDudeActor() && gDudeInfoExtra[dude->spr.type - kDudeBase].melee); } //--------------------------------------------------------------------------- @@ -5056,26 +5057,26 @@ bool aiFightIsMeleeUnit(DBloodActor* dude) // //--------------------------------------------------------------------------- -int aiFightGetTargetDist(DBloodActor* actor, DUDEINFO* pDudeInfo, DBloodActor* target) +int aiFightGetTargetDist(DBloodActor* actor, DUDEINFO* pDudeInfo, DBloodActor* target) { - int dx = target->spr.pos.X - actor->spr.pos.X; - int dy = target->spr.pos.Y - actor->spr.pos.Y; + int dx = target->spr.pos.X - actor->spr.pos.X; + int dy = target->spr.pos.Y - actor->spr.pos.Y; - int dist = approxDist(dx, dy); - if (dist <= pDudeInfo->meleeDist) return 0; - if (dist >= pDudeInfo->seeDist) return 13; - if (dist <= pDudeInfo->seeDist / 12) return 1; - if (dist <= pDudeInfo->seeDist / 11) return 2; - if (dist <= pDudeInfo->seeDist / 10) return 3; - if (dist <= pDudeInfo->seeDist / 9) return 4; - if (dist <= pDudeInfo->seeDist / 8) return 5; - if (dist <= pDudeInfo->seeDist / 7) return 6; - if (dist <= pDudeInfo->seeDist / 6) return 7; - if (dist <= pDudeInfo->seeDist / 5) return 8; - if (dist <= pDudeInfo->seeDist / 4) return 9; - if (dist <= pDudeInfo->seeDist / 3) return 10; - if (dist <= pDudeInfo->seeDist / 2) return 11; - return 12; + int dist = approxDist(dx, dy); + if (dist <= pDudeInfo->meleeDist) return 0; + if (dist >= pDudeInfo->seeDist) return 13; + if (dist <= pDudeInfo->seeDist / 12) return 1; + if (dist <= pDudeInfo->seeDist / 11) return 2; + if (dist <= pDudeInfo->seeDist / 10) return 3; + if (dist <= pDudeInfo->seeDist / 9) return 4; + if (dist <= pDudeInfo->seeDist / 8) return 5; + if (dist <= pDudeInfo->seeDist / 7) return 6; + if (dist <= pDudeInfo->seeDist / 6) return 7; + if (dist <= pDudeInfo->seeDist / 5) return 8; + if (dist <= pDudeInfo->seeDist / 4) return 9; + if (dist <= pDudeInfo->seeDist / 3) return 10; + if (dist <= pDudeInfo->seeDist / 2) return 11; + return 12; } //--------------------------------------------------------------------------- @@ -5086,11 +5087,11 @@ int aiFightGetTargetDist(DBloodActor* actor, DUDEINFO* pDudeInfo, DBloodActor* t int aiFightGetFineTargetDist(DBloodActor* actor, DBloodActor* target) { - int dx = target->spr.pos.X - actor->spr.pos.X; - int dy = target->spr.pos.Y - actor->spr.pos.Y; + int dx = target->spr.pos.X - actor->spr.pos.X; + int dy = target->spr.pos.Y - actor->spr.pos.Y; - int dist = approxDist(dx, dy); - return dist; + int dist = approxDist(dx, dy); + return dist; } //--------------------------------------------------------------------------- @@ -5101,12 +5102,12 @@ int aiFightGetFineTargetDist(DBloodActor* actor, DBloodActor* target) void sectorKillSounds(sectortype* pSector) { - BloodSectIterator it(pSector); - while (auto actor = it.Next()) - { - if (actor->spr.type != kSoundSector) continue; - sfxKill3DSound(actor); - } + BloodSectIterator it(pSector); + while (auto actor = it.Next()) + { + if (actor->spr.type != kSoundSector) continue; + sfxKill3DSound(actor); + } } //--------------------------------------------------------------------------- @@ -5115,17 +5116,17 @@ void sectorKillSounds(sectortype* pSector) // //--------------------------------------------------------------------------- -void sectorPauseMotion(sectortype* pSector) +void sectorPauseMotion(sectortype* pSector) { - if (!pSector->hasX()) return; - XSECTOR* pXSector = &pSector->xs(); - pXSector->unused1 = 1; - - evKillSector(pSector); + if (!pSector->hasX()) return; + XSECTOR* pXSector = &pSector->xs(); + pXSector->unused1 = 1; - sectorKillSounds(pSector); - if ((pXSector->busy == 0 && !pXSector->state) || (pXSector->busy == 65536 && pXSector->state)) - SectorEndSound(pSector, pXSector->state); + evKillSector(pSector); + + sectorKillSounds(pSector); + if ((pXSector->busy == 0 && !pXSector->state) || (pXSector->busy == 65536 && pXSector->state)) + SectorEndSound(pSector, pXSector->state); } //--------------------------------------------------------------------------- @@ -5134,95 +5135,95 @@ void sectorPauseMotion(sectortype* pSector) // //--------------------------------------------------------------------------- -void sectorContinueMotion(sectortype* pSector, EVENT event) +void sectorContinueMotion(sectortype* pSector, EVENT event) { - if (!pSector->hasX()) return; + if (!pSector->hasX()) return; - XSECTOR* pXSector = &pSector->xs(); - pXSector->unused1 = 0; - - int busyTimeA = pXSector->busyTimeA; - int waitTimeA = pXSector->waitTimeA; - int busyTimeB = pXSector->busyTimeB; - int waitTimeB = pXSector->waitTimeB; - if (pSector->type == kSectorPath) - { - if (!pXSector->marker0) return; - busyTimeA = busyTimeB = pXSector->marker0->xspr.busyTime; - waitTimeA = waitTimeB = pXSector->marker0->xspr.waitTime; - } - - if (!pXSector->interruptable && event.cmd != kCmdSectorMotionContinue - && ((!pXSector->state && pXSector->busy) || (pXSector->state && pXSector->busy != 65536))) - { - event.cmd = kCmdSectorMotionContinue; - } - else if (event.cmd == kCmdToggle) - { - event.cmd = (pXSector->state) ? kCmdOn : kCmdOff; - } + XSECTOR* pXSector = &pSector->xs(); + pXSector->unused1 = 0; - int nDelta = 1; - switch (event.cmd) - { - case kCmdOff: - if (pXSector->busy == 0) - { - if (pXSector->reTriggerB && waitTimeB) evPostSector(pSector, (waitTimeB * 120) / 10, kCmdOff); - return; - } - pXSector->state = 1; - nDelta = 65536 / ClipLow((busyTimeB * 120) / 10, 1); - break; + int busyTimeA = pXSector->busyTimeA; + int waitTimeA = pXSector->waitTimeA; + int busyTimeB = pXSector->busyTimeB; + int waitTimeB = pXSector->waitTimeB; + if (pSector->type == kSectorPath) + { + if (!pXSector->marker0) return; + busyTimeA = busyTimeB = pXSector->marker0->xspr.busyTime; + waitTimeA = waitTimeB = pXSector->marker0->xspr.waitTime; + } - case kCmdOn: - if (pXSector->busy == 65536) - { - if (pXSector->reTriggerA && waitTimeA) evPostSector(pSector, (waitTimeA * 120) / 10, kCmdOn); - return; - } - pXSector->state = 0; - nDelta = 65536 / ClipLow((busyTimeA * 120) / 10, 1); - break; + if (!pXSector->interruptable && event.cmd != kCmdSectorMotionContinue + && ((!pXSector->state && pXSector->busy) || (pXSector->state && pXSector->busy != 65536))) + { + event.cmd = kCmdSectorMotionContinue; + } + else if (event.cmd == kCmdToggle) + { + event.cmd = (pXSector->state) ? kCmdOn : kCmdOff; + } - case kCmdSectorMotionContinue: - nDelta = 65536 / ClipLow((((pXSector->state) ? busyTimeB : busyTimeA) * 120) / 10, 1); - break; - } + int nDelta = 1; + switch (event.cmd) + { + case kCmdOff: + if (pXSector->busy == 0) + { + if (pXSector->reTriggerB && waitTimeB) evPostSector(pSector, (waitTimeB * 120) / 10, kCmdOff); + return; + } + pXSector->state = 1; + nDelta = 65536 / ClipLow((busyTimeB * 120) / 10, 1); + break; - //bool crush = pXSector->Crush; - int busyFunc = BUSYID_0; - switch (pSector->type) - { - case kSectorZMotion: - busyFunc = BUSYID_2; - break; - case kSectorZMotionSprite: - busyFunc = BUSYID_1; - break; - case kSectorSlideMarked: - case kSectorSlide: - busyFunc = BUSYID_3; - break; - case kSectorRotateMarked: - case kSectorRotate: - busyFunc = BUSYID_4; - break; - case kSectorRotateStep: - busyFunc = BUSYID_5; - break; - case kSectorPath: - busyFunc = BUSYID_7; - break; - default: - I_Error("Unsupported sector type %d", pSector->type); - break; - } + case kCmdOn: + if (pXSector->busy == 65536) + { + if (pXSector->reTriggerA && waitTimeA) evPostSector(pSector, (waitTimeA * 120) / 10, kCmdOn); + return; + } + pXSector->state = 0; + nDelta = 65536 / ClipLow((busyTimeA * 120) / 10, 1); + break; - SectorStartSound(pSector, pXSector->state); - nDelta = (pXSector->state) ? -nDelta : nDelta; - BUSY b = { pSector, nDelta, (int)pXSector->busy, (BUSYID)busyFunc }; - gBusy.Push(b); + case kCmdSectorMotionContinue: + nDelta = 65536 / ClipLow((((pXSector->state) ? busyTimeB : busyTimeA) * 120) / 10, 1); + break; + } + + //bool crush = pXSector->Crush; + int busyFunc = BUSYID_0; + switch (pSector->type) + { + case kSectorZMotion: + busyFunc = BUSYID_2; + break; + case kSectorZMotionSprite: + busyFunc = BUSYID_1; + break; + case kSectorSlideMarked: + case kSectorSlide: + busyFunc = BUSYID_3; + break; + case kSectorRotateMarked: + case kSectorRotate: + busyFunc = BUSYID_4; + break; + case kSectorRotateStep: + busyFunc = BUSYID_5; + break; + case kSectorPath: + busyFunc = BUSYID_7; + break; + default: + I_Error("Unsupported sector type %d", pSector->type); + break; + } + + SectorStartSound(pSector, pXSector->state); + nDelta = (pXSector->state) ? -nDelta : nDelta; + BUSY b = { pSector, nDelta, (int)pXSector->busy, (BUSYID)busyFunc }; + gBusy.Push(b); } //--------------------------------------------------------------------------- @@ -5231,56 +5232,56 @@ void sectorContinueMotion(sectortype* pSector, EVENT event) // //--------------------------------------------------------------------------- -bool modernTypeOperateSector(sectortype* pSector, const EVENT& event) +bool modernTypeOperateSector(sectortype* pSector, const EVENT& event) { - auto pXSector = &pSector->xs(); - if (event.cmd >= kCmdLock && event.cmd <= kCmdToggleLock) - { - switch (event.cmd) - { - case kCmdLock: - pXSector->locked = 1; - break; - case kCmdUnlock: - pXSector->locked = 0; - break; - case kCmdToggleLock: - pXSector->locked = pXSector->locked ^ 1; - break; - } + auto pXSector = &pSector->xs(); + if (event.cmd >= kCmdLock && event.cmd <= kCmdToggleLock) + { + switch (event.cmd) + { + case kCmdLock: + pXSector->locked = 1; + break; + case kCmdUnlock: + pXSector->locked = 0; + break; + case kCmdToggleLock: + pXSector->locked = pXSector->locked ^ 1; + break; + } - switch (pSector->type) - { - case kSectorCounter: - if (pXSector->locked != 1) break; - SetSectorState(pSector, 0); - evPostSector(pSector, 0, kCallbackCounterCheck); - break; - } - return true; - - // continue motion of the paused sector - } - else if (pXSector->unused1) - { - switch (event.cmd) - { - case kCmdOff: - case kCmdOn: - case kCmdToggle: - case kCmdSectorMotionContinue: - sectorContinueMotion(pSector, event); - return true; - } - - // pause motion of the sector - } - else if (event.cmd == kCmdSectorMotionPause) - { - sectorPauseMotion(pSector); - return true; - } - return false; + switch (pSector->type) + { + case kSectorCounter: + if (pXSector->locked != 1) break; + SetSectorState(pSector, 0); + evPostSector(pSector, 0, kCallbackCounterCheck); + break; + } + return true; + + // continue motion of the paused sector + } + else if (pXSector->unused1) + { + switch (event.cmd) + { + case kCmdOff: + case kCmdOn: + case kCmdToggle: + case kCmdSectorMotionContinue: + sectorContinueMotion(pSector, event); + return true; + } + + // pause motion of the sector + } + else if (event.cmd == kCmdSectorMotionPause) + { + sectorPauseMotion(pSector); + return true; + } + return false; } //--------------------------------------------------------------------------- @@ -5291,13 +5292,13 @@ bool modernTypeOperateSector(sectortype* pSector, const EVENT& event) void useCustomDudeSpawn(DBloodActor* pSource, DBloodActor* pActor) { - genDudeSpawn(pSource, pActor, pActor->spr.clipdist << 1); + genDudeSpawn(pSource, pActor, pActor->spr.clipdist << 1); } void useDudeSpawn(DBloodActor* pSource, DBloodActor* pActor) { - if (randomSpawnDude(pSource, pActor, pActor->spr.clipdist << 1, 0) == nullptr) - nnExtSpawnDude(pSource, pActor, pSource->xspr.data1, pActor->spr.clipdist << 1, 0); + if (randomSpawnDude(pSource, pActor, pActor->spr.clipdist << 1, 0) == nullptr) + nnExtSpawnDude(pSource, pActor, pSource->xspr.data1, pActor->spr.clipdist << 1, 0); } //--------------------------------------------------------------------------- @@ -5306,508 +5307,508 @@ void useDudeSpawn(DBloodActor* pSource, DBloodActor* pActor) // //--------------------------------------------------------------------------- -bool modernTypeOperateSprite(DBloodActor* actor, EVENT& event) +bool modernTypeOperateSprite(DBloodActor* actor, EVENT& event) { - if (event.cmd >= kCmdLock && event.cmd <= kCmdToggleLock) - { - switch (event.cmd) - { - case kCmdLock: - actor->xspr.locked = 1; - break; - case kCmdUnlock: - actor->xspr.locked = 0; - break; - case kCmdToggleLock: - actor->xspr.locked = actor->xspr.locked ^ 1; - break; - } + if (event.cmd >= kCmdLock && event.cmd <= kCmdToggleLock) + { + switch (event.cmd) + { + case kCmdLock: + actor->xspr.locked = 1; + break; + case kCmdUnlock: + actor->xspr.locked = 0; + break; + case kCmdToggleLock: + actor->xspr.locked = actor->xspr.locked ^ 1; + break; + } - switch (actor->spr.type) - { - case kModernCondition: - case kModernConditionFalse: - actor->xspr.restState = 0; - if (actor->xspr.busyTime <= 0) break; - else if (!actor->xspr.locked) actor->xspr.busy = 0; - break; - } - return true; - } - else if (event.cmd == kCmdDudeFlagsSet) - { - if (!event.isActor()) - { - viewSetSystemMessage("Only sprites can use command #%d", event.cmd); - return true; + switch (actor->spr.type) + { + case kModernCondition: + case kModernConditionFalse: + actor->xspr.restState = 0; + if (actor->xspr.busyTime <= 0) break; + else if (!actor->xspr.locked) actor->xspr.busy = 0; + break; + } + return true; + } + else if (event.cmd == kCmdDudeFlagsSet) + { + if (!event.isActor()) + { + viewSetSystemMessage("Only sprites can use command #%d", event.cmd); + return true; - } - else - { - auto pEvActor = event.getActor(); - if (pEvActor && pEvActor->hasX()) - { + } + else + { + auto pEvActor = event.getActor(); + if (pEvActor && pEvActor->hasX()) + { - // copy dude flags from the source to destination sprite - aiPatrolFlagsMgr(pEvActor, actor, true, false); - } + // copy dude flags from the source to destination sprite + aiPatrolFlagsMgr(pEvActor, actor, true, false); + } - } - } - if (actor->spr.statnum == kStatDude && actor->IsDudeActor()) - { - switch (event.cmd) - { - case kCmdOff: - if (actor->xspr.state) SetSpriteState(actor, 0); - break; - case kCmdOn: - if (!actor->xspr.state) SetSpriteState(actor, 1); - if (!actor->IsDudeActor() || actor->IsPlayerActor() || actor->xspr.health <= 0) break; - else if (actor->xspr.aiState->stateType >= kAiStatePatrolBase && actor->xspr.aiState->stateType < kAiStatePatrolMax) - break; + } + } + if (actor->spr.statnum == kStatDude && actor->IsDudeActor()) + { + switch (event.cmd) + { + case kCmdOff: + if (actor->xspr.state) SetSpriteState(actor, 0); + break; + case kCmdOn: + if (!actor->xspr.state) SetSpriteState(actor, 1); + if (!actor->IsDudeActor() || actor->IsPlayerActor() || actor->xspr.health <= 0) break; + else if (actor->xspr.aiState->stateType >= kAiStatePatrolBase && actor->xspr.aiState->stateType < kAiStatePatrolMax) + break; - switch (actor->xspr.aiState->stateType) - { - case kAiStateIdle: - case kAiStateGenIdle: - aiActivateDude(actor); - break; - } - break; + switch (actor->xspr.aiState->stateType) + { + case kAiStateIdle: + case kAiStateGenIdle: + aiActivateDude(actor); + break; + } + break; - case kCmdDudeFlagsSet: - if (event.isActor()) - { - auto pEvActor = event.getActor(); - if (!pEvActor || !pEvActor->hasX()) break; - else aiPatrolFlagsMgr(pEvActor, actor, false, true); // initialize patrol dude with possible new flags - } - break; + case kCmdDudeFlagsSet: + if (event.isActor()) + { + auto pEvActor = event.getActor(); + if (!pEvActor || !pEvActor->hasX()) break; + else aiPatrolFlagsMgr(pEvActor, actor, false, true); // initialize patrol dude with possible new flags + } + break; - default: - if (!actor->xspr.state) evPostActor(actor, 0, kCmdOn); - else evPostActor(actor, 0, kCmdOff); - break; - } - return true; - } + default: + if (!actor->xspr.state) evPostActor(actor, 0, kCmdOn); + else evPostActor(actor, 0, kCmdOff); + break; + } + return true; + } - switch (actor->spr.type) - { - default: - return false; // no modern type found to work with, go normal OperateSprite(); - case kThingBloodBits: - case kThingBloodChunks: - // dude to thing morphing causing a lot of problems since it continues receiving commands after dude is dead. - // this leads to weird stuff like exploding with gargoyle gib or corpse disappearing immediately. - // let's allow only specific commands here to avoid this. - if (actor->spr.inittype < kDudeBase || actor->spr.inittype >= kDudeMax) return false; - else if (event.cmd != kCmdToggle && event.cmd != kCmdOff && event.cmd != kCmdSpriteImpact) return true; - DudeToGibCallback1(0, actor); // set proper gib type just in case DATAs was changed from the outside. - return false; + switch (actor->spr.type) + { + default: + return false; // no modern type found to work with, go normal OperateSprite(); + case kThingBloodBits: + case kThingBloodChunks: + // dude to thing morphing causing a lot of problems since it continues receiving commands after dude is dead. + // this leads to weird stuff like exploding with gargoyle gib or corpse disappearing immediately. + // let's allow only specific commands here to avoid this. + if (actor->spr.inittype < kDudeBase || actor->spr.inittype >= kDudeMax) return false; + else if (event.cmd != kCmdToggle && event.cmd != kCmdOff && event.cmd != kCmdSpriteImpact) return true; + DudeToGibCallback1(0, actor); // set proper gib type just in case DATAs was changed from the outside. + return false; - case kModernCondition: - case kModernConditionFalse: - if (!actor->xspr.isTriggered) useCondition(actor, event); - return true; + case kModernCondition: + case kModernConditionFalse: + if (!actor->xspr.isTriggered) useCondition(actor, event); + return true; - // add spawn random dude feature - works only if at least 2 data fields are not empty. - case kMarkerDudeSpawn: - if (!gGameOptions.nMonsterSettings) return true; - else if (!(actor->spr.flags & kModernTypeFlag4)) useDudeSpawn(actor, actor); - else if (actor->xspr.txID) evSendActor(actor, actor->xspr.txID, kCmdModernUse); - return true; + // add spawn random dude feature - works only if at least 2 data fields are not empty. + case kMarkerDudeSpawn: + if (!gGameOptions.nMonsterSettings) return true; + else if (!(actor->spr.flags & kModernTypeFlag4)) useDudeSpawn(actor, actor); + else if (actor->xspr.txID) evSendActor(actor, actor->xspr.txID, kCmdModernUse); + return true; - case kModernCustomDudeSpawn: - if (!gGameOptions.nMonsterSettings) return true; - else if (!(actor->spr.flags & kModernTypeFlag4)) useCustomDudeSpawn(actor, actor); - else if (actor->xspr.txID) evSendActor(actor, actor->xspr.txID, kCmdModernUse); - return true; + case kModernCustomDudeSpawn: + if (!gGameOptions.nMonsterSettings) return true; + else if (!(actor->spr.flags & kModernTypeFlag4)) useCustomDudeSpawn(actor, actor); + else if (actor->xspr.txID) evSendActor(actor, actor->xspr.txID, kCmdModernUse); + return true; - case kModernRandomTX: // random Event Switch takes random data field and uses it as TX ID - case kModernSequentialTX: // sequential Switch takes values from data fields starting from data1 and uses it as TX ID - if (actor->xspr.command == kCmdLink) return true; // work as event redirector - switch (actor->spr.type) - { - case kModernRandomTX: - useRandomTx(actor, (COMMAND_ID)actor->xspr.command, true); - break; + case kModernRandomTX: // random Event Switch takes random data field and uses it as TX ID + case kModernSequentialTX: // sequential Switch takes values from data fields starting from data1 and uses it as TX ID + if (actor->xspr.command == kCmdLink) return true; // work as event redirector + switch (actor->spr.type) + { + case kModernRandomTX: + useRandomTx(actor, (COMMAND_ID)actor->xspr.command, true); + break; - case kModernSequentialTX: - if (!(actor->spr.flags & kModernTypeFlag1)) useSequentialTx(actor, (COMMAND_ID)actor->xspr.command, true); - else seqTxSendCmdAll(actor, actor, (COMMAND_ID)actor->xspr.command, false); - break; - } - return true; + case kModernSequentialTX: + if (!(actor->spr.flags & kModernTypeFlag1)) useSequentialTx(actor, (COMMAND_ID)actor->xspr.command, true); + else seqTxSendCmdAll(actor, actor, (COMMAND_ID)actor->xspr.command, false); + break; + } + return true; - case kModernSpriteDamager: - switch (event.cmd) - { - case kCmdOff: - if (actor->xspr.state == 1) SetSpriteState(actor, 0); - break; - case kCmdOn: - evKillActor(actor); // queue overflow protect - if (actor->xspr.state == 0) SetSpriteState(actor, 1); - [[fallthrough]]; - case kCmdRepeat: - if (actor->xspr.txID > 0) modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); - else if (actor->xspr.data1 == 0 && actor->spr.insector()) useSpriteDamager(actor, OBJ_SECTOR, actor->spr.sector(), nullptr); - else if (actor->xspr.data1 >= 666 && actor->xspr.data1 < 669) useSpriteDamager(actor, -1, nullptr, nullptr); - else - { - PLAYER* pPlayer = getPlayerById(actor->xspr.data1); - if (pPlayer != NULL) - useSpriteDamager(actor, OBJ_SPRITE, 0, pPlayer->actor); - } + case kModernSpriteDamager: + switch (event.cmd) + { + case kCmdOff: + if (actor->xspr.state == 1) SetSpriteState(actor, 0); + break; + case kCmdOn: + evKillActor(actor); // queue overflow protect + if (actor->xspr.state == 0) SetSpriteState(actor, 1); + [[fallthrough]]; + case kCmdRepeat: + if (actor->xspr.txID > 0) modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + else if (actor->xspr.data1 == 0 && actor->spr.insector()) useSpriteDamager(actor, OBJ_SECTOR, actor->spr.sector(), nullptr); + else if (actor->xspr.data1 >= 666 && actor->xspr.data1 < 669) useSpriteDamager(actor, -1, nullptr, nullptr); + else + { + PLAYER* pPlayer = getPlayerById(actor->xspr.data1); + if (pPlayer != NULL) + useSpriteDamager(actor, OBJ_SPRITE, 0, pPlayer->actor); + } - if (actor->xspr.busyTime > 0) - evPostActor(actor, actor->xspr.busyTime, kCmdRepeat); - break; + if (actor->xspr.busyTime > 0) + evPostActor(actor, actor->xspr.busyTime, kCmdRepeat); + break; - default: - if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); - else evPostActor(actor, 0, kCmdOff); - break; - } - return true; + default: + if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); + else evPostActor(actor, 0, kCmdOff); + break; + } + return true; - case kMarkerWarpDest: - if (actor->xspr.txID <= 0) { - - PLAYER* pPlayer = getPlayerById(actor->xspr.data1); - if (pPlayer != NULL && SetSpriteState(actor, actor->xspr.state ^ 1) == 1) - useTeleportTarget(actor, pPlayer->actor); - return true; - } - [[fallthrough]]; - case kModernObjPropertiesChanger: - if (actor->xspr.txID <= 0) - { - if (SetSpriteState(actor, actor->xspr.state ^ 1) == 1) - usePropertiesChanger(actor, -1, nullptr, nullptr, nullptr); - return true; - } - [[fallthrough]]; - case kModernSlopeChanger: - case kModernObjSizeChanger: - case kModernObjPicnumChanger: - case kModernSectorFXChanger: - case kModernObjDataChanger: - modernTypeSetSpriteState(actor, actor->xspr.state ^ 1); - return true; + case kMarkerWarpDest: + if (actor->xspr.txID <= 0) { - case kModernSeqSpawner: - case kModernEffectSpawner: - switch (event.cmd) - { - case kCmdOff: - if (actor->xspr.state == 1) SetSpriteState(actor, 0); - break; - case kCmdOn: - evKillActor(actor); // queue overflow protect - if (actor->xspr.state == 0) SetSpriteState(actor, 1); - if (actor->spr.type == kModernSeqSpawner) seqSpawnerOffSameTx(actor); - [[fallthrough]]; - case kCmdRepeat: - if (actor->xspr.txID > 0) modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); - else if (actor->spr.type == kModernSeqSpawner) useSeqSpawnerGen(actor, OBJ_SPRITE, nullptr, nullptr, actor); - else useEffectGen(actor, nullptr); - - if (actor->xspr.busyTime > 0) - evPostActor(actor, ClipLow((int(actor->xspr.busyTime) + Random2(actor->xspr.data1)) * 120 / 10, 0), kCmdRepeat); - break; - default: - if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); - else evPostActor(actor, 0, kCmdOff); - break; - } - return true; + PLAYER* pPlayer = getPlayerById(actor->xspr.data1); + if (pPlayer != NULL && SetSpriteState(actor, actor->xspr.state ^ 1) == 1) + useTeleportTarget(actor, pPlayer->actor); + return true; + } + [[fallthrough]]; + case kModernObjPropertiesChanger: + if (actor->xspr.txID <= 0) + { + if (SetSpriteState(actor, actor->xspr.state ^ 1) == 1) + usePropertiesChanger(actor, -1, nullptr, nullptr, nullptr); + return true; + } + [[fallthrough]]; + case kModernSlopeChanger: + case kModernObjSizeChanger: + case kModernObjPicnumChanger: + case kModernSectorFXChanger: + case kModernObjDataChanger: + modernTypeSetSpriteState(actor, actor->xspr.state ^ 1); + return true; - case kModernWindGenerator: - switch (event.cmd) - { - case kCmdOff: - windGenStopWindOnSectors(actor); - if (actor->xspr.state == 1) SetSpriteState(actor, 0); - break; - case kCmdOn: - evKillActor(actor); // queue overflow protect - if (actor->xspr.state == 0) SetSpriteState(actor, 1); - [[fallthrough]]; - case kCmdRepeat: - if (actor->xspr.txID > 0) modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); - else useSectorWindGen(actor, nullptr); + case kModernSeqSpawner: + case kModernEffectSpawner: + switch (event.cmd) + { + case kCmdOff: + if (actor->xspr.state == 1) SetSpriteState(actor, 0); + break; + case kCmdOn: + evKillActor(actor); // queue overflow protect + if (actor->xspr.state == 0) SetSpriteState(actor, 1); + if (actor->spr.type == kModernSeqSpawner) seqSpawnerOffSameTx(actor); + [[fallthrough]]; + case kCmdRepeat: + if (actor->xspr.txID > 0) modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + else if (actor->spr.type == kModernSeqSpawner) useSeqSpawnerGen(actor, OBJ_SPRITE, nullptr, nullptr, actor); + else useEffectGen(actor, nullptr); - if (actor->xspr.busyTime > 0) evPostActor(actor, actor->xspr.busyTime, kCmdRepeat); - break; - default: - if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); - else evPostActor(actor, 0, kCmdOff); - break; - } - return true; - case kModernDudeTargetChanger: + if (actor->xspr.busyTime > 0) + evPostActor(actor, ClipLow((int(actor->xspr.busyTime) + Random2(actor->xspr.data1)) * 120 / 10, 0), kCmdRepeat); + break; + default: + if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); + else evPostActor(actor, 0, kCmdOff); + break; + } + return true; - // this one is required if data4 of generator was dynamically changed - // it turns monsters in normal idle state instead of genIdle, so they not ignore the world. - if (actor->xspr.dropMsg == 3 && 3 != actor->xspr.data4) - aiFightActivateDudes(actor->xspr.txID); + case kModernWindGenerator: + switch (event.cmd) + { + case kCmdOff: + windGenStopWindOnSectors(actor); + if (actor->xspr.state == 1) SetSpriteState(actor, 0); + break; + case kCmdOn: + evKillActor(actor); // queue overflow protect + if (actor->xspr.state == 0) SetSpriteState(actor, 1); + [[fallthrough]]; + case kCmdRepeat: + if (actor->xspr.txID > 0) modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + else useSectorWindGen(actor, nullptr); - switch (event.cmd) - { - case kCmdOff: - if (actor->xspr.data4 == 3) aiFightActivateDudes(actor->xspr.txID); - if (actor->xspr.state == 1) SetSpriteState(actor, 0); - break; - case kCmdOn: - evKillActor(actor); // queue overflow protect - if (actor->xspr.state == 0) SetSpriteState(actor, 1); - [[fallthrough]]; - case kCmdRepeat: - if (actor->xspr.txID <= 0 || !aiFightGetDudesForBattle(actor)) - { - aiFightFreeAllTargets(actor); - evPostActor(actor, 0, kCmdOff); - break; - } - else - { - modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); - } + if (actor->xspr.busyTime > 0) evPostActor(actor, actor->xspr.busyTime, kCmdRepeat); + break; + default: + if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); + else evPostActor(actor, 0, kCmdOff); + break; + } + return true; + case kModernDudeTargetChanger: - if (actor->xspr.busyTime > 0) evPostActor(actor, actor->xspr.busyTime, kCmdRepeat); - break; - default: - if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); - else evPostActor(actor, 0, kCmdOff); - break; - } - actor->xspr.dropMsg = uint8_t(actor->xspr.data4); - return true; + // this one is required if data4 of generator was dynamically changed + // it turns monsters in normal idle state instead of genIdle, so they not ignore the world. + if (actor->xspr.dropMsg == 3 && 3 != actor->xspr.data4) + aiFightActivateDudes(actor->xspr.txID); - case kModernObjDataAccumulator: - switch (event.cmd) { - case kCmdOff: - if (actor->xspr.state == 1) SetSpriteState(actor, 0); - break; - case kCmdOn: - evKillActor(actor); // queue overflow protect - if (actor->xspr.state == 0) SetSpriteState(actor, 1); - [[fallthrough]]; - case kCmdRepeat: - // force OFF after *all* TX objects reach the goal value - if (actor->spr.flags == kModernTypeFlag0 && incDecGoalValueIsReached(actor)) - { - evPostActor(actor, 0, kCmdOff); - break; - } - - modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); - if (actor->xspr.busyTime > 0) evPostActor(actor, actor->xspr.busyTime, kCmdRepeat); - break; - default: - if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); - else evPostActor(actor, 0, kCmdOff); - break; - } - return true; - case kModernRandom: - case kModernRandom2: - switch (event.cmd) - { - case kCmdOff: - if (actor->xspr.state == 1) SetSpriteState(actor, 0); - break; - case kCmdOn: - evKillActor(actor); // queue overflow protect - if (actor->xspr.state == 0) SetSpriteState(actor, 1); - [[fallthrough]]; - case kCmdRepeat: - useRandomItemGen(actor); - if (actor->xspr.busyTime > 0) - evPostActor(actor, (120 * actor->xspr.busyTime) / 10, kCmdRepeat); - break; - default: - if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); - else evPostActor(actor, 0, kCmdOff); - break; - } - return true; + switch (event.cmd) + { + case kCmdOff: + if (actor->xspr.data4 == 3) aiFightActivateDudes(actor->xspr.txID); + if (actor->xspr.state == 1) SetSpriteState(actor, 0); + break; + case kCmdOn: + evKillActor(actor); // queue overflow protect + if (actor->xspr.state == 0) SetSpriteState(actor, 1); + [[fallthrough]]; + case kCmdRepeat: + if (actor->xspr.txID <= 0 || !aiFightGetDudesForBattle(actor)) + { + aiFightFreeAllTargets(actor); + evPostActor(actor, 0, kCmdOff); + break; + } + else + { + modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + } - case kModernThingTNTProx: - if (actor->spr.statnum != kStatRespawn) - { - switch (event.cmd) - { - case kCmdSpriteProximity: - if (actor->xspr.state) break; - sfxPlay3DSound(actor, 452, 0, 0); - evPostActor(actor, 30, kCmdOff); - actor->xspr.state = 1; - [[fallthrough]]; - case kCmdOn: - sfxPlay3DSound(actor, 451, 0, 0); - actor->xspr.Proximity = 1; - break; - default: - actExplodeSprite(actor); - break; - } - } - return true; - case kModernThingEnemyLifeLeech: - dudeLeechOperate(actor, event); - return true; - case kModernPlayerControl: { // WIP - PLAYER* pPlayer = NULL; int cmd = (event.cmd >= kCmdNumberic) ? event.cmd : actor->xspr.command; - if ((pPlayer = getPlayerById(actor->xspr.data1)) == NULL - || ((cmd < 67 || cmd > 68) && !modernTypeSetSpriteState(actor, actor->xspr.state ^ 1))) - return true; + if (actor->xspr.busyTime > 0) evPostActor(actor, actor->xspr.busyTime, kCmdRepeat); + break; + default: + if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); + else evPostActor(actor, 0, kCmdOff); + break; + } + actor->xspr.dropMsg = uint8_t(actor->xspr.data4); + return true; - TRPLAYERCTRL* pCtrl = &gPlayerCtrl[pPlayer->nPlayer]; + case kModernObjDataAccumulator: + switch (event.cmd) { + case kCmdOff: + if (actor->xspr.state == 1) SetSpriteState(actor, 0); + break; + case kCmdOn: + evKillActor(actor); // queue overflow protect + if (actor->xspr.state == 0) SetSpriteState(actor, 1); + [[fallthrough]]; + case kCmdRepeat: + // force OFF after *all* TX objects reach the goal value + if (actor->spr.flags == kModernTypeFlag0 && incDecGoalValueIsReached(actor)) + { + evPostActor(actor, 0, kCmdOff); + break; + } - /// !!! COMMANDS OF THE CURRENT SPRITE, NOT OF THE EVENT !!! /// - if ((cmd -= kCmdNumberic) < 0) return true; - else if (pPlayer->actor->xspr.health <= 0) - { - - switch (cmd) { - case 36: - actHealDude(pPlayer->actor, ((actor->xspr.data2 > 0) ? ClipHigh(actor->xspr.data2, 200) : getDudeInfo(pPlayer->actor->spr.type)->startHealth), 200); - pPlayer->curWeapon = kWeapPitchFork; - break; - } - return true; - } + modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + if (actor->xspr.busyTime > 0) evPostActor(actor, actor->xspr.busyTime, kCmdRepeat); + break; + default: + if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); + else evPostActor(actor, 0, kCmdOff); + break; + } + return true; + case kModernRandom: + case kModernRandom2: + switch (event.cmd) + { + case kCmdOff: + if (actor->xspr.state == 1) SetSpriteState(actor, 0); + break; + case kCmdOn: + evKillActor(actor); // queue overflow protect + if (actor->xspr.state == 0) SetSpriteState(actor, 1); + [[fallthrough]]; + case kCmdRepeat: + useRandomItemGen(actor); + if (actor->xspr.busyTime > 0) + evPostActor(actor, (120 * actor->xspr.busyTime) / 10, kCmdRepeat); + break; + default: + if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); + else evPostActor(actor, 0, kCmdOff); + break; + } + return true; - switch (cmd) - { - case 0: // 64 (player life form) - if (actor->xspr.data2 < kModeHuman || actor->xspr.data2 > kModeHumanGrown) break; - else trPlayerCtrlSetRace(actor->xspr.data2, pPlayer); - break; - case 1: // 65 (move speed and jump height) - // player movement speed (for all races and postures) - if (valueIsBetween(actor->xspr.data2, -1, 32767)) - trPlayerCtrlSetMoveSpeed(actor->xspr.data2, pPlayer); + case kModernThingTNTProx: + if (actor->spr.statnum != kStatRespawn) + { + switch (event.cmd) + { + case kCmdSpriteProximity: + if (actor->xspr.state) break; + sfxPlay3DSound(actor, 452, 0, 0); + evPostActor(actor, 30, kCmdOff); + actor->xspr.state = 1; + [[fallthrough]]; + case kCmdOn: + sfxPlay3DSound(actor, 451, 0, 0); + actor->xspr.Proximity = 1; + break; + default: + actExplodeSprite(actor); + break; + } + } + return true; + case kModernThingEnemyLifeLeech: + dudeLeechOperate(actor, event); + return true; + case kModernPlayerControl: { // WIP + PLAYER* pPlayer = NULL; int cmd = (event.cmd >= kCmdNumberic) ? event.cmd : actor->xspr.command; + if ((pPlayer = getPlayerById(actor->xspr.data1)) == NULL + || ((cmd < 67 || cmd > 68) && !modernTypeSetSpriteState(actor, actor->xspr.state ^ 1))) + return true; - // player jump height (for all races and stand posture only) - if (valueIsBetween(actor->xspr.data3, -1, 32767)) - trPlayerCtrlSetJumpHeight(actor->xspr.data3, pPlayer); - break; - case 2: // 66 (player screen effects) - if (actor->xspr.data3 < 0) break; - else trPlayerCtrlSetScreenEffect(actor->xspr.data2, actor->xspr.data3, pPlayer); - break; - case 3: // 67 (start playing qav scene) - trPlayerCtrlStartScene(actor, pPlayer, (actor->xspr.data4 == 1) ? true : false); - break; - case 4: // 68 (stop playing qav scene) - if (actor->xspr.data2 > 0 && actor->xspr.data2 != pPlayer->sceneQav) break; - else trPlayerCtrlStopScene(pPlayer); - break; - case 5: // 69 (set player look angle, TO-DO: if tx > 0, take a look on TX ID sprite) - //data4 is reserved - if (actor->xspr.data4 != 0) break; - else if (valueIsBetween(actor->xspr.data2, -128, 128)) - trPlayerCtrlSetLookAngle(actor->xspr.data2, pPlayer); - break; - case 6: // 70 (erase player stuff...) - if (actor->xspr.data2 < 0) break; - else trPlayerCtrlEraseStuff(actor->xspr.data2, pPlayer); - break; - case 7: // 71 (give something to player...) - if (actor->xspr.data2 <= 0) break; - else trPlayerCtrlGiveStuff(actor->xspr.data2, actor->xspr.data3,actor->xspr.data4, pPlayer, pCtrl); - break; - case 8: // 72 (use inventory item) - if (actor->xspr.data2 < 1 || actor->xspr.data2 > 5) break; - else trPlayerCtrlUsePackItem(actor->xspr.data2, actor->xspr.data3, actor->xspr.data4, pPlayer, event.cmd); - break; - case 9: // 73 (set player's sprite angle, TO-DO: if tx > 0, take a look on TX ID sprite) - //data4 is reserved - if (actor->xspr.data4 != 0) break; - else if (actor->spr.flags & kModernTypeFlag1) - { - pPlayer->angle.settarget(actor->spr.ang); - pPlayer->angle.lockinput(); - } - else if (valueIsBetween(actor->xspr.data2, -kAng360, kAng360)) - { - pPlayer->angle.settarget(actor->xspr.data2); - pPlayer->angle.lockinput(); - } - break; - case 10: // 74 (de)activate powerup - if (actor->xspr.data2 <= 0 || actor->xspr.data2 > (kMaxAllowedPowerup - (kMinAllowedPowerup << 1) + 1)) break; - trPlayerCtrlUsePowerup(actor, pPlayer, event.cmd); - break; - // case 11: // 75 (print the book) - // data2: RFF TXT id - // data3: background tile - // data4: font base tile - // pal: font / background palette - // hitag: - // d1: 0: print whole text at a time, 1: print line by line, 2: word by word, 3: letter by letter - // d2: 1: force pause the game (sp only) - // d3: 1: inherit palette for font, 2: inherit palette for background, 3: both - // busyTime: speed of word/letter/line printing - // waitTime: if TX ID > 0 and TX ID object is book reader, trigger it? - //break; + TRPLAYERCTRL* pCtrl = &gPlayerCtrl[pPlayer->nPlayer]; - } - } - return true; + /// !!! COMMANDS OF THE CURRENT SPRITE, NOT OF THE EVENT !!! /// + if ((cmd -= kCmdNumberic) < 0) return true; + else if (pPlayer->actor->xspr.health <= 0) + { - case kGenModernSound: - switch (event.cmd) { - case kCmdOff: - if (actor->xspr.state == 1) SetSpriteState(actor, 0); - break; - case kCmdOn: - evKillActor(actor); // queue overflow protect - if (actor->xspr.state == 0) SetSpriteState(actor, 1); - [[fallthrough]]; - case kCmdRepeat: - if (actor->xspr.txID) modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); - else useSoundGen(actor, actor); - - if (actor->xspr.busyTime > 0) - evPostActor(actor, (120 * actor->xspr.busyTime) / 10, kCmdRepeat); - break; - default: - if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); - else evPostActor(actor, 0, kCmdOff); - break; - } - return true; - case kGenModernMissileUniversal: - switch (event.cmd) - { - case kCmdOff: - if (actor->xspr.state == 1) SetSpriteState(actor, 0); - break; - case kCmdOn: - evKillActor(actor); // queue overflow protect - if (actor->xspr.state == 0) SetSpriteState(actor, 1); - [[fallthrough]]; - case kCmdRepeat: - if (actor->xspr.txID) modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); - else useUniMissileGen(actor, actor); - - if (actor->xspr.busyTime > 0) - evPostActor(actor, (120 * actor->xspr.busyTime) / 10, kCmdRepeat); + switch (cmd) { + case 36: + actHealDude(pPlayer->actor, ((actor->xspr.data2 > 0) ? ClipHigh(actor->xspr.data2, 200) : getDudeInfo(pPlayer->actor->spr.type)->startHealth), 200); + pPlayer->curWeapon = kWeapPitchFork; + break; + } + return true; + } - break; - default: - if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); - else evPostActor(actor, 0, kCmdOff); - break; - } - return true; - } + switch (cmd) + { + case 0: // 64 (player life form) + if (actor->xspr.data2 < kModeHuman || actor->xspr.data2 > kModeHumanGrown) break; + else trPlayerCtrlSetRace(actor->xspr.data2, pPlayer); + break; + case 1: // 65 (move speed and jump height) + // player movement speed (for all races and postures) + if (valueIsBetween(actor->xspr.data2, -1, 32767)) + trPlayerCtrlSetMoveSpeed(actor->xspr.data2, pPlayer); + + // player jump height (for all races and stand posture only) + if (valueIsBetween(actor->xspr.data3, -1, 32767)) + trPlayerCtrlSetJumpHeight(actor->xspr.data3, pPlayer); + break; + case 2: // 66 (player screen effects) + if (actor->xspr.data3 < 0) break; + else trPlayerCtrlSetScreenEffect(actor->xspr.data2, actor->xspr.data3, pPlayer); + break; + case 3: // 67 (start playing qav scene) + trPlayerCtrlStartScene(actor, pPlayer, (actor->xspr.data4 == 1) ? true : false); + break; + case 4: // 68 (stop playing qav scene) + if (actor->xspr.data2 > 0 && actor->xspr.data2 != pPlayer->sceneQav) break; + else trPlayerCtrlStopScene(pPlayer); + break; + case 5: // 69 (set player look angle, TO-DO: if tx > 0, take a look on TX ID sprite) + //data4 is reserved + if (actor->xspr.data4 != 0) break; + else if (valueIsBetween(actor->xspr.data2, -128, 128)) + trPlayerCtrlSetLookAngle(actor->xspr.data2, pPlayer); + break; + case 6: // 70 (erase player stuff...) + if (actor->xspr.data2 < 0) break; + else trPlayerCtrlEraseStuff(actor->xspr.data2, pPlayer); + break; + case 7: // 71 (give something to player...) + if (actor->xspr.data2 <= 0) break; + else trPlayerCtrlGiveStuff(actor->xspr.data2, actor->xspr.data3, actor->xspr.data4, pPlayer, pCtrl); + break; + case 8: // 72 (use inventory item) + if (actor->xspr.data2 < 1 || actor->xspr.data2 > 5) break; + else trPlayerCtrlUsePackItem(actor->xspr.data2, actor->xspr.data3, actor->xspr.data4, pPlayer, event.cmd); + break; + case 9: // 73 (set player's sprite angle, TO-DO: if tx > 0, take a look on TX ID sprite) + //data4 is reserved + if (actor->xspr.data4 != 0) break; + else if (actor->spr.flags & kModernTypeFlag1) + { + pPlayer->angle.settarget(actor->spr.ang); + pPlayer->angle.lockinput(); + } + else if (valueIsBetween(actor->xspr.data2, -kAng360, kAng360)) + { + pPlayer->angle.settarget(actor->xspr.data2); + pPlayer->angle.lockinput(); + } + break; + case 10: // 74 (de)activate powerup + if (actor->xspr.data2 <= 0 || actor->xspr.data2 > (kMaxAllowedPowerup - (kMinAllowedPowerup << 1) + 1)) break; + trPlayerCtrlUsePowerup(actor, pPlayer, event.cmd); + break; + // case 11: // 75 (print the book) + // data2: RFF TXT id + // data3: background tile + // data4: font base tile + // pal: font / background palette + // hitag: + // d1: 0: print whole text at a time, 1: print line by line, 2: word by word, 3: letter by letter + // d2: 1: force pause the game (sp only) + // d3: 1: inherit palette for font, 2: inherit palette for background, 3: both + // busyTime: speed of word/letter/line printing + // waitTime: if TX ID > 0 and TX ID object is book reader, trigger it? + //break; + + } + } + return true; + + case kGenModernSound: + switch (event.cmd) { + case kCmdOff: + if (actor->xspr.state == 1) SetSpriteState(actor, 0); + break; + case kCmdOn: + evKillActor(actor); // queue overflow protect + if (actor->xspr.state == 0) SetSpriteState(actor, 1); + [[fallthrough]]; + case kCmdRepeat: + if (actor->xspr.txID) modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + else useSoundGen(actor, actor); + + if (actor->xspr.busyTime > 0) + evPostActor(actor, (120 * actor->xspr.busyTime) / 10, kCmdRepeat); + break; + default: + if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); + else evPostActor(actor, 0, kCmdOff); + break; + } + return true; + case kGenModernMissileUniversal: + switch (event.cmd) + { + case kCmdOff: + if (actor->xspr.state == 1) SetSpriteState(actor, 0); + break; + case kCmdOn: + evKillActor(actor); // queue overflow protect + if (actor->xspr.state == 0) SetSpriteState(actor, 1); + [[fallthrough]]; + case kCmdRepeat: + if (actor->xspr.txID) modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + else useUniMissileGen(actor, actor); + + if (actor->xspr.busyTime > 0) + evPostActor(actor, (120 * actor->xspr.busyTime) / 10, kCmdRepeat); + + break; + default: + if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); + else evPostActor(actor, 0, kCmdOff); + break; + } + return true; + } } //--------------------------------------------------------------------------- @@ -5816,26 +5817,26 @@ bool modernTypeOperateSprite(DBloodActor* actor, EVENT& event) // //--------------------------------------------------------------------------- -bool modernTypeOperateWall(walltype* pWall, const EVENT& event) +bool modernTypeOperateWall(walltype* pWall, const EVENT& event) { - switch (pWall->type) - { - case kSwitchOneWay: - switch (event.cmd) { - case kCmdOff: - SetWallState(pWall, 0); - break; - case kCmdOn: - SetWallState(pWall, 1); - break; - default: - SetWallState(pWall, pWall->xw().restState ^ 1); - break; - } - return true; - default: - return false; // no modern type found to work with, go normal OperateWall(); - } + switch (pWall->type) + { + case kSwitchOneWay: + switch (event.cmd) { + case kCmdOff: + SetWallState(pWall, 0); + break; + case kCmdOn: + SetWallState(pWall, 1); + break; + default: + SetWallState(pWall, pWall->xw().restState ^ 1); + break; + } + return true; + default: + return false; // no modern type found to work with, go normal OperateWall(); + } } //--------------------------------------------------------------------------- @@ -5844,20 +5845,20 @@ bool modernTypeOperateWall(walltype* pWall, const EVENT& event) // //--------------------------------------------------------------------------- -bool txIsRanged(DBloodActor* sourceactor) +bool txIsRanged(DBloodActor* sourceactor) { - if (!sourceactor->hasX()) return false; - if (sourceactor->xspr.data1 > 0 && sourceactor->xspr.data2 <= 0 && sourceactor->xspr.data3 <= 0 && sourceactor->xspr.data4 > 0) - { - if (sourceactor->xspr.data1 > sourceactor->xspr.data4) - { - // data1 must be less than data4 - int tmp = sourceactor->xspr.data1; sourceactor->xspr.data1 = sourceactor->xspr.data4; - sourceactor->xspr.data4 = tmp; - } - return true; - } - return false; + if (!sourceactor->hasX()) return false; + if (sourceactor->xspr.data1 > 0 && sourceactor->xspr.data2 <= 0 && sourceactor->xspr.data3 <= 0 && sourceactor->xspr.data4 > 0) + { + if (sourceactor->xspr.data1 > sourceactor->xspr.data4) + { + // data1 must be less than data4 + int tmp = sourceactor->xspr.data1; sourceactor->xspr.data1 = sourceactor->xspr.data4; + sourceactor->xspr.data4 = tmp; + } + return true; + } + return false; } //--------------------------------------------------------------------------- @@ -5866,29 +5867,29 @@ bool txIsRanged(DBloodActor* sourceactor) // //--------------------------------------------------------------------------- -void seqTxSendCmdAll(DBloodActor* sourceactor, DBloodActor* actor, COMMAND_ID cmd, bool modernSend) +void seqTxSendCmdAll(DBloodActor* sourceactor, DBloodActor* actor, COMMAND_ID cmd, bool modernSend) { - bool ranged = txIsRanged(sourceactor); - if (ranged) - { - for (sourceactor->xspr.txID = sourceactor->xspr.data1; sourceactor->xspr.txID <= sourceactor->xspr.data4; sourceactor->xspr.txID++) - { - if (sourceactor->xspr.txID <= 0 || sourceactor->xspr.txID >= kChannelUserMax) continue; - else if (!modernSend) evSendActor(actor, sourceactor->xspr.txID, cmd); - else modernTypeSendCommand(actor, sourceactor->xspr.txID, cmd); - } - } - else - { - for (int i = 0; i <= 3; i++) - { - sourceactor->xspr.txID = GetDataVal(sourceactor, i); - if (sourceactor->xspr.txID <= 0 || sourceactor->xspr.txID >= kChannelUserMax) continue; - else if (!modernSend) evSendActor(actor, sourceactor->xspr.txID, cmd); - else modernTypeSendCommand(actor, sourceactor->xspr.txID, cmd); - } - } - sourceactor->xspr.txID = sourceactor->xspr.sysData1 = 0; + bool ranged = txIsRanged(sourceactor); + if (ranged) + { + for (sourceactor->xspr.txID = sourceactor->xspr.data1; sourceactor->xspr.txID <= sourceactor->xspr.data4; sourceactor->xspr.txID++) + { + if (sourceactor->xspr.txID <= 0 || sourceactor->xspr.txID >= kChannelUserMax) continue; + else if (!modernSend) evSendActor(actor, sourceactor->xspr.txID, cmd); + else modernTypeSendCommand(actor, sourceactor->xspr.txID, cmd); + } + } + else + { + for (int i = 0; i <= 3; i++) + { + sourceactor->xspr.txID = GetDataVal(sourceactor, i); + if (sourceactor->xspr.txID <= 0 || sourceactor->xspr.txID >= kChannelUserMax) continue; + else if (!modernSend) evSendActor(actor, sourceactor->xspr.txID, cmd); + else modernTypeSendCommand(actor, sourceactor->xspr.txID, cmd); + } + } + sourceactor->xspr.txID = sourceactor->xspr.sysData1 = 0; } //--------------------------------------------------------------------------- @@ -5897,31 +5898,31 @@ void seqTxSendCmdAll(DBloodActor* sourceactor, DBloodActor* actor, COMMAND_ID cm // //--------------------------------------------------------------------------- -void useRandomTx(DBloodActor* sourceactor, COMMAND_ID cmd, bool setState) +void useRandomTx(DBloodActor* sourceactor, COMMAND_ID cmd, bool setState) { - int tx = 0; int maxRetries = kMaxRandomizeRetries; - - if (txIsRanged(sourceactor)) - { - while (maxRetries-- >= 0) - { - if ((tx = nnExtRandom(sourceactor->xspr.data1, sourceactor->xspr.data4)) != sourceactor->xspr.txID) - break; - } - } - else - { - while (maxRetries-- >= 0) - { - if ((tx = randomGetDataValue(sourceactor, kRandomizeTX)) > 0 && tx != sourceactor->xspr.txID) - break; - } - } + int tx = 0; int maxRetries = kMaxRandomizeRetries; - sourceactor->xspr.txID = (tx > 0 && tx < kChannelUserMax) ? tx : 0; - if (setState) - SetSpriteState(sourceactor, sourceactor->xspr.state ^ 1); - //evSendActor(sourceactor->spr.index, sourceactor->xspr.txID, (COMMAND_ID)sourceactor->xspr.command); + if (txIsRanged(sourceactor)) + { + while (maxRetries-- >= 0) + { + if ((tx = nnExtRandom(sourceactor->xspr.data1, sourceactor->xspr.data4)) != sourceactor->xspr.txID) + break; + } + } + else + { + while (maxRetries-- >= 0) + { + if ((tx = randomGetDataValue(sourceactor, kRandomizeTX)) > 0 && tx != sourceactor->xspr.txID) + break; + } + } + + sourceactor->xspr.txID = (tx > 0 && tx < kChannelUserMax) ? tx : 0; + if (setState) + SetSpriteState(sourceactor, sourceactor->xspr.state ^ 1); + //evSendActor(sourceactor->spr.index, sourceactor->xspr.txID, (COMMAND_ID)sourceactor->xspr.command); } //--------------------------------------------------------------------------- @@ -5930,70 +5931,70 @@ void useRandomTx(DBloodActor* sourceactor, COMMAND_ID cmd, bool setState) // //--------------------------------------------------------------------------- -void useSequentialTx(DBloodActor* sourceactor, COMMAND_ID cmd, bool setState) +void useSequentialTx(DBloodActor* sourceactor, COMMAND_ID cmd, bool setState) { - bool range = txIsRanged(sourceactor); int cnt = 3; int tx = 0; + bool range = txIsRanged(sourceactor); int cnt = 3; int tx = 0; - if (range) - { - // make sure sysData is correct as we store current index of TX ID here. - if (sourceactor->xspr.sysData1 < sourceactor->xspr.data1) sourceactor->xspr.sysData1 = sourceactor->xspr.data1; - else if (sourceactor->xspr.sysData1 > sourceactor->xspr.data4) sourceactor->xspr.sysData1 = sourceactor->xspr.data4; + if (range) + { + // make sure sysData is correct as we store current index of TX ID here. + if (sourceactor->xspr.sysData1 < sourceactor->xspr.data1) sourceactor->xspr.sysData1 = sourceactor->xspr.data1; + else if (sourceactor->xspr.sysData1 > sourceactor->xspr.data4) sourceactor->xspr.sysData1 = sourceactor->xspr.data4; - } - else - { - // make sure sysData is correct as we store current index of data field here. - if (sourceactor->xspr.sysData1 > 3) sourceactor->xspr.sysData1 = 0; - else if (sourceactor->xspr.sysData1 < 0) sourceactor->xspr.sysData1 = 3; - } + } + else + { + // make sure sysData is correct as we store current index of data field here. + if (sourceactor->xspr.sysData1 > 3) sourceactor->xspr.sysData1 = 0; + else if (sourceactor->xspr.sysData1 < 0) sourceactor->xspr.sysData1 = 3; + } - switch (cmd) - { - case kCmdOff: - if (!range) - { - while (cnt-- >= 0) // skip empty data fields - { - if (sourceactor->xspr.sysData1-- < 0) sourceactor->xspr.sysData1 = 3; - if ((tx = GetDataVal(sourceactor, sourceactor->xspr.sysData1)) <= 0) continue; - else break; - } - } - else - { - if (--sourceactor->xspr.sysData1 < sourceactor->xspr.data1) sourceactor->xspr.sysData1 = sourceactor->xspr.data4; - tx = sourceactor->xspr.sysData1; - } - break; + switch (cmd) + { + case kCmdOff: + if (!range) + { + while (cnt-- >= 0) // skip empty data fields + { + if (sourceactor->xspr.sysData1-- < 0) sourceactor->xspr.sysData1 = 3; + if ((tx = GetDataVal(sourceactor, sourceactor->xspr.sysData1)) <= 0) continue; + else break; + } + } + else + { + if (--sourceactor->xspr.sysData1 < sourceactor->xspr.data1) sourceactor->xspr.sysData1 = sourceactor->xspr.data4; + tx = sourceactor->xspr.sysData1; + } + break; - default: - if (!range) - { - while (cnt-- >= 0) // skip empty data fields - { - if (sourceactor->xspr.sysData1 > 3) sourceactor->xspr.sysData1 = 0; - if ((tx = GetDataVal(sourceactor, sourceactor->xspr.sysData1++)) <= 0) continue; - else break; - } - } - else - { - tx = sourceactor->xspr.sysData1; - if (sourceactor->xspr.sysData1 >= sourceactor->xspr.data4) - { - sourceactor->xspr.sysData1 = sourceactor->xspr.data1; - break; - } - sourceactor->xspr.sysData1++; - } - break; - } + default: + if (!range) + { + while (cnt-- >= 0) // skip empty data fields + { + if (sourceactor->xspr.sysData1 > 3) sourceactor->xspr.sysData1 = 0; + if ((tx = GetDataVal(sourceactor, sourceactor->xspr.sysData1++)) <= 0) continue; + else break; + } + } + else + { + tx = sourceactor->xspr.sysData1; + if (sourceactor->xspr.sysData1 >= sourceactor->xspr.data4) + { + sourceactor->xspr.sysData1 = sourceactor->xspr.data1; + break; + } + sourceactor->xspr.sysData1++; + } + break; + } - sourceactor->xspr.txID = (tx > 0 && tx < kChannelUserMax) ? tx : 0; - if (setState) - SetSpriteState(sourceactor, sourceactor->xspr.state ^ 1); - //evSendActor(sourceactor->spr.index, sourceactor->xspr.txID, (COMMAND_ID)sourceactor->xspr.command); + sourceactor->xspr.txID = (tx > 0 && tx < kChannelUserMax) ? tx : 0; + if (setState) + SetSpriteState(sourceactor, sourceactor->xspr.state ^ 1); + //evSendActor(sourceactor->spr.index, sourceactor->xspr.txID, (COMMAND_ID)sourceactor->xspr.command); } @@ -6005,94 +6006,94 @@ void useSequentialTx(DBloodActor* sourceactor, COMMAND_ID cmd, bool setState) int useCondition(DBloodActor* sourceactor, EVENT& event) { - bool srcIsCondition = false; + bool srcIsCondition = false; - auto const pActor = event.isActor() ? event.getActor() : nullptr; + auto const pActor = event.isActor() ? event.getActor() : nullptr; - if (event.isActor() && pActor == nullptr) return -1; - if (event.isActor() && pActor != sourceactor) - srcIsCondition = (pActor->spr.type == kModernCondition || pActor->spr.type == kModernConditionFalse); + if (event.isActor() && pActor == nullptr) return -1; + if (event.isActor() && pActor != sourceactor) + srcIsCondition = (pActor->spr.type == kModernCondition || pActor->spr.type == kModernConditionFalse); - // if it's a tracking condition, it must ignore all the commands sent from objects - if (sourceactor->xspr.busyTime > 0 && event.funcID != kCallbackMax) return -1; - else if (!srcIsCondition) // save object serials in the stack and make copy of initial object - { - condPush(sourceactor, event.target); - condBackup(sourceactor); - } - else // or grab serials of objects from previous conditions - { - sourceactor->condition[0] = pActor->condition[0]; - sourceactor->condition[1] = pActor->condition[1]; + // if it's a tracking condition, it must ignore all the commands sent from objects + if (sourceactor->xspr.busyTime > 0 && event.funcID != kCallbackMax) return -1; + else if (!srcIsCondition) // save object serials in the stack and make copy of initial object + { + condPush(sourceactor, event.target); + condBackup(sourceactor); + } + else // or grab serials of objects from previous conditions + { + sourceactor->condition[0] = pActor->condition[0]; + sourceactor->condition[1] = pActor->condition[1]; - } - - int cond = sourceactor->xspr.data1; - bool ok = false; - bool RVRS = (sourceactor->spr.type == kModernConditionFalse); - bool RSET = (sourceactor->xspr.command == kCmdNumberic + 36); - bool PUSH = (sourceactor->xspr.command == kCmdNumberic); - int comOp = sourceactor->spr.cstat; // comparison operator + } - if (sourceactor->xspr.restState == 0) - { - if (cond == 0) ok = true; // dummy - else if (cond >= kCondGameBase && cond < kCondGameMax) ok = condCheckGame(sourceactor, event, comOp, PUSH); - else if (cond >= kCondMixedBase && cond < kCondMixedMax) ok = condCheckMixed(sourceactor, event, comOp, PUSH); - else if (cond >= kCondWallBase && cond < kCondWallMax) ok = condCheckWall(sourceactor, comOp, PUSH); - else if (cond >= kCondSectorBase && cond < kCondSectorMax) ok = condCheckSector(sourceactor, comOp, PUSH); - else if (cond >= kCondPlayerBase && cond < kCondPlayerMax) ok = condCheckPlayer(sourceactor, comOp, PUSH); - else if (cond >= kCondDudeBase && cond < kCondDudeMax) ok = condCheckDude(sourceactor, comOp, PUSH); - else if (cond >= kCondSpriteBase && cond < kCondSpriteMax) ok = condCheckSprite(sourceactor, comOp, PUSH); - else condError(sourceactor,"Unexpected condition id %d!", cond); + int cond = sourceactor->xspr.data1; + bool ok = false; + bool RVRS = (sourceactor->spr.type == kModernConditionFalse); + bool RSET = (sourceactor->xspr.command == kCmdNumberic + 36); + bool PUSH = (sourceactor->xspr.command == kCmdNumberic); + int comOp = sourceactor->spr.cstat; // comparison operator - sourceactor->xspr.state = (ok ^ RVRS); - - if (sourceactor->xspr.waitTime > 0 && sourceactor->xspr.state > 0) - { - sourceactor->xspr.restState = 1; - evKillActor(sourceactor); - evPostActor(sourceactor, (sourceactor->xspr.waitTime * 120) / 10, kCmdRepeat); - return -1; - } - } - else if (event.cmd == kCmdRepeat) - { - sourceactor->xspr.restState = 0; - } - else - { - return -1; - } + if (sourceactor->xspr.restState == 0) + { + if (cond == 0) ok = true; // dummy + else if (cond >= kCondGameBase && cond < kCondGameMax) ok = condCheckGame(sourceactor, event, comOp, PUSH); + else if (cond >= kCondMixedBase && cond < kCondMixedMax) ok = condCheckMixed(sourceactor, event, comOp, PUSH); + else if (cond >= kCondWallBase && cond < kCondWallMax) ok = condCheckWall(sourceactor, comOp, PUSH); + else if (cond >= kCondSectorBase && cond < kCondSectorMax) ok = condCheckSector(sourceactor, comOp, PUSH); + else if (cond >= kCondPlayerBase && cond < kCondPlayerMax) ok = condCheckPlayer(sourceactor, comOp, PUSH); + else if (cond >= kCondDudeBase && cond < kCondDudeMax) ok = condCheckDude(sourceactor, comOp, PUSH); + else if (cond >= kCondSpriteBase && cond < kCondSpriteMax) ok = condCheckSprite(sourceactor, comOp, PUSH); + else condError(sourceactor, "Unexpected condition id %d!", cond); - if (sourceactor->xspr.state) - { - sourceactor->xspr.isTriggered = sourceactor->xspr.triggerOnce; - - if (RSET) - condRestore(sourceactor); // reset focus to the initial object + sourceactor->xspr.state = (ok ^ RVRS); - // send command to rx bucket - if (sourceactor->xspr.txID) - evSendActor(sourceactor, sourceactor->xspr.txID, (COMMAND_ID)sourceactor->xspr.command); + if (sourceactor->xspr.waitTime > 0 && sourceactor->xspr.state > 0) + { + sourceactor->xspr.restState = 1; + evKillActor(sourceactor); + evPostActor(sourceactor, (sourceactor->xspr.waitTime * 120) / 10, kCmdRepeat); + return -1; + } + } + else if (event.cmd == kCmdRepeat) + { + sourceactor->xspr.restState = 0; + } + else + { + return -1; + } - if (sourceactor->spr.flags) { - - // send it for object currently in the focus - if (sourceactor->spr.flags & kModernTypeFlag1) - { - nnExtTriggerObject(event.target, sourceactor->xspr.command); - } + if (sourceactor->xspr.state) + { + sourceactor->xspr.isTriggered = sourceactor->xspr.triggerOnce; - // send it for initial object - if ((sourceactor->spr.flags & kModernTypeFlag2) && (sourceactor->condition[0] != sourceactor->condition[1] || !(sourceactor->spr.hitag & kModernTypeFlag1))) - { - auto co = condGet(sourceactor); - nnExtTriggerObject(co, sourceactor->xspr.command); - } - } - } - return sourceactor->xspr.state; + if (RSET) + condRestore(sourceactor); // reset focus to the initial object + + // send command to rx bucket + if (sourceactor->xspr.txID) + evSendActor(sourceactor, sourceactor->xspr.txID, (COMMAND_ID)sourceactor->xspr.command); + + if (sourceactor->spr.flags) { + + // send it for object currently in the focus + if (sourceactor->spr.flags & kModernTypeFlag1) + { + nnExtTriggerObject(event.target, sourceactor->xspr.command); + } + + // send it for initial object + if ((sourceactor->spr.flags & kModernTypeFlag2) && (sourceactor->condition[0] != sourceactor->condition[1] || !(sourceactor->spr.hitag & kModernTypeFlag1))) + { + auto co = condGet(sourceactor); + nnExtTriggerObject(co, sourceactor->xspr.command); + } + } + } + return sourceactor->xspr.state; } //--------------------------------------------------------------------------- @@ -6101,47 +6102,47 @@ int useCondition(DBloodActor* sourceactor, EVENT& event) // //--------------------------------------------------------------------------- -void useRandomItemGen(DBloodActor* actor) +void useRandomItemGen(DBloodActor* actor) { - // let's first search for previously dropped items and remove it - if (actor->xspr.dropMsg > 0) - { - BloodStatIterator it(kStatItem); - while (auto iactor = it.Next()) - { - if ((unsigned int)iactor->spr.type == actor->xspr.dropMsg && iactor->spr.pos.X == actor->spr.pos.X && iactor->spr.pos.Y == actor->spr.pos.Y && iactor->spr.pos.Z == actor->spr.pos.Z) - { - gFX.fxSpawnActor((FX_ID)29, actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z, 0); - iactor->spr.type = kSpriteDecoration; - actPostSprite(iactor, kStatFree); - break; - } - } - } + // let's first search for previously dropped items and remove it + if (actor->xspr.dropMsg > 0) + { + BloodStatIterator it(kStatItem); + while (auto iactor = it.Next()) + { + if ((unsigned int)iactor->spr.type == actor->xspr.dropMsg && iactor->spr.pos.X == actor->spr.pos.X && iactor->spr.pos.Y == actor->spr.pos.Y && iactor->spr.pos.Z == actor->spr.pos.Z) + { + gFX.fxSpawnActor((FX_ID)29, actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z, 0); + iactor->spr.type = kSpriteDecoration; + actPostSprite(iactor, kStatFree); + break; + } + } + } - // then drop item - auto dropactor = randomDropPickupObject(actor, actor->xspr.dropMsg); + // then drop item + auto dropactor = randomDropPickupObject(actor, actor->xspr.dropMsg); - if (dropactor != nullptr) - { - clampSprite(dropactor); + if (dropactor != nullptr) + { + clampSprite(dropactor); - // check if generator affected by physics - if (debrisGetIndex(actor) != -1) - { - dropactor->addX(); - int nIndex = debrisGetFreeIndex(); - if (nIndex >= 0) - { - dropactor->xspr.physAttr |= kPhysMove | kPhysGravity | kPhysFalling; // must fall always - actor->spr.cstat &= ~CSTAT_SPRITE_BLOCK; + // check if generator affected by physics + if (debrisGetIndex(actor) != -1) + { + dropactor->addX(); + int nIndex = debrisGetFreeIndex(); + if (nIndex >= 0) + { + dropactor->xspr.physAttr |= kPhysMove | kPhysGravity | kPhysFalling; // must fall always + actor->spr.cstat &= ~CSTAT_SPRITE_BLOCK; - gPhysSpritesList[nIndex] = dropactor; - if (nIndex >= gPhysSpritesCount) gPhysSpritesCount++; - getSpriteMassBySize(dropactor); // create mass cache - } - } - } + gPhysSpritesList[nIndex] = dropactor; + if (nIndex >= gPhysSpritesCount) gPhysSpritesCount++; + getSpriteMassBySize(dropactor); // create mass cache + } + } + } } //--------------------------------------------------------------------------- @@ -6150,78 +6151,78 @@ void useRandomItemGen(DBloodActor* actor) // //--------------------------------------------------------------------------- -void useUniMissileGen(DBloodActor* sourceactor, DBloodActor* actor) +void useUniMissileGen(DBloodActor* sourceactor, DBloodActor* actor) { - if (actor == nullptr) actor = sourceactor; - int dx = 0, dy = 0, dz = 0; + if (actor == nullptr) actor = sourceactor; + int dx = 0, dy = 0, dz = 0; - if (sourceactor->xspr.data1 < kMissileBase || sourceactor->xspr.data1 >= kMissileMax) - return; + if (sourceactor->xspr.data1 < kMissileBase || sourceactor->xspr.data1 >= kMissileMax) + return; - if (actor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_FLOOR) - { - if (actor->spr.cstat & CSTAT_SPRITE_YFLIP) dz = 0x4000; - else dz = -0x4000; - } - else - { - dx = bcos(actor->spr.ang); - dy = bsin(actor->spr.ang); - dz = sourceactor->xspr.data3 << 6; // add slope controlling - if (dz > 0x10000) dz = 0x10000; - else if (dz < -0x10000) dz = -0x10000; - } + if (actor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_FLOOR) + { + if (actor->spr.cstat & CSTAT_SPRITE_YFLIP) dz = 0x4000; + else dz = -0x4000; + } + else + { + dx = bcos(actor->spr.ang); + dy = bsin(actor->spr.ang); + dz = sourceactor->xspr.data3 << 6; // add slope controlling + if (dz > 0x10000) dz = 0x10000; + else if (dz < -0x10000) dz = -0x10000; + } - auto missileactor = actFireMissile(actor, 0, 0, dx, dy, dz, actor->xspr.data1); - if (missileactor) - { - int from; // inherit some properties of the generator - if ((from = (sourceactor->spr.flags & kModernTypeFlag3)) > 0) - { - int canInherit = 0xF; - if (missileactor->hasX() && seqGetStatus(missileactor) >= 0) - { - canInherit &= ~0x8; - - SEQINST* pInst = GetInstance(missileactor); - Seq* pSeq = pInst->pSequence; - for (int i = 0; i < pSeq->nFrames; i++) - { - if ((canInherit & 0x4) && pSeq->frames[i].palette != 0) canInherit &= ~0x4; - if ((canInherit & 0x2) && pSeq->frames[i].xrepeat != 0) canInherit &= ~0x2; - if ((canInherit & 0x1) && pSeq->frames[i].yrepeat != 0) canInherit &= ~0x1; - } - } + auto missileactor = actFireMissile(actor, 0, 0, dx, dy, dz, actor->xspr.data1); + if (missileactor) + { + int from; // inherit some properties of the generator + if ((from = (sourceactor->spr.flags & kModernTypeFlag3)) > 0) + { + int canInherit = 0xF; + if (missileactor->hasX() && seqGetStatus(missileactor) >= 0) + { + canInherit &= ~0x8; - if (canInherit != 0) - { - if (canInherit & 0x2) - missileactor->spr.xrepeat = (from == kModernTypeFlag1) ? sourceactor->spr.xrepeat : actor->spr.xrepeat; - - if (canInherit & 0x1) - missileactor->spr.yrepeat = (from == kModernTypeFlag1) ? sourceactor->spr.yrepeat : actor->spr.yrepeat; + SEQINST* pInst = GetInstance(missileactor); + Seq* pSeq = pInst->pSequence; + for (int i = 0; i < pSeq->nFrames; i++) + { + if ((canInherit & 0x4) && pSeq->frames[i].palette != 0) canInherit &= ~0x4; + if ((canInherit & 0x2) && pSeq->frames[i].xrepeat != 0) canInherit &= ~0x2; + if ((canInherit & 0x1) && pSeq->frames[i].yrepeat != 0) canInherit &= ~0x1; + } + } - if (canInherit & 0x4) - missileactor->spr.pal = (from == kModernTypeFlag1) ? sourceactor->spr.pal : actor->spr.pal; - - if (canInherit & 0x8) - missileactor->spr.shade = (from == kModernTypeFlag1) ? sourceactor->spr.shade : actor->spr.shade; - } - } + if (canInherit != 0) + { + if (canInherit & 0x2) + missileactor->spr.xrepeat = (from == kModernTypeFlag1) ? sourceactor->spr.xrepeat : actor->spr.xrepeat; - // add velocity controlling - if (sourceactor->xspr.data2 > 0) - { - int velocity = sourceactor->xspr.data2 << 12; - missileactor->xvel = MulScale(velocity, dx, 14); - missileactor->yvel = MulScale(velocity, dy, 14); - missileactor->zvel = MulScale(velocity, dz, 14); - } + if (canInherit & 0x1) + missileactor->spr.yrepeat = (from == kModernTypeFlag1) ? sourceactor->spr.yrepeat : actor->spr.yrepeat; - // add bursting for missiles - if (missileactor->spr.type != kMissileFlareAlt && sourceactor->xspr.data4 > 0) - evPostActor(missileactor, ClipHigh(sourceactor->xspr.data4, 500), kCallbackMissileBurst); - } + if (canInherit & 0x4) + missileactor->spr.pal = (from == kModernTypeFlag1) ? sourceactor->spr.pal : actor->spr.pal; + + if (canInherit & 0x8) + missileactor->spr.shade = (from == kModernTypeFlag1) ? sourceactor->spr.shade : actor->spr.shade; + } + } + + // add velocity controlling + if (sourceactor->xspr.data2 > 0) + { + int velocity = sourceactor->xspr.data2 << 12; + missileactor->xvel = MulScale(velocity, dx, 14); + missileactor->yvel = MulScale(velocity, dy, 14); + missileactor->zvel = MulScale(velocity, dz, 14); + } + + // add bursting for missiles + if (missileactor->spr.type != kMissileFlareAlt && sourceactor->xspr.data4 > 0) + evPostActor(missileactor, ClipHigh(sourceactor->xspr.data4, 500), kCallbackMissileBurst); + } } @@ -6233,9 +6234,9 @@ void useUniMissileGen(DBloodActor* sourceactor, DBloodActor* actor) void useSoundGen(DBloodActor* sourceactor, DBloodActor* actor) { - int pitch = sourceactor->xspr.data4 << 1; - if (pitch < 2000) pitch = 0; - sfxPlay3DSoundCP(actor, sourceactor->xspr.data2, -1, 0, pitch, sourceactor->xspr.data3); + int pitch = sourceactor->xspr.data4 << 1; + if (pitch < 2000) pitch = 0; + sfxPlay3DSoundCP(actor, sourceactor->xspr.data2, -1, 0, pitch, sourceactor->xspr.data3); } //--------------------------------------------------------------------------- @@ -6244,76 +6245,76 @@ void useSoundGen(DBloodActor* sourceactor, DBloodActor* actor) // //--------------------------------------------------------------------------- -void useIncDecGen(DBloodActor* sourceactor, int objType, sectortype* destSect, walltype* destWall, DBloodActor* objactor) +void useIncDecGen(DBloodActor* sourceactor, int objType, sectortype* destSect, walltype* destWall, DBloodActor* objactor) { - char buffer[7]; - int data = -65535; - short tmp = 0; - int dataIndex = 0; - snprintf(buffer, 7, "%d", abs(sourceactor->xspr.data1)); - int len = int(strlen(buffer)); - - for (int i = 0; i < len; i++) - { - dataIndex = (buffer[i] - 52) + 4; - if ((data = getDataFieldOfObject(objType, destSect, destWall, objactor, dataIndex)) == -65535) - { - Printf(PRINT_HIGH, "\nWrong index of data (%c) for IncDec Gen! Only 1, 2, 3 and 4 indexes allowed!\n", buffer[i]); - continue; - } - - if (sourceactor->xspr.data2 < sourceactor->xspr.data3) - { - data = ClipRange(data, sourceactor->xspr.data2, sourceactor->xspr.data3); - if ((data += sourceactor->xspr.data4) >= sourceactor->xspr.data3) - { - switch (sourceactor->spr.flags) - { - case kModernTypeFlag0: - case kModernTypeFlag1: - if (data > sourceactor->xspr.data3) data = sourceactor->xspr.data3; - break; - case kModernTypeFlag2: - if (data > sourceactor->xspr.data3) data = sourceactor->xspr.data3; - if (!incDecGoalValueIsReached(sourceactor)) break; - tmp = sourceactor->xspr.data3; - sourceactor->xspr.data3 = sourceactor->xspr.data2; - sourceactor->xspr.data2 = tmp; - break; - case kModernTypeFlag3: - if (data > sourceactor->xspr.data3) data = sourceactor->xspr.data2; - break; - } - } + char buffer[7]; + int data = -65535; + short tmp = 0; + int dataIndex = 0; + snprintf(buffer, 7, "%d", abs(sourceactor->xspr.data1)); + int len = int(strlen(buffer)); - } - else if (sourceactor->xspr.data2 > sourceactor->xspr.data3) - { - data = ClipRange(data, sourceactor->xspr.data3, sourceactor->xspr.data2); - if ((data -= sourceactor->xspr.data4) <= sourceactor->xspr.data3) - { - switch (sourceactor->spr.flags) - { - case kModernTypeFlag0: - case kModernTypeFlag1: - if (data < sourceactor->xspr.data3) data = sourceactor->xspr.data3; - break; - case kModernTypeFlag2: - if (data < sourceactor->xspr.data3) data = sourceactor->xspr.data3; - if (!incDecGoalValueIsReached(sourceactor)) break; - tmp = sourceactor->xspr.data3; - sourceactor->xspr.data3 = sourceactor->xspr.data2; - sourceactor->xspr.data2 = tmp; - break; - case kModernTypeFlag3: - if (data < sourceactor->xspr.data3) data = sourceactor->xspr.data2; - break; - } - } - } - sourceactor->xspr.sysData1 = data; - setDataValueOfObject(objType, destSect, destWall, objactor, dataIndex, data); - } + for (int i = 0; i < len; i++) + { + dataIndex = (buffer[i] - 52) + 4; + if ((data = getDataFieldOfObject(objType, destSect, destWall, objactor, dataIndex)) == -65535) + { + Printf(PRINT_HIGH, "\nWrong index of data (%c) for IncDec Gen! Only 1, 2, 3 and 4 indexes allowed!\n", buffer[i]); + continue; + } + + if (sourceactor->xspr.data2 < sourceactor->xspr.data3) + { + data = ClipRange(data, sourceactor->xspr.data2, sourceactor->xspr.data3); + if ((data += sourceactor->xspr.data4) >= sourceactor->xspr.data3) + { + switch (sourceactor->spr.flags) + { + case kModernTypeFlag0: + case kModernTypeFlag1: + if (data > sourceactor->xspr.data3) data = sourceactor->xspr.data3; + break; + case kModernTypeFlag2: + if (data > sourceactor->xspr.data3) data = sourceactor->xspr.data3; + if (!incDecGoalValueIsReached(sourceactor)) break; + tmp = sourceactor->xspr.data3; + sourceactor->xspr.data3 = sourceactor->xspr.data2; + sourceactor->xspr.data2 = tmp; + break; + case kModernTypeFlag3: + if (data > sourceactor->xspr.data3) data = sourceactor->xspr.data2; + break; + } + } + + } + else if (sourceactor->xspr.data2 > sourceactor->xspr.data3) + { + data = ClipRange(data, sourceactor->xspr.data3, sourceactor->xspr.data2); + if ((data -= sourceactor->xspr.data4) <= sourceactor->xspr.data3) + { + switch (sourceactor->spr.flags) + { + case kModernTypeFlag0: + case kModernTypeFlag1: + if (data < sourceactor->xspr.data3) data = sourceactor->xspr.data3; + break; + case kModernTypeFlag2: + if (data < sourceactor->xspr.data3) data = sourceactor->xspr.data3; + if (!incDecGoalValueIsReached(sourceactor)) break; + tmp = sourceactor->xspr.data3; + sourceactor->xspr.data3 = sourceactor->xspr.data2; + sourceactor->xspr.data2 = tmp; + break; + case kModernTypeFlag3: + if (data < sourceactor->xspr.data3) data = sourceactor->xspr.data2; + break; + } + } + } + sourceactor->xspr.sysData1 = data; + setDataValueOfObject(objType, destSect, destWall, objactor, dataIndex, data); + } } //--------------------------------------------------------------------------- @@ -6322,24 +6323,24 @@ void useIncDecGen(DBloodActor* sourceactor, int objType, sectortype* destSect, w // //--------------------------------------------------------------------------- -void sprite2sectorSlope(DBloodActor* actor, sectortype* pSector, char rel, bool forcez) +void sprite2sectorSlope(DBloodActor* actor, sectortype* pSector, char rel, bool forcez) { - int slope = 0, z = 0; - switch (rel) { - default: - z = getflorzofslopeptr(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y); - if ((actor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_FLOOR) && actor->hasX() && actor->xspr.Touch) z--; - slope = pSector->floorheinum; - break; - case 1: - z = getceilzofslopeptr(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y); - if ((actor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_FLOOR) && actor->hasX() && actor->xspr.Touch) z++; - slope = pSector->ceilingheinum; - break; - } + int slope = 0, z = 0; + switch (rel) { + default: + z = getflorzofslopeptr(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y); + if ((actor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_FLOOR) && actor->hasX() && actor->xspr.Touch) z--; + slope = pSector->floorheinum; + break; + case 1: + z = getceilzofslopeptr(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y); + if ((actor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_FLOOR) && actor->hasX() && actor->xspr.Touch) z++; + slope = pSector->ceilingheinum; + break; + } - spriteSetSlope(&actor->spr, slope); - if (forcez) actor->spr.pos.Z = z; + spriteSetSlope(&actor->spr, slope); + if (forcez) actor->spr.pos.Z = z; } //--------------------------------------------------------------------------- @@ -6348,135 +6349,135 @@ void sprite2sectorSlope(DBloodActor* actor, sectortype* pSector, char rel, bool // //--------------------------------------------------------------------------- -void useSlopeChanger(DBloodActor* sourceactor, int objType, sectortype* pSect, DBloodActor* objActor) +void useSlopeChanger(DBloodActor* sourceactor, int objType, sectortype* pSect, DBloodActor* objActor) { - int slope, oslope; - bool flag2 = (sourceactor->spr.flags & kModernTypeFlag2); + int slope, oslope; + bool flag2 = (sourceactor->spr.flags & kModernTypeFlag2); - if (sourceactor->spr.flags & kModernTypeFlag1) slope = ClipRange(sourceactor->xspr.data2, -32767, 32767); - else slope = (32767 / kPercFull) * ClipRange(sourceactor->xspr.data2, -kPercFull, kPercFull); + if (sourceactor->spr.flags & kModernTypeFlag1) slope = ClipRange(sourceactor->xspr.data2, -32767, 32767); + else slope = (32767 / kPercFull) * ClipRange(sourceactor->xspr.data2, -kPercFull, kPercFull); - if (objType == OBJ_SECTOR) - { - switch (sourceactor->xspr.data1) - { - case 2: - case 0: + if (objType == OBJ_SECTOR) + { + switch (sourceactor->xspr.data1) + { + case 2: + case 0: - // just set floor slope - if (flag2) - { - pSect->setfloorslope(slope); - } - else - { - // force closest floor aligned sprites to inherit slope of the sector's floor - oslope = pSect->floorheinum; - BloodSectIterator it(pSect); - while (auto iactor = it.Next()) - { - if (!(iactor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_FLOOR)) continue; - else if (getflorzofslopeptr(pSect, iactor->spr.pos.X, iactor->spr.pos.Y) - kSlopeDist <= iactor->spr.pos.Z) - { - sprite2sectorSlope(iactor, pSect, 0, true); + // just set floor slope + if (flag2) + { + pSect->setfloorslope(slope); + } + else + { + // force closest floor aligned sprites to inherit slope of the sector's floor + oslope = pSect->floorheinum; + BloodSectIterator it(pSect); + while (auto iactor = it.Next()) + { + if (!(iactor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_FLOOR)) continue; + else if (getflorzofslopeptr(pSect, iactor->spr.pos.X, iactor->spr.pos.Y) - kSlopeDist <= iactor->spr.pos.Z) + { + sprite2sectorSlope(iactor, pSect, 0, true); - // set temporary slope of floor - pSect->floorheinum = slope; + // set temporary slope of floor + pSect->floorheinum = slope; - // force sloped sprites to be on floor slope z - sprite2sectorSlope(iactor, pSect, 0, true); + // force sloped sprites to be on floor slope z + sprite2sectorSlope(iactor, pSect, 0, true); - // restore old slope for next sprite - pSect->floorheinum = oslope; - } - } + // restore old slope for next sprite + pSect->floorheinum = oslope; + } + } - // finally set new slope of floor - pSect->setfloorslope(slope); + // finally set new slope of floor + pSect->setfloorslope(slope); - } + } - if (sourceactor->xspr.data1 == 0) break; - [[fallthrough]]; - case 1: + if (sourceactor->xspr.data1 == 0) break; + [[fallthrough]]; + case 1: - // just set ceiling slope - if (flag2) - { - pSect->setceilingslope(slope); - } - else - { - oslope = pSect->ceilingheinum; - BloodSectIterator it(pSect); - while (auto iactor = it.Next()) - { - if (!(iactor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_FLOOR)) continue; - else if (getceilzofslopeptr(pSect, iactor->spr.pos.X, iactor->spr.pos.Y) + kSlopeDist >= iactor->spr.pos.Z) - { - sprite2sectorSlope(iactor, pSect, 1, true); + // just set ceiling slope + if (flag2) + { + pSect->setceilingslope(slope); + } + else + { + oslope = pSect->ceilingheinum; + BloodSectIterator it(pSect); + while (auto iactor = it.Next()) + { + if (!(iactor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_FLOOR)) continue; + else if (getceilzofslopeptr(pSect, iactor->spr.pos.X, iactor->spr.pos.Y) + kSlopeDist >= iactor->spr.pos.Z) + { + sprite2sectorSlope(iactor, pSect, 1, true); - // set new slope of ceiling - pSect->ceilingheinum = slope; + // set new slope of ceiling + pSect->ceilingheinum = slope; - // force sloped sprites to be on ceiling slope z - sprite2sectorSlope(iactor, pSect, 1, true); + // force sloped sprites to be on ceiling slope z + sprite2sectorSlope(iactor, pSect, 1, true); - // restore old slope for next sprite - pSect->ceilingheinum = oslope; - } - } + // restore old slope for next sprite + pSect->ceilingheinum = oslope; + } + } - // finally set new slope of ceiling - pSect->setceilingslope(slope); + // finally set new slope of ceiling + pSect->setceilingslope(slope); - } - break; - } + } + break; + } - // let's give a little impulse to the physics sprites... - BloodSectIterator it(pSect); - while (auto iactor = it.Next()) - { - if (iactor->hasX() && iactor->xspr.physAttr > 0) - { - iactor->xspr.physAttr |= kPhysFalling; - iactor->zvel++; - } - else if ((iactor->spr.statnum == kStatThing || iactor->spr.statnum == kStatDude) && (iactor->spr.flags & kPhysGravity)) - { - iactor->spr.flags |= kPhysFalling; - iactor->zvel++; - } - } - } - else if (objType == OBJ_SPRITE) - { - if (!(objActor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_FLOOR)) objActor->spr.cstat |= CSTAT_SPRITE_ALIGNMENT_FLOOR; - if ((objActor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_SLOPE) != CSTAT_SPRITE_ALIGNMENT_SLOPE) - objActor->spr.cstat |= CSTAT_SPRITE_ALIGNMENT_SLOPE; + // let's give a little impulse to the physics sprites... + BloodSectIterator it(pSect); + while (auto iactor = it.Next()) + { + if (iactor->hasX() && iactor->xspr.physAttr > 0) + { + iactor->xspr.physAttr |= kPhysFalling; + iactor->zvel++; + } + else if ((iactor->spr.statnum == kStatThing || iactor->spr.statnum == kStatDude) && (iactor->spr.flags & kPhysGravity)) + { + iactor->spr.flags |= kPhysFalling; + iactor->zvel++; + } + } + } + else if (objType == OBJ_SPRITE) + { + if (!(objActor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_FLOOR)) objActor->spr.cstat |= CSTAT_SPRITE_ALIGNMENT_FLOOR; + if ((objActor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_SLOPE) != CSTAT_SPRITE_ALIGNMENT_SLOPE) + objActor->spr.cstat |= CSTAT_SPRITE_ALIGNMENT_SLOPE; - switch (sourceactor->xspr.data4) - { - case 1: - case 2: - case 3: - if (!objActor->spr.insector()) break; - switch (sourceactor->xspr.data4) - { - case 1: sprite2sectorSlope(objActor, objActor->spr.sector(), 0, flag2); break; - case 2: sprite2sectorSlope(objActor, objActor->spr.sector(), 1, flag2); break; - case 3: - if (getflorzofslopeptr(objActor->spr.sector(), objActor->spr.pos.X, objActor->spr.pos.Y) - kSlopeDist <= objActor->spr.pos.Z) sprite2sectorSlope(objActor, objActor->spr.sector(), 0, flag2); - if (getceilzofslopeptr(objActor->spr.sector(), objActor->spr.pos.X, objActor->spr.pos.Y) + kSlopeDist >= objActor->spr.pos.Z) sprite2sectorSlope(objActor, objActor->spr.sector(), 1, flag2); - break; - } - break; - default: - spriteSetSlope(&objActor->spr, slope); - break; - } - } + switch (sourceactor->xspr.data4) + { + case 1: + case 2: + case 3: + if (!objActor->spr.insector()) break; + switch (sourceactor->xspr.data4) + { + case 1: sprite2sectorSlope(objActor, objActor->spr.sector(), 0, flag2); break; + case 2: sprite2sectorSlope(objActor, objActor->spr.sector(), 1, flag2); break; + case 3: + if (getflorzofslopeptr(objActor->spr.sector(), objActor->spr.pos.X, objActor->spr.pos.Y) - kSlopeDist <= objActor->spr.pos.Z) sprite2sectorSlope(objActor, objActor->spr.sector(), 0, flag2); + if (getceilzofslopeptr(objActor->spr.sector(), objActor->spr.pos.X, objActor->spr.pos.Y) + kSlopeDist >= objActor->spr.pos.Z) sprite2sectorSlope(objActor, objActor->spr.sector(), 1, flag2); + break; + } + break; + default: + spriteSetSlope(&objActor->spr, slope); + break; + } + } } //--------------------------------------------------------------------------- @@ -6487,30 +6488,30 @@ void useSlopeChanger(DBloodActor* sourceactor, int objType, sectortype* pSect, D void useDataChanger(DBloodActor* sourceactor, int objType, sectortype* pSector, walltype* pWall, DBloodActor* objActor) { - switch (objType) - { - case OBJ_SECTOR: - if ((sourceactor->spr.flags & kModernTypeFlag1) || (sourceactor->xspr.data1 != -1 && sourceactor->xspr.data1 != 32767)) - setDataValueOfObject(objType, pSector, pWall, nullptr, 1, sourceactor->xspr.data1); - break; - case OBJ_SPRITE: - if ((sourceactor->spr.flags & kModernTypeFlag1) || (sourceactor->xspr.data1 != -1 && sourceactor->xspr.data1 != 32767)) - setDataValueOfObject(objType, pSector, pWall, objActor, 1, sourceactor->xspr.data1); + switch (objType) + { + case OBJ_SECTOR: + if ((sourceactor->spr.flags & kModernTypeFlag1) || (sourceactor->xspr.data1 != -1 && sourceactor->xspr.data1 != 32767)) + setDataValueOfObject(objType, pSector, pWall, nullptr, 1, sourceactor->xspr.data1); + break; + case OBJ_SPRITE: + if ((sourceactor->spr.flags & kModernTypeFlag1) || (sourceactor->xspr.data1 != -1 && sourceactor->xspr.data1 != 32767)) + setDataValueOfObject(objType, pSector, pWall, objActor, 1, sourceactor->xspr.data1); - if ((sourceactor->spr.flags & kModernTypeFlag1) || (sourceactor->xspr.data2 != -1 && sourceactor->xspr.data2 != 32767)) - setDataValueOfObject(objType, pSector, pWall, objActor, 2, sourceactor->xspr.data2); + if ((sourceactor->spr.flags & kModernTypeFlag1) || (sourceactor->xspr.data2 != -1 && sourceactor->xspr.data2 != 32767)) + setDataValueOfObject(objType, pSector, pWall, objActor, 2, sourceactor->xspr.data2); - if ((sourceactor->spr.flags & kModernTypeFlag1) || (sourceactor->xspr.data3 != -1 && sourceactor->xspr.data3 != 32767)) - setDataValueOfObject(objType, pSector, pWall, objActor, 3, sourceactor->xspr.data3); + if ((sourceactor->spr.flags & kModernTypeFlag1) || (sourceactor->xspr.data3 != -1 && sourceactor->xspr.data3 != 32767)) + setDataValueOfObject(objType, pSector, pWall, objActor, 3, sourceactor->xspr.data3); - if ((sourceactor->spr.flags & kModernTypeFlag1) || sourceactor->xspr.data4 != 65535) - setDataValueOfObject(objType, pSector, pWall, objActor, 4, sourceactor->xspr.data4); - break; - case OBJ_WALL: - if ((sourceactor->spr.flags & kModernTypeFlag1) || (sourceactor->xspr.data1 != -1 && sourceactor->xspr.data1 != 32767)) - setDataValueOfObject(objType, pSector, pWall, nullptr, 1, sourceactor->xspr.data1); - break; - } + if ((sourceactor->spr.flags & kModernTypeFlag1) || sourceactor->xspr.data4 != 65535) + setDataValueOfObject(objType, pSector, pWall, objActor, 4, sourceactor->xspr.data4); + break; + case OBJ_WALL: + if ((sourceactor->spr.flags & kModernTypeFlag1) || (sourceactor->xspr.data1 != -1 && sourceactor->xspr.data1 != 32767)) + setDataValueOfObject(objType, pSector, pWall, nullptr, 1, sourceactor->xspr.data1); + break; + } } //--------------------------------------------------------------------------- @@ -6519,44 +6520,44 @@ void useDataChanger(DBloodActor* sourceactor, int objType, sectortype* pSector, // //--------------------------------------------------------------------------- -void useSectorLightChanger(DBloodActor* sourceactor, sectortype* pSector) +void useSectorLightChanger(DBloodActor* sourceactor, sectortype* pSector) { - auto pXSector = &pSector->xs(); + auto pXSector = &pSector->xs(); - if (valueIsBetween(sourceactor->xspr.data1, -1, 32767)) - pXSector->wave = ClipHigh(sourceactor->xspr.data1, 11); + if (valueIsBetween(sourceactor->xspr.data1, -1, 32767)) + pXSector->wave = ClipHigh(sourceactor->xspr.data1, 11); - int oldAmplitude = pXSector->amplitude; - if (valueIsBetween(sourceactor->xspr.data2, -128, 128)) - pXSector->amplitude = uint8_t(sourceactor->xspr.data2); + int oldAmplitude = pXSector->amplitude; + if (valueIsBetween(sourceactor->xspr.data2, -128, 128)) + pXSector->amplitude = uint8_t(sourceactor->xspr.data2); - if (valueIsBetween(sourceactor->xspr.data3, -1, 32767)) - pXSector->freq = ClipHigh(sourceactor->xspr.data3, 255); + if (valueIsBetween(sourceactor->xspr.data3, -1, 32767)) + pXSector->freq = ClipHigh(sourceactor->xspr.data3, 255); - if (valueIsBetween(sourceactor->xspr.data4, -1, 65535)) - pXSector->phase = ClipHigh(sourceactor->xspr.data4, 255); + if (valueIsBetween(sourceactor->xspr.data4, -1, 65535)) + pXSector->phase = ClipHigh(sourceactor->xspr.data4, 255); - if (sourceactor->spr.flags) - { - if (sourceactor->spr.flags != kModernTypeFlag1) - { - pXSector->shadeAlways = (sourceactor->spr.flags & 0x0001) ? true : false; - pXSector->shadeFloor = (sourceactor->spr.flags & 0x0002) ? true : false; - pXSector->shadeCeiling = (sourceactor->spr.flags & 0x0004) ? true : false; - pXSector->shadeWalls = (sourceactor->spr.flags & 0x0008) ? true : false; - } - else - { - pXSector->shadeAlways = true; - } - } + if (sourceactor->spr.flags) + { + if (sourceactor->spr.flags != kModernTypeFlag1) + { + pXSector->shadeAlways = (sourceactor->spr.flags & 0x0001) ? true : false; + pXSector->shadeFloor = (sourceactor->spr.flags & 0x0002) ? true : false; + pXSector->shadeCeiling = (sourceactor->spr.flags & 0x0004) ? true : false; + pXSector->shadeWalls = (sourceactor->spr.flags & 0x0008) ? true : false; + } + else + { + pXSector->shadeAlways = true; + } + } - // add to shadeList if amplitude was set to 0 previously - if (oldAmplitude != pXSector->amplitude) - { - if (!shadeList.Contains(pSector)) - shadeList.Push(pSector); - } + // add to shadeList if amplitude was set to 0 previously + if (oldAmplitude != pXSector->amplitude) + { + if (!shadeList.Contains(pSector)) + shadeList.Push(pSector); + } } //--------------------------------------------------------------------------- @@ -6567,271 +6568,271 @@ void useSectorLightChanger(DBloodActor* sourceactor, sectortype* pSector) void useTargetChanger(DBloodActor* sourceactor, DBloodActor* actor) { - if (!actor->IsDudeActor() || actor->spr.statnum != kStatDude) - { - switch (actor->spr.type) // can be dead dude turned in gib - { - // make current target and all other dudes not attack this dude anymore - case kThingBloodBits: - case kThingBloodChunks: - aiFightFreeTargets(actor); - return; - default: - return; - } - } - - - int receiveHp = 33 + Random(33); - DUDEINFO* pDudeInfo = getDudeInfo(actor->spr.type); - int matesPerEnemy = 1; - - // dude is burning? - if (actor->xspr.burnTime > 0 && actor->GetBurnSource()) - { - if (IsBurningDude(actor)) return; - else - { - auto burnactor = actor->GetBurnSource(); - if (burnactor->hasX()) - { - if (sourceactor->xspr.data2 == 1 && actor->xspr.rxID == burnactor->xspr.rxID) - { - actor->xspr.burnTime = 0; - - // heal dude a bit in case of friendly fire - int startHp = (actor->xspr.sysData2 > 0) ? ClipRange(actor->xspr.sysData2 << 4, 1, 65535) : pDudeInfo->startHealth << 4; - if (actor->xspr.health < (unsigned)startHp) actHealDude(actor, receiveHp, startHp); - } - else if (burnactor->xspr.health <= 0) - { - actor->xspr.burnTime = 0; - } - } - } - } - - auto playeractor = aiFightTargetIsPlayer(actor); - // special handling for player(s) if target changer data4 > 2. - if (playeractor != nullptr) - { - auto actLeech = leechIsDropped(actor); - if (sourceactor->xspr.data4 == 3) - { - aiSetTarget(actor, actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z); - aiSetGenIdleState(actor); - if (actor->spr.type == kDudeModernCustom && actLeech) - removeLeech(actLeech); - } - else if (sourceactor->xspr.data4 == 4) - { - aiSetTarget(actor, playeractor->spr.pos.X, playeractor->spr.pos.Y, playeractor->spr.pos.Z); - if (actor->spr.type == kDudeModernCustom && actLeech) - removeLeech(actLeech); - } - } - - int maxAlarmDudes = 8 + Random(8); - auto targetactor = actor->GetTarget(); - if (targetactor && targetactor->hasX() && playeractor == nullptr) - { - if (aiFightUnitCanFly(actor) && aiFightIsMeleeUnit(targetactor) && !aiFightUnitCanFly(targetactor)) - actor->spr.flags |= 0x0002; - else if (aiFightUnitCanFly(actor)) - actor->spr.flags &= ~0x0002; - - if (!targetactor->IsDudeActor() || targetactor->xspr.health < 1 || !aiFightDudeCanSeeTarget(actor, pDudeInfo, targetactor)) - { - aiSetTarget(actor, actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z); - } - // dude attack or attacked by target that does not fit by data id? - else if (sourceactor->xspr.data1 != 666 && targetactor->xspr.data1 != sourceactor->xspr.data1) - { - if (aiFightDudeIsAffected(targetactor)) - { - // force stop attack target - aiSetTarget(actor, actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z); - if (actor->GetBurnSource() == targetactor) - { - actor->xspr.burnTime = 0; - actor->SetBurnSource(nullptr); - } - - // force stop attack dude - aiSetTarget(targetactor, targetactor->spr.pos.X, targetactor->spr.pos.Y, targetactor->spr.pos.Z); - if (targetactor->GetBurnSource() == actor) - { - targetactor->xspr.burnTime = 0; - targetactor->SetBurnSource(nullptr); - } - } - } - else if (sourceactor->xspr.data2 == 1 && actor->xspr.rxID == targetactor->xspr.rxID) - { - auto mateactor = targetactor; - - // heal dude - int startHp = (actor->xspr.sysData2 > 0) ? ClipRange(actor->xspr.sysData2 << 4, 1, 65535) : pDudeInfo->startHealth << 4; - if (actor->xspr.health < (unsigned)startHp) actHealDude(actor, receiveHp, startHp); - - // heal mate - startHp = (mateactor->xspr.sysData2 > 0) ? ClipRange(mateactor->xspr.sysData2 << 4, 1, 65535) : getDudeInfo(mateactor->spr.type)->startHealth << 4; - if (mateactor->xspr.health < (unsigned)startHp) actHealDude(mateactor, receiveHp, startHp); - - auto matetarget = mateactor->GetTarget(); - if (matetarget != nullptr && matetarget->hasX()) - { - // force mate stop attack dude, if he does - if (matetarget == actor) - { - aiSetTarget(mateactor, mateactor->spr.pos.X, mateactor->spr.pos.Y, mateactor->spr.pos.Z); - } - else if (actor->xspr.rxID != matetarget->xspr.rxID) - { - // force dude to attack same target that mate have - aiSetTarget(actor, matetarget); - return; - } - else - { - // force mate to stop attack another mate - aiSetTarget(mateactor, mateactor->spr.pos.X, mateactor->spr.pos.Y, mateactor->spr.pos.Z); - } - } - - // force dude stop attack mate, if target was not changed previously - if (actor == mateactor) - aiSetTarget(actor, actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z); + if (!actor->IsDudeActor() || actor->spr.statnum != kStatDude) + { + switch (actor->spr.type) // can be dead dude turned in gib + { + // make current target and all other dudes not attack this dude anymore + case kThingBloodBits: + case kThingBloodChunks: + aiFightFreeTargets(actor); + return; + default: + return; + } + } - } - // check if targets aims player then force this target to fight with dude - else if (aiFightTargetIsPlayer(actor) != nullptr) - { - aiSetTarget(targetactor, actor); - } + int receiveHp = 33 + Random(33); + DUDEINFO* pDudeInfo = getDudeInfo(actor->spr.type); + int matesPerEnemy = 1; - int mDist = 3; - if (aiFightIsMeleeUnit(actor)) mDist = 2; + // dude is burning? + if (actor->xspr.burnTime > 0 && actor->GetBurnSource()) + { + if (IsBurningDude(actor)) return; + else + { + auto burnactor = actor->GetBurnSource(); + if (burnactor->hasX()) + { + if (sourceactor->xspr.data2 == 1 && actor->xspr.rxID == burnactor->xspr.rxID) + { + actor->xspr.burnTime = 0; - if (targetactor != nullptr && aiFightGetTargetDist(actor, pDudeInfo, targetactor) < mDist) - { - if (!isActive(actor)) aiActivateDude(actor); - return; - } - // lets try to look for target that fits better by distance - else if ((PlayClock & 256) != 0 && (targetactor == nullptr || aiFightGetTargetDist(actor, pDudeInfo, targetactor) >= mDist)) - { - auto newtargactor = aiFightGetTargetInRange(actor, 0, mDist, sourceactor->xspr.data1, sourceactor->xspr.data2); - if (newtargactor != nullptr) - { - // Make prev target not aim in dude - if (targetactor) - { - aiSetTarget(targetactor, targetactor->spr.pos.X, targetactor->spr.pos.Y, targetactor->spr.pos.Z); - if (!isActive(newtargactor)) - aiActivateDude(newtargactor); - } + // heal dude a bit in case of friendly fire + int startHp = (actor->xspr.sysData2 > 0) ? ClipRange(actor->xspr.sysData2 << 4, 1, 65535) : pDudeInfo->startHealth << 4; + if (actor->xspr.health < (unsigned)startHp) actHealDude(actor, receiveHp, startHp); + } + else if (burnactor->xspr.health <= 0) + { + actor->xspr.burnTime = 0; + } + } + } + } - // Change target for dude - aiSetTarget(actor, newtargactor); - if (!isActive(actor)) - aiActivateDude(actor); + auto playeractor = aiFightTargetIsPlayer(actor); + // special handling for player(s) if target changer data4 > 2. + if (playeractor != nullptr) + { + auto actLeech = leechIsDropped(actor); + if (sourceactor->xspr.data4 == 3) + { + aiSetTarget(actor, actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z); + aiSetGenIdleState(actor); + if (actor->spr.type == kDudeModernCustom && actLeech) + removeLeech(actLeech); + } + else if (sourceactor->xspr.data4 == 4) + { + aiSetTarget(actor, playeractor->spr.pos.X, playeractor->spr.pos.Y, playeractor->spr.pos.Z); + if (actor->spr.type == kDudeModernCustom && actLeech) + removeLeech(actLeech); + } + } - // ...and change target of target to dude to force it fight - if (sourceactor->xspr.data3 > 0 && newtargactor->GetTarget() != actor) - { - aiSetTarget(newtargactor, actor); - if (!isActive(newtargactor)) - aiActivateDude(newtargactor); - } + int maxAlarmDudes = 8 + Random(8); + auto targetactor = actor->GetTarget(); + if (targetactor && targetactor->hasX() && playeractor == nullptr) + { + if (aiFightUnitCanFly(actor) && aiFightIsMeleeUnit(targetactor) && !aiFightUnitCanFly(targetactor)) + actor->spr.flags |= 0x0002; + else if (aiFightUnitCanFly(actor)) + actor->spr.flags &= ~0x0002; - return; - } - } - } - - if ((targetactor == nullptr || playeractor != nullptr) && (PlayClock & 32) != 0) - { - // try find first target that dude can see - BloodStatIterator it(kStatDude); - while (auto newtargactor = it.Next()) - { - if (newtargactor->GetTarget() == actor) - { - aiSetTarget(actor, newtargactor); - return; - } + if (!targetactor->IsDudeActor() || targetactor->xspr.health < 1 || !aiFightDudeCanSeeTarget(actor, pDudeInfo, targetactor)) + { + aiSetTarget(actor, actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z); + } + // dude attack or attacked by target that does not fit by data id? + else if (sourceactor->xspr.data1 != 666 && targetactor->xspr.data1 != sourceactor->xspr.data1) + { + if (aiFightDudeIsAffected(targetactor)) + { + // force stop attack target + aiSetTarget(actor, actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z); + if (actor->GetBurnSource() == targetactor) + { + actor->xspr.burnTime = 0; + actor->SetBurnSource(nullptr); + } - // skip non-dudes and players - if (!newtargactor->IsDudeActor() || (newtargactor->IsPlayerActor() && sourceactor->xspr.data4 > 0) || newtargactor->GetOwner() == actor) continue; - // avoid self aiming, those who dude can't see, and those who dude own - else if (!aiFightDudeCanSeeTarget(actor, pDudeInfo, newtargactor) || actor == newtargactor) continue; - // if Target Changer have data1 = 666, everyone can be target, except AI team mates. - else if (sourceactor->xspr.data1 != 666 && sourceactor->xspr.data1 != newtargactor->xspr.data1) continue; - // don't attack immortal, burning dudes and mates - if (IsBurningDude(newtargactor) || !IsKillableDude(newtargactor) || (sourceactor->xspr.data2 == 1 && actor->xspr.rxID == newtargactor->xspr.rxID)) - continue; + // force stop attack dude + aiSetTarget(targetactor, targetactor->spr.pos.X, targetactor->spr.pos.Y, targetactor->spr.pos.Z); + if (targetactor->GetBurnSource() == actor) + { + targetactor->xspr.burnTime = 0; + targetactor->SetBurnSource(nullptr); + } + } + } + else if (sourceactor->xspr.data2 == 1 && actor->xspr.rxID == targetactor->xspr.rxID) + { + auto mateactor = targetactor; - if (sourceactor->xspr.data2 == 0 || (sourceactor->xspr.data2 == 1 && !aiFightMatesHaveSameTarget(actor, newtargactor, matesPerEnemy))) - { - // Change target for dude - aiSetTarget(actor, newtargactor); - if (!isActive(actor)) - aiActivateDude(actor); + // heal dude + int startHp = (actor->xspr.sysData2 > 0) ? ClipRange(actor->xspr.sysData2 << 4, 1, 65535) : pDudeInfo->startHealth << 4; + if (actor->xspr.health < (unsigned)startHp) actHealDude(actor, receiveHp, startHp); - // ...and change target of target to dude to force it fight - if (sourceactor->xspr.data3 > 0 && newtargactor->GetTarget() != actor) - { - aiSetTarget(newtargactor, actor); - if (playeractor == nullptr && !isActive(newtargactor)) - aiActivateDude(newtargactor); + // heal mate + startHp = (mateactor->xspr.sysData2 > 0) ? ClipRange(mateactor->xspr.sysData2 << 4, 1, 65535) : getDudeInfo(mateactor->spr.type)->startHealth << 4; + if (mateactor->xspr.health < (unsigned)startHp) actHealDude(mateactor, receiveHp, startHp); - if (sourceactor->xspr.data3 == 2) - aiFightAlarmDudesInSight(newtargactor, maxAlarmDudes); - } - return; - } - break; - } - } + auto matetarget = mateactor->GetTarget(); + if (matetarget != nullptr && matetarget->hasX()) + { + // force mate stop attack dude, if he does + if (matetarget == actor) + { + aiSetTarget(mateactor, mateactor->spr.pos.X, mateactor->spr.pos.Y, mateactor->spr.pos.Z); + } + else if (actor->xspr.rxID != matetarget->xspr.rxID) + { + // force dude to attack same target that mate have + aiSetTarget(actor, matetarget); + return; + } + else + { + // force mate to stop attack another mate + aiSetTarget(mateactor, mateactor->spr.pos.X, mateactor->spr.pos.Y, mateactor->spr.pos.Z); + } + } - // got no target - let's ask mates if they have targets - if ((actor->GetTarget() == nullptr || playeractor != nullptr) && sourceactor->xspr.data2 == 1 && (PlayClock & 64) != 0) - { - DBloodActor* pMateTargetActor = aiFightGetMateTargets(actor); - if (pMateTargetActor != nullptr && pMateTargetActor->hasX()) - { + // force dude stop attack mate, if target was not changed previously + if (actor == mateactor) + aiSetTarget(actor, actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z); - if (aiFightDudeCanSeeTarget(actor, pDudeInfo, pMateTargetActor)) - { - if (pMateTargetActor->GetTarget() == nullptr) - { - aiSetTarget(pMateTargetActor, actor); - if (pMateTargetActor->IsDudeActor() && !isActive(pMateTargetActor)) - aiActivateDude(pMateTargetActor); - } - aiSetTarget(actor, pMateTargetActor); - if (!isActive(actor)) - aiActivateDude(actor); - return; + } + // check if targets aims player then force this target to fight with dude + else if (aiFightTargetIsPlayer(actor) != nullptr) + { + aiSetTarget(targetactor, actor); + } - // try walk in mate direction in case if not see the target - } - else if (pMateTargetActor->GetTarget() && aiFightDudeCanSeeTarget(actor, pDudeInfo, pMateTargetActor->GetTarget())) - { - actor->SetTarget(pMateTargetActor); - auto pMate = pMateTargetActor->GetTarget(); - actor->xspr.targetX = pMate->spr.pos.X; - actor->xspr.targetY = pMate->spr.pos.Y; - actor->xspr.targetZ = pMate->spr.pos.Z; - if (!isActive(actor)) - aiActivateDude(actor); - return; - } - } - } + int mDist = 3; + if (aiFightIsMeleeUnit(actor)) mDist = 2; + + if (targetactor != nullptr && aiFightGetTargetDist(actor, pDudeInfo, targetactor) < mDist) + { + if (!isActive(actor)) aiActivateDude(actor); + return; + } + // lets try to look for target that fits better by distance + else if ((PlayClock & 256) != 0 && (targetactor == nullptr || aiFightGetTargetDist(actor, pDudeInfo, targetactor) >= mDist)) + { + auto newtargactor = aiFightGetTargetInRange(actor, 0, mDist, sourceactor->xspr.data1, sourceactor->xspr.data2); + if (newtargactor != nullptr) + { + // Make prev target not aim in dude + if (targetactor) + { + aiSetTarget(targetactor, targetactor->spr.pos.X, targetactor->spr.pos.Y, targetactor->spr.pos.Z); + if (!isActive(newtargactor)) + aiActivateDude(newtargactor); + } + + // Change target for dude + aiSetTarget(actor, newtargactor); + if (!isActive(actor)) + aiActivateDude(actor); + + // ...and change target of target to dude to force it fight + if (sourceactor->xspr.data3 > 0 && newtargactor->GetTarget() != actor) + { + aiSetTarget(newtargactor, actor); + if (!isActive(newtargactor)) + aiActivateDude(newtargactor); + } + + return; + } + } + } + + if ((targetactor == nullptr || playeractor != nullptr) && (PlayClock & 32) != 0) + { + // try find first target that dude can see + BloodStatIterator it(kStatDude); + while (auto newtargactor = it.Next()) + { + if (newtargactor->GetTarget() == actor) + { + aiSetTarget(actor, newtargactor); + return; + } + + // skip non-dudes and players + if (!newtargactor->IsDudeActor() || (newtargactor->IsPlayerActor() && sourceactor->xspr.data4 > 0) || newtargactor->GetOwner() == actor) continue; + // avoid self aiming, those who dude can't see, and those who dude own + else if (!aiFightDudeCanSeeTarget(actor, pDudeInfo, newtargactor) || actor == newtargactor) continue; + // if Target Changer have data1 = 666, everyone can be target, except AI team mates. + else if (sourceactor->xspr.data1 != 666 && sourceactor->xspr.data1 != newtargactor->xspr.data1) continue; + // don't attack immortal, burning dudes and mates + if (IsBurningDude(newtargactor) || !IsKillableDude(newtargactor) || (sourceactor->xspr.data2 == 1 && actor->xspr.rxID == newtargactor->xspr.rxID)) + continue; + + if (sourceactor->xspr.data2 == 0 || (sourceactor->xspr.data2 == 1 && !aiFightMatesHaveSameTarget(actor, newtargactor, matesPerEnemy))) + { + // Change target for dude + aiSetTarget(actor, newtargactor); + if (!isActive(actor)) + aiActivateDude(actor); + + // ...and change target of target to dude to force it fight + if (sourceactor->xspr.data3 > 0 && newtargactor->GetTarget() != actor) + { + aiSetTarget(newtargactor, actor); + if (playeractor == nullptr && !isActive(newtargactor)) + aiActivateDude(newtargactor); + + if (sourceactor->xspr.data3 == 2) + aiFightAlarmDudesInSight(newtargactor, maxAlarmDudes); + } + return; + } + break; + } + } + + // got no target - let's ask mates if they have targets + if ((actor->GetTarget() == nullptr || playeractor != nullptr) && sourceactor->xspr.data2 == 1 && (PlayClock & 64) != 0) + { + DBloodActor* pMateTargetActor = aiFightGetMateTargets(actor); + if (pMateTargetActor != nullptr && pMateTargetActor->hasX()) + { + + if (aiFightDudeCanSeeTarget(actor, pDudeInfo, pMateTargetActor)) + { + if (pMateTargetActor->GetTarget() == nullptr) + { + aiSetTarget(pMateTargetActor, actor); + if (pMateTargetActor->IsDudeActor() && !isActive(pMateTargetActor)) + aiActivateDude(pMateTargetActor); + } + + aiSetTarget(actor, pMateTargetActor); + if (!isActive(actor)) + aiActivateDude(actor); + return; + + // try walk in mate direction in case if not see the target + } + else if (pMateTargetActor->GetTarget() && aiFightDudeCanSeeTarget(actor, pDudeInfo, pMateTargetActor->GetTarget())) + { + actor->SetTarget(pMateTargetActor); + auto pMate = pMateTargetActor->GetTarget(); + actor->xspr.targetX = pMate->spr.pos.X; + actor->xspr.targetY = pMate->spr.pos.Y; + actor->xspr.targetZ = pMate->spr.pos.Z; + if (!isActive(actor)) + aiActivateDude(actor); + return; + } + } + } } //--------------------------------------------------------------------------- @@ -6842,41 +6843,41 @@ void useTargetChanger(DBloodActor* sourceactor, DBloodActor* actor) void usePictureChanger(DBloodActor* sourceactor, int objType, sectortype* targSect, walltype* targWall, DBloodActor* objActor) { - switch (objType) { - case OBJ_SECTOR: - if (valueIsBetween(sourceactor->xspr.data1, -1, 32767)) - targSect->floorpicnum = sourceactor->xspr.data1; + switch (objType) { + case OBJ_SECTOR: + if (valueIsBetween(sourceactor->xspr.data1, -1, 32767)) + targSect->floorpicnum = sourceactor->xspr.data1; - if (valueIsBetween(sourceactor->xspr.data2, -1, 32767)) - targSect->ceilingpicnum = sourceactor->xspr.data2; + if (valueIsBetween(sourceactor->xspr.data2, -1, 32767)) + targSect->ceilingpicnum = sourceactor->xspr.data2; - if (valueIsBetween(sourceactor->xspr.data3, -1, 32767)) - targSect->floorpal = uint8_t(sourceactor->xspr.data3); + if (valueIsBetween(sourceactor->xspr.data3, -1, 32767)) + targSect->floorpal = uint8_t(sourceactor->xspr.data3); - if (valueIsBetween(sourceactor->xspr.data4, -1, 65535)) - targSect->ceilingpal = uint8_t(sourceactor->xspr.data4); - break; - case OBJ_SPRITE: - if (valueIsBetween(sourceactor->xspr.data1, -1, 32767)) - objActor->spr.picnum = sourceactor->xspr.data1; + if (valueIsBetween(sourceactor->xspr.data4, -1, 65535)) + targSect->ceilingpal = uint8_t(sourceactor->xspr.data4); + break; + case OBJ_SPRITE: + if (valueIsBetween(sourceactor->xspr.data1, -1, 32767)) + objActor->spr.picnum = sourceactor->xspr.data1; - if (sourceactor->xspr.data2 >= 0) objActor->spr.shade = (sourceactor->xspr.data2 > 127) ? 127 : sourceactor->xspr.data2; - else if (sourceactor->xspr.data2 < -1) objActor->spr.shade = (sourceactor->xspr.data2 < -127) ? -127 : sourceactor->xspr.data2; + if (sourceactor->xspr.data2 >= 0) objActor->spr.shade = (sourceactor->xspr.data2 > 127) ? 127 : sourceactor->xspr.data2; + else if (sourceactor->xspr.data2 < -1) objActor->spr.shade = (sourceactor->xspr.data2 < -127) ? -127 : sourceactor->xspr.data2; - if (valueIsBetween(sourceactor->xspr.data3, -1, 32767)) - objActor->spr.pal = uint8_t(sourceactor->xspr.data3); - break; - case OBJ_WALL: - if (valueIsBetween(sourceactor->xspr.data1, -1, 32767)) - targWall->picnum = sourceactor->xspr.data1; + if (valueIsBetween(sourceactor->xspr.data3, -1, 32767)) + objActor->spr.pal = uint8_t(sourceactor->xspr.data3); + break; + case OBJ_WALL: + if (valueIsBetween(sourceactor->xspr.data1, -1, 32767)) + targWall->picnum = sourceactor->xspr.data1; - if (valueIsBetween(sourceactor->xspr.data2, -1, 32767)) - targWall->overpicnum = sourceactor->xspr.data2; + if (valueIsBetween(sourceactor->xspr.data2, -1, 32767)) + targWall->overpicnum = sourceactor->xspr.data2; - if (valueIsBetween(sourceactor->xspr.data3, -1, 32767)) - targWall->pal = uint8_t(sourceactor->xspr.data3); - break; - } + if (valueIsBetween(sourceactor->xspr.data3, -1, 32767)) + targWall->pal = uint8_t(sourceactor->xspr.data3); + break; + } } //--------------------------------------------------------------------------- @@ -6885,11 +6886,11 @@ void usePictureChanger(DBloodActor* sourceactor, int objType, sectortype* targSe // //--------------------------------------------------------------------------- -QAV* playerQavSceneLoad(int qavId) +QAV* playerQavSceneLoad(int qavId) { - QAV* pQav = getQAV(qavId); - if (!pQav) viewSetSystemMessage("Failed to load QAV animation #%d", qavId); - return pQav; + QAV* pQav = getQAV(qavId); + if (!pQav) viewSetSystemMessage("Failed to load QAV animation #%d", qavId); + return pQav; } //--------------------------------------------------------------------------- @@ -6900,47 +6901,47 @@ QAV* playerQavSceneLoad(int qavId) void playerQavSceneProcess(PLAYER* pPlayer, QAVSCENE* pQavScene) { - auto initiator = pQavScene->initiator; - if (initiator->hasX()) - { - if (initiator->xspr.waitTime > 0 && --initiator->xspr.sysData1 <= 0) - { - if (initiator->xspr.txID >= kChannelUser) - { - for (int i = bucketHead[initiator->xspr.txID]; i < bucketHead[initiator->xspr.txID + 1]; i++) - { - if (rxBucket[i].isActor()) - { - auto rxactor = rxBucket[i].actor(); - if (!rxactor || !rxactor->hasX() || rxactor == initiator) continue; + auto initiator = pQavScene->initiator; + if (initiator->hasX()) + { + if (initiator->xspr.waitTime > 0 && --initiator->xspr.sysData1 <= 0) + { + if (initiator->xspr.txID >= kChannelUser) + { + for (int i = bucketHead[initiator->xspr.txID]; i < bucketHead[initiator->xspr.txID + 1]; i++) + { + if (rxBucket[i].isActor()) + { + auto rxactor = rxBucket[i].actor(); + if (!rxactor || !rxactor->hasX() || rxactor == initiator) continue; - if (rxactor->spr.type == kModernPlayerControl && rxactor->xspr.command == 67) - { - if (rxactor->xspr.data2 == initiator->xspr.data2 || rxactor->xspr.locked) continue; - else trPlayerCtrlStartScene(rxactor, pPlayer, true); - return; - } + if (rxactor->spr.type == kModernPlayerControl && rxactor->xspr.command == 67) + { + if (rxactor->xspr.data2 == initiator->xspr.data2 || rxactor->xspr.locked) continue; + else trPlayerCtrlStartScene(rxactor, pPlayer, true); + return; + } - } - nnExtTriggerObject(rxBucket[i], initiator->xspr.command); + } + nnExtTriggerObject(rxBucket[i], initiator->xspr.command); - } - } - trPlayerCtrlStopScene(pPlayer); - } - else - { - playerQavScenePlay(pPlayer); - pPlayer->weaponTimer = ClipLow(pPlayer->weaponTimer -= 4, 0); - } - } - else - { - - pQavScene->initiator = nullptr; - pPlayer->sceneQav = -1; - pQavScene->qavResrc = NULL; - } + } + } + trPlayerCtrlStopScene(pPlayer); + } + else + { + playerQavScenePlay(pPlayer); + pPlayer->weaponTimer = ClipLow(pPlayer->weaponTimer -= 4, 0); + } + } + else + { + + pQavScene->initiator = nullptr; + pPlayer->sceneQav = -1; + pQavScene->qavResrc = NULL; + } } //--------------------------------------------------------------------------- @@ -6951,40 +6952,40 @@ void playerQavSceneProcess(PLAYER* pPlayer, QAVSCENE* pQavScene) void playerQavSceneDraw(PLAYER* pPlayer, int a2, double a3, double a4, int a5) { - if (pPlayer == NULL || pPlayer->sceneQav == -1) return; + if (pPlayer == NULL || pPlayer->sceneQav == -1) return; - QAVSCENE* pQavScene = &gPlayerCtrl[pPlayer->nPlayer].qavScene; - auto actor = pQavScene->initiator; + QAVSCENE* pQavScene = &gPlayerCtrl[pPlayer->nPlayer].qavScene; + auto actor = pQavScene->initiator; - if (pQavScene->qavResrc != NULL) - { - QAV* pQAV = pQavScene->qavResrc; - int v4; - double smoothratio; + if (pQavScene->qavResrc != NULL) + { + QAV* pQAV = pQavScene->qavResrc; + int v4; + double smoothratio; - qavProcessTimer(pPlayer, pQAV, &v4, &smoothratio); + qavProcessTimer(pPlayer, pQAV, &v4, &smoothratio); - int flags = 2; int nInv = powerupCheck(pPlayer, kPwUpShadowCloak); - if (nInv >= 120 * 8 || (nInv != 0 && (PlayClock & 32))) - { - a2 = -128; flags |= 1; - } + int flags = 2; int nInv = powerupCheck(pPlayer, kPwUpShadowCloak); + if (nInv >= 120 * 8 || (nInv != 0 && (PlayClock & 32))) + { + a2 = -128; flags |= 1; + } - // draw as weapon - if (!(actor->spr.flags & kModernTypeFlag1)) - { - pQAV->x = int(a3); pQAV->y = int(a4); - pQAV->Draw(a3, a4, v4, flags, a2, a5, true, smoothratio); + // draw as weapon + if (!(actor->spr.flags & kModernTypeFlag1)) + { + pQAV->x = int(a3); pQAV->y = int(a4); + pQAV->Draw(a3, a4, v4, flags, a2, a5, true, smoothratio); - // draw fullscreen (currently 4:3 only) - } - else - { - // What an awful hack. This throws proper ordering out of the window, but there is no way to reproduce this better with strict layering of elements. + // draw fullscreen (currently 4:3 only) + } + else + { + // What an awful hack. This throws proper ordering out of the window, but there is no way to reproduce this better with strict layering of elements. // From the above commit it seems to be incomplete anyway... - pQAV->Draw(v4, flags, a2, a5, false, smoothratio); - } - } + pQAV->Draw(v4, flags, a2, a5, false, smoothratio); + } + } } //--------------------------------------------------------------------------- @@ -6995,56 +6996,56 @@ void playerQavSceneDraw(PLAYER* pPlayer, int a2, double a3, double a4, int a5) void playerQavScenePlay(PLAYER* pPlayer) { - if (pPlayer == NULL) return; - - QAVSCENE* pQavScene = &gPlayerCtrl[pPlayer->nPlayer].qavScene; - if (pPlayer->sceneQav == -1 && pQavScene->initiator != nullptr) - pPlayer->sceneQav = pQavScene->initiator->xspr.data2; + if (pPlayer == NULL) return; - if (pQavScene->qavResrc != NULL) - { - QAV* pQAV = pQavScene->qavResrc; - int nTicks = pQAV->duration - pPlayer->weaponTimer; - pQAV->Play(nTicks - 4, nTicks, pPlayer->qavCallback, pPlayer); - } + QAVSCENE* pQavScene = &gPlayerCtrl[pPlayer->nPlayer].qavScene; + if (pPlayer->sceneQav == -1 && pQavScene->initiator != nullptr) + pPlayer->sceneQav = pQavScene->initiator->xspr.data2; + + if (pQavScene->qavResrc != NULL) + { + QAV* pQAV = pQavScene->qavResrc; + int nTicks = pQAV->duration - pPlayer->weaponTimer; + pQAV->Play(nTicks - 4, nTicks, pPlayer->qavCallback, pPlayer); + } } -void playerQavSceneReset(PLAYER* pPlayer) +void playerQavSceneReset(PLAYER* pPlayer) { - QAVSCENE* pQavScene = &gPlayerCtrl[pPlayer->nPlayer].qavScene; - pQavScene->initiator = nullptr; - pQavScene->dummy = pPlayer->sceneQav = -1; - pQavScene->qavResrc = NULL; + QAVSCENE* pQavScene = &gPlayerCtrl[pPlayer->nPlayer].qavScene; + pQavScene->initiator = nullptr; + pQavScene->dummy = pPlayer->sceneQav = -1; + pQavScene->qavResrc = NULL; } -bool playerSizeShrink(PLAYER* pPlayer, int divider) +bool playerSizeShrink(PLAYER* pPlayer, int divider) { - pPlayer->actor->xspr.scale = 256 / divider; - playerSetRace(pPlayer, kModeHumanShrink); - return true; + pPlayer->actor->xspr.scale = 256 / divider; + playerSetRace(pPlayer, kModeHumanShrink); + return true; } -bool playerSizeGrow(PLAYER* pPlayer, int multiplier) +bool playerSizeGrow(PLAYER* pPlayer, int multiplier) { - pPlayer->actor->xspr.scale = 256 * multiplier; - playerSetRace(pPlayer, kModeHumanGrown); - return true; + pPlayer->actor->xspr.scale = 256 * multiplier; + playerSetRace(pPlayer, kModeHumanGrown); + return true; } -bool playerSizeReset(PLAYER* pPlayer) +bool playerSizeReset(PLAYER* pPlayer) { - playerSetRace(pPlayer, kModeHuman); - pPlayer->actor->xspr.scale = 0; - return true; + playerSetRace(pPlayer, kModeHuman); + pPlayer->actor->xspr.scale = 0; + return true; } -void playerDeactivateShrooms(PLAYER* pPlayer) +void playerDeactivateShrooms(PLAYER* pPlayer) { - powerupDeactivate(pPlayer, kPwUpGrowShroom); - pPlayer->pwUpTime[kPwUpGrowShroom] = 0; + powerupDeactivate(pPlayer, kPwUpGrowShroom); + pPlayer->pwUpTime[kPwUpGrowShroom] = 0; - powerupDeactivate(pPlayer, kPwUpShrinkShroom); - pPlayer->pwUpTime[kPwUpShrinkShroom] = 0; + powerupDeactivate(pPlayer, kPwUpShrinkShroom); + pPlayer->pwUpTime[kPwUpShrinkShroom] = 0; } //--------------------------------------------------------------------------- @@ -7053,31 +7054,31 @@ void playerDeactivateShrooms(PLAYER* pPlayer) // //--------------------------------------------------------------------------- -PLAYER* getPlayerById(int id) +PLAYER* getPlayerById(int id) { - // relative to connected players - if (id >= 1 && id <= kMaxPlayers) - { - id = id - 1; - for (int i = connecthead; i >= 0; i = connectpoint2[i]) - { - if (id == gPlayer[i].nPlayer) - return &gPlayer[i]; - } + // relative to connected players + if (id >= 1 && id <= kMaxPlayers) + { + id = id - 1; + for (int i = connecthead; i >= 0; i = connectpoint2[i]) + { + if (id == gPlayer[i].nPlayer) + return &gPlayer[i]; + } - // absolute sprite type - } - else if (id >= kDudePlayer1 && id <= kDudePlayer8) - { - for (int i = connecthead; i >= 0; i = connectpoint2[i]) - { - if (id == gPlayer[i].actor->spr.type) - return &gPlayer[i]; - } - } + // absolute sprite type + } + else if (id >= kDudePlayer1 && id <= kDudePlayer8) + { + for (int i = connecthead; i >= 0; i = connectpoint2[i]) + { + if (id == gPlayer[i].actor->spr.type) + return &gPlayer[i]; + } + } - //viewSetSystemMessage("There is no player id #%d", id); - return NULL; + //viewSetSystemMessage("There is no player id #%d", id); + return NULL; } //--------------------------------------------------------------------------- @@ -7086,67 +7087,67 @@ PLAYER* getPlayerById(int id) // //--------------------------------------------------------------------------- -bool IsBurningDude(DBloodActor* actor) +bool IsBurningDude(DBloodActor* actor) { - if (actor == NULL) return false; - switch (actor->spr.type) - { - case kDudeBurningInnocent: - case kDudeBurningCultist: - case kDudeBurningZombieAxe: - case kDudeBurningZombieButcher: - case kDudeBurningTinyCaleb: - case kDudeBurningBeast: - case kDudeModernCustomBurning: - return true; - } + if (actor == NULL) return false; + switch (actor->spr.type) + { + case kDudeBurningInnocent: + case kDudeBurningCultist: + case kDudeBurningZombieAxe: + case kDudeBurningZombieButcher: + case kDudeBurningTinyCaleb: + case kDudeBurningBeast: + case kDudeModernCustomBurning: + return true; + } - return false; + return false; } bool IsKillableDude(DBloodActor* actor) { - switch (actor->spr.type) - { - case kDudeGargoyleStatueFlesh: - case kDudeGargoyleStatueStone: - return false; - default: - if (!actor->IsDudeActor() || actor->xspr.locked == 1) return false; - return true; - } + switch (actor->spr.type) + { + case kDudeGargoyleStatueFlesh: + case kDudeGargoyleStatueStone: + return false; + default: + if (!actor->IsDudeActor() || actor->xspr.locked == 1) return false; + return true; + } } bool isGrown(DBloodActor* actor) { - if (powerupCheck(&gPlayer[actor->spr.type - kDudePlayer1], kPwUpGrowShroom) > 0) return true; - else if (actor->hasX() && actor->xspr.scale >= 512) return true; - else return false; + if (powerupCheck(&gPlayer[actor->spr.type - kDudePlayer1], kPwUpGrowShroom) > 0) return true; + else if (actor->hasX() && actor->xspr.scale >= 512) return true; + else return false; } bool isShrinked(DBloodActor* actor) { - if (powerupCheck(&gPlayer[actor->spr.type - kDudePlayer1], kPwUpShrinkShroom) > 0) return true; - else if (actor->hasX() && actor->xspr.scale > 0 && actor->xspr.scale <= 128) return true; - else return false; + if (powerupCheck(&gPlayer[actor->spr.type - kDudePlayer1], kPwUpShrinkShroom) > 0) return true; + else if (actor->hasX() && actor->xspr.scale > 0 && actor->xspr.scale <= 128) return true; + else return false; } -bool isActive(DBloodActor* actor) +bool isActive(DBloodActor* actor) { - if (!actor->hasX()) - return false; + if (!actor->hasX()) + return false; - switch (actor->xspr.aiState->stateType) - { - case kAiStateIdle: - case kAiStateGenIdle: - case kAiStateSearch: - case kAiStateMove: - case kAiStateOther: - return false; - default: - return true; - } + switch (actor->xspr.aiState->stateType) + { + case kAiStateIdle: + case kAiStateGenIdle: + case kAiStateSearch: + case kAiStateMove: + case kAiStateOther: + return false; + default: + return true; + } } //--------------------------------------------------------------------------- @@ -7155,64 +7156,64 @@ bool isActive(DBloodActor* actor) // //--------------------------------------------------------------------------- -int getDataFieldOfObject(EventObject &eob, int dataIndex) +int getDataFieldOfObject(EventObject& eob, int dataIndex) { - int data = -65535; + int data = -65535; - if (eob.isActor()) - { - auto actor = eob.actor(); - if (actor) - { - switch (dataIndex) - { - case 1: return actor->xspr.data1; - case 2: return actor->xspr.data2; - case 3: - switch (actor->spr.type) - { - case kDudeModernCustom: return actor->xspr.sysData1; - default: return actor->xspr.data3; - } - case 4: return actor->xspr.data4; - default: return data; - } - } - } - else if (eob.isSector()) - { - return eob.sector()->xs().data; - } - else if (eob.isWall()) - { - return eob.wall()->xw().data; - } - return data; + if (eob.isActor()) + { + auto actor = eob.actor(); + if (actor) + { + switch (dataIndex) + { + case 1: return actor->xspr.data1; + case 2: return actor->xspr.data2; + case 3: + switch (actor->spr.type) + { + case kDudeModernCustom: return actor->xspr.sysData1; + default: return actor->xspr.data3; + } + case 4: return actor->xspr.data4; + default: return data; + } + } + } + else if (eob.isSector()) + { + return eob.sector()->xs().data; + } + else if (eob.isWall()) + { + return eob.wall()->xw().data; + } + return data; } int getDataFieldOfObject(int objType, sectortype* sect, walltype* wal, DBloodActor* actor, int dataIndex) { - int data = -65535; - switch (objType) - { - case OBJ_SPRITE: - switch (dataIndex) - { - case 1: return actor->xspr.data1; - case 2: return actor->xspr.data2; - case 3: - switch (actor->spr.type) - { - case kDudeModernCustom: return actor->xspr.sysData1; - default: return actor->xspr.data3; - } - case 4: return actor->xspr.data4; - default: return data; - } - case OBJ_SECTOR: return sect->xs().data; - case OBJ_WALL: return wal->xw().data; - default: return data; - } + int data = -65535; + switch (objType) + { + case OBJ_SPRITE: + switch (dataIndex) + { + case 1: return actor->xspr.data1; + case 2: return actor->xspr.data2; + case 3: + switch (actor->spr.type) + { + case kDudeModernCustom: return actor->xspr.sysData1; + default: return actor->xspr.data3; + } + case 4: return actor->xspr.data4; + default: return data; + } + case OBJ_SECTOR: return sect->xs().data; + case OBJ_WALL: return wal->xw().data; + default: return data; + } } //--------------------------------------------------------------------------- @@ -7223,82 +7224,82 @@ int getDataFieldOfObject(int objType, sectortype* sect, walltype* wal, DBloodAct bool setDataValueOfObject(int objType, sectortype* sect, walltype* wal, DBloodActor* objActor, int dataIndex, int value) { - switch (objType) - { - case OBJ_SPRITE: - { - int type = objActor->spr.type; + switch (objType) + { + case OBJ_SPRITE: + { + int type = objActor->spr.type; - // exceptions - if (objActor->IsDudeActor() && objActor->xspr.health <= 0) return true; - switch (type) - { - case kThingBloodBits: - case kThingBloodChunks: - case kThingZombieHead: - return true; - break; - } + // exceptions + if (objActor->IsDudeActor() && objActor->xspr.health <= 0) return true; + switch (type) + { + case kThingBloodBits: + case kThingBloodChunks: + case kThingZombieHead: + return true; + break; + } - switch (dataIndex) - { - case 1: - objActor->xspr.data1 = value; - switch (type) - { - case kSwitchCombo: - if (value == objActor->xspr.data2) SetSpriteState(objActor, 1); - else SetSpriteState(objActor, 0); - break; - case kDudeModernCustom: - case kDudeModernCustomBurning: - objActor->genDudeExtra.updReq[kGenDudePropertyWeapon] = true; - objActor->genDudeExtra.updReq[kGenDudePropertyDmgScale] = true; - evPostActor(objActor, kGenDudeUpdTimeRate, kCallbackGenDudeUpdate); - break; - } - return true; - case 2: - objActor->xspr.data2 = value; - switch (type) - { - case kDudeModernCustom: - case kDudeModernCustomBurning: - objActor->genDudeExtra.updReq[kGenDudePropertySpriteSize] = true; - objActor->genDudeExtra.updReq[kGenDudePropertyMass] = true; - objActor->genDudeExtra.updReq[kGenDudePropertyDmgScale] = true; - objActor->genDudeExtra.updReq[kGenDudePropertyStates] = true; - objActor->genDudeExtra.updReq[kGenDudePropertyAttack] = true; - evPostActor(objActor, kGenDudeUpdTimeRate, kCallbackGenDudeUpdate); - break; - } - return true; - case 3: - objActor->xspr.data3 = value; - switch (type) - { - case kDudeModernCustom: - case kDudeModernCustomBurning: - objActor->xspr.sysData1 = value; - break; - } - return true; - case 4: - objActor->xspr.data4 = value; - return true; - default: - return false; - } - } - case OBJ_SECTOR: - sect->xs().data = value; - return true; - case OBJ_WALL: - wal->xw().data = value; - return true; - default: - return false; - } + switch (dataIndex) + { + case 1: + objActor->xspr.data1 = value; + switch (type) + { + case kSwitchCombo: + if (value == objActor->xspr.data2) SetSpriteState(objActor, 1); + else SetSpriteState(objActor, 0); + break; + case kDudeModernCustom: + case kDudeModernCustomBurning: + objActor->genDudeExtra.updReq[kGenDudePropertyWeapon] = true; + objActor->genDudeExtra.updReq[kGenDudePropertyDmgScale] = true; + evPostActor(objActor, kGenDudeUpdTimeRate, kCallbackGenDudeUpdate); + break; + } + return true; + case 2: + objActor->xspr.data2 = value; + switch (type) + { + case kDudeModernCustom: + case kDudeModernCustomBurning: + objActor->genDudeExtra.updReq[kGenDudePropertySpriteSize] = true; + objActor->genDudeExtra.updReq[kGenDudePropertyMass] = true; + objActor->genDudeExtra.updReq[kGenDudePropertyDmgScale] = true; + objActor->genDudeExtra.updReq[kGenDudePropertyStates] = true; + objActor->genDudeExtra.updReq[kGenDudePropertyAttack] = true; + evPostActor(objActor, kGenDudeUpdTimeRate, kCallbackGenDudeUpdate); + break; + } + return true; + case 3: + objActor->xspr.data3 = value; + switch (type) + { + case kDudeModernCustom: + case kDudeModernCustomBurning: + objActor->xspr.sysData1 = value; + break; + } + return true; + case 4: + objActor->xspr.data4 = value; + return true; + default: + return false; + } + } + case OBJ_SECTOR: + sect->xs().data = value; + return true; + case OBJ_WALL: + wal->xw().data = value; + return true; + default: + return false; + } } //--------------------------------------------------------------------------- @@ -7307,28 +7308,28 @@ bool setDataValueOfObject(int objType, sectortype* sect, walltype* wal, DBloodAc // //--------------------------------------------------------------------------- -bool nnExtCanMove(DBloodActor* actor, DBloodActor* target, int nAngle, int nRange) +bool nnExtCanMove(DBloodActor* actor, DBloodActor* target, int nAngle, int nRange) { - int x = actor->spr.pos.X, y = actor->spr.pos.Y, z = actor->spr.pos.Z; - auto pSector = actor->spr.sector(); - HitScan(actor, z, Cos(nAngle) >> 16, Sin(nAngle) >> 16, 0, CLIPMASK0, nRange); - int nDist = approxDist(x - gHitInfo.hitpos.X, y - gHitInfo.hitpos.Y); - if (target != nullptr && nDist - (actor->spr.clipdist << 2) < nRange) - return (target == gHitInfo.actor()); + int x = actor->spr.pos.X, y = actor->spr.pos.Y, z = actor->spr.pos.Z; + auto pSector = actor->spr.sector(); + HitScan(actor, z, Cos(nAngle) >> 16, Sin(nAngle) >> 16, 0, CLIPMASK0, nRange); + int nDist = approxDist(x - gHitInfo.hitpos.X, y - gHitInfo.hitpos.Y); + if (target != nullptr && nDist - (actor->spr.clipdist << 2) < nRange) + return (target == gHitInfo.actor()); - x += MulScale(nRange, Cos(nAngle), 30); - y += MulScale(nRange, Sin(nAngle), 30); - if (!FindSector(x, y, z, &pSector)) - return false; + x += MulScale(nRange, Cos(nAngle), 30); + y += MulScale(nRange, Sin(nAngle), 30); + if (!FindSector(x, y, z, &pSector)) + return false; - if (pSector->hasX()) { + if (pSector->hasX()) { - XSECTOR* pXSector = &pSector->xs(); - return !((pSector->type == kSectorDamage || pXSector->damageType > 0) && pXSector->state && !nnExtIsImmune(actor, pXSector->damageType, 16)); + XSECTOR* pXSector = &pSector->xs(); + return !((pSector->type == kSectorDamage || pXSector->damageType > 0) && pXSector->state && !nnExtIsImmune(actor, pXSector->damageType, 16)); - } + } - return true; + return true; } @@ -7338,42 +7339,42 @@ bool nnExtCanMove(DBloodActor* actor, DBloodActor* target, int nAngle, int nRang // //--------------------------------------------------------------------------- -void nnExtAiSetDirection(DBloodActor* actor, int a3) +void nnExtAiSetDirection(DBloodActor* actor, int a3) { - assert(actor->spr.type >= kDudeBase && actor->spr.type < kDudeMax); - - int vc = ((a3 + 1024 - actor->spr.ang) & 2047) - 1024; - int t1 = DMulScale(actor->xvel, Cos(actor->spr.ang), actor->yvel, Sin(actor->spr.ang), 30); - int vsi = ((t1 * 15) >> 12) / 2; - int v8 = 341; - - if (vc < 0) - v8 = -341; + assert(actor->spr.type >= kDudeBase && actor->spr.type < kDudeMax); - if (nnExtCanMove(actor, actor->GetTarget(), actor->spr.ang + vc, vsi)) - actor->xspr.goalAng = actor->spr.ang + vc; - else if (nnExtCanMove(actor, actor->GetTarget(), actor->spr.ang + vc / 2, vsi)) - actor->xspr.goalAng = actor->spr.ang + vc / 2; - else if (nnExtCanMove(actor, actor->GetTarget(), actor->spr.ang - vc / 2, vsi)) - actor->xspr.goalAng = actor->spr.ang - vc / 2; - else if (nnExtCanMove(actor, actor->GetTarget(), actor->spr.ang + v8, vsi)) - actor->xspr.goalAng = actor->spr.ang + v8; - else if (nnExtCanMove(actor, actor->GetTarget(), actor->spr.ang, vsi)) - actor->xspr.goalAng = actor->spr.ang; - else if (nnExtCanMove(actor, actor->GetTarget(), actor->spr.ang - v8, vsi)) - actor->xspr.goalAng = actor->spr.ang - v8; - else - actor->xspr.goalAng = actor->spr.ang + 341; + int vc = ((a3 + 1024 - actor->spr.ang) & 2047) - 1024; + int t1 = DMulScale(actor->xvel, Cos(actor->spr.ang), actor->yvel, Sin(actor->spr.ang), 30); + int vsi = ((t1 * 15) >> 12) / 2; + int v8 = 341; - if (actor->xspr.dodgeDir) - { - if (!nnExtCanMove(actor, actor->GetTarget(), actor->spr.ang + actor->xspr.dodgeDir * 512, 512)) - { - actor->xspr.dodgeDir = -actor->xspr.dodgeDir; - if (!nnExtCanMove(actor, actor->GetTarget(), actor->spr.ang + actor->xspr.dodgeDir * 512, 512)) - actor->xspr.dodgeDir = 0; - } - } + if (vc < 0) + v8 = -341; + + if (nnExtCanMove(actor, actor->GetTarget(), actor->spr.ang + vc, vsi)) + actor->xspr.goalAng = actor->spr.ang + vc; + else if (nnExtCanMove(actor, actor->GetTarget(), actor->spr.ang + vc / 2, vsi)) + actor->xspr.goalAng = actor->spr.ang + vc / 2; + else if (nnExtCanMove(actor, actor->GetTarget(), actor->spr.ang - vc / 2, vsi)) + actor->xspr.goalAng = actor->spr.ang - vc / 2; + else if (nnExtCanMove(actor, actor->GetTarget(), actor->spr.ang + v8, vsi)) + actor->xspr.goalAng = actor->spr.ang + v8; + else if (nnExtCanMove(actor, actor->GetTarget(), actor->spr.ang, vsi)) + actor->xspr.goalAng = actor->spr.ang; + else if (nnExtCanMove(actor, actor->GetTarget(), actor->spr.ang - v8, vsi)) + actor->xspr.goalAng = actor->spr.ang - v8; + else + actor->xspr.goalAng = actor->spr.ang + 341; + + if (actor->xspr.dodgeDir) + { + if (!nnExtCanMove(actor, actor->GetTarget(), actor->spr.ang + actor->xspr.dodgeDir * 512, 512)) + { + actor->xspr.dodgeDir = -actor->xspr.dodgeDir; + if (!nnExtCanMove(actor, actor->GetTarget(), actor->spr.ang + actor->xspr.dodgeDir * 512, 512)) + actor->xspr.dodgeDir = 0; + } + } } @@ -7383,92 +7384,92 @@ void nnExtAiSetDirection(DBloodActor* actor, int a3) // //--------------------------------------------------------------------------- -void aiPatrolState(DBloodActor* actor, int state) +void aiPatrolState(DBloodActor* actor, int state) { - assert(actor->spr.type >= kDudeBase && actor->spr.type < kDudeMax && actor->hasX()); - assert(actor->GetTarget()); - - auto markeractor = actor->GetTarget(); - assert(markeractor->spr.type == kMarkerPath); + assert(actor->spr.type >= kDudeBase && actor->spr.type < kDudeMax&& actor->hasX()); + assert(actor->GetTarget()); - bool nSeqOverride = false, crouch = false; - int i, seq = -1, start = 0, end = kPatrolStateSize; - - const DUDEINFO_EXTRA* pExtra = &gDudeInfoExtra[actor->spr.type - kDudeBase]; - - switch (state) { - case kAiStatePatrolWaitL: - seq = pExtra->idlgseqofs; - start = 0; end = 2; - break; - case kAiStatePatrolMoveL: - seq = pExtra->mvegseqofs; - start = 2, end = 7; - break; - case kAiStatePatrolTurnL: - seq = pExtra->mvegseqofs; - start = 7, end = 12; - break; - case kAiStatePatrolWaitW: - seq = pExtra->idlwseqofs; - start = 12; end = 18; - break; - case kAiStatePatrolMoveW: - seq = pExtra->mvewseqofs; - start = 18; end = 25; - break; - case kAiStatePatrolTurnW: - seq = pExtra->mvewseqofs; - start = 25; end = 32; - break; - case kAiStatePatrolWaitC: - seq = pExtra->idlcseqofs; - start = 32; end = 36; - crouch = true; - break; - case kAiStatePatrolMoveC: - seq = pExtra->mvecseqofs; - start = 36; end = 39; - crouch = true; - break; - case kAiStatePatrolTurnC: - seq = pExtra->mvecseqofs; - start = 39; end = kPatrolStateSize; - crouch = true; - break; - } + auto markeractor = actor->GetTarget(); + assert(markeractor->spr.type == kMarkerPath); - - if (markeractor->xspr.data4 > 0) seq = markeractor->xspr.data4, nSeqOverride = true; - else if (!nSeqOverride && state == kAiStatePatrolWaitC && (actor->spr.type == kDudeCultistTesla || actor->spr.type == kDudeCultistTNT)) - seq = 11537, nSeqOverride = true; // these don't have idle crouch seq for some reason... + bool nSeqOverride = false, crouch = false; + int i, seq = -1, start = 0, end = kPatrolStateSize; - if (seq < 0) - return aiPatrolStop(actor, nullptr); + const DUDEINFO_EXTRA* pExtra = &gDudeInfoExtra[actor->spr.type - kDudeBase]; - for (i = start; i < end; i++) - { - AISTATE* newState = &genPatrolStates[i]; - if (newState->stateType != state || (!nSeqOverride && seq != newState->seqId)) - continue; + switch (state) { + case kAiStatePatrolWaitL: + seq = pExtra->idlgseqofs; + start = 0; end = 2; + break; + case kAiStatePatrolMoveL: + seq = pExtra->mvegseqofs; + start = 2, end = 7; + break; + case kAiStatePatrolTurnL: + seq = pExtra->mvegseqofs; + start = 7, end = 12; + break; + case kAiStatePatrolWaitW: + seq = pExtra->idlwseqofs; + start = 12; end = 18; + break; + case kAiStatePatrolMoveW: + seq = pExtra->mvewseqofs; + start = 18; end = 25; + break; + case kAiStatePatrolTurnW: + seq = pExtra->mvewseqofs; + start = 25; end = 32; + break; + case kAiStatePatrolWaitC: + seq = pExtra->idlcseqofs; + start = 32; end = 36; + crouch = true; + break; + case kAiStatePatrolMoveC: + seq = pExtra->mvecseqofs; + start = 36; end = 39; + crouch = true; + break; + case kAiStatePatrolTurnC: + seq = pExtra->mvecseqofs; + start = 39; end = kPatrolStateSize; + crouch = true; + break; + } - if (actor->spr.type == kDudeModernCustom) aiGenDudeNewState(actor, newState); - else aiNewState(actor, newState); - if (crouch) actor->xspr.unused1 |= kDudeFlagCrouch; - else actor->xspr.unused1 &= ~kDudeFlagCrouch; + if (markeractor->xspr.data4 > 0) seq = markeractor->xspr.data4, nSeqOverride = true; + else if (!nSeqOverride && state == kAiStatePatrolWaitC && (actor->spr.type == kDudeCultistTesla || actor->spr.type == kDudeCultistTNT)) + seq = 11537, nSeqOverride = true; // these don't have idle crouch seq for some reason... - if (nSeqOverride) - seqSpawn(seq, actor); + if (seq < 0) + return aiPatrolStop(actor, nullptr); - return; - } + for (i = start; i < end; i++) + { + AISTATE* newState = &genPatrolStates[i]; + if (newState->stateType != state || (!nSeqOverride && seq != newState->seqId)) + continue; - if (i == end) - { - viewSetSystemMessage("No patrol state #%d found for dude #%d (type = %d)", state, actor->GetIndex(), actor->spr.type); - aiPatrolStop(actor, nullptr); - } + if (actor->spr.type == kDudeModernCustom) aiGenDudeNewState(actor, newState); + else aiNewState(actor, newState); + + if (crouch) actor->xspr.unused1 |= kDudeFlagCrouch; + else actor->xspr.unused1 &= ~kDudeFlagCrouch; + + if (nSeqOverride) + seqSpawn(seq, actor); + + return; + } + + if (i == end) + { + viewSetSystemMessage("No patrol state #%d found for dude #%d (type = %d)", state, actor->GetIndex(), actor->spr.type); + aiPatrolStop(actor, nullptr); + } } //--------------------------------------------------------------------------- @@ -7477,19 +7478,19 @@ void aiPatrolState(DBloodActor* actor, int state) // //--------------------------------------------------------------------------- -DBloodActor* aiPatrolMarkerBusy(DBloodActor* except, DBloodActor* marker) +DBloodActor* aiPatrolMarkerBusy(DBloodActor* except, DBloodActor* marker) { - BloodStatIterator it(kStatDude); - while (auto actor = it.Next()) - { - if (!actor->IsDudeActor() || actor == except || !actor->hasX()) - continue; + BloodStatIterator it(kStatDude); + while (auto actor = it.Next()) + { + if (!actor->IsDudeActor() || actor == except || !actor->hasX()) + continue; - auto targ = actor->GetTarget(); - if (actor->xspr.health > 0 && targ != nullptr && targ->spr.type == kMarkerPath && targ == marker) - return actor; - } - return nullptr; + auto targ = actor->GetTarget(); + if (actor->xspr.health > 0 && targ != nullptr && targ->spr.type == kMarkerPath && targ == marker) + return actor; + } + return nullptr; } //--------------------------------------------------------------------------- @@ -7498,36 +7499,36 @@ DBloodActor* aiPatrolMarkerBusy(DBloodActor* except, DBloodActor* marker) // //--------------------------------------------------------------------------- -bool aiPatrolMarkerReached(DBloodActor* actor) +bool aiPatrolMarkerReached(DBloodActor* actor) { - assert(actor->spr.type >= kDudeBase && actor->spr.type < kDudeMax); + assert(actor->spr.type >= kDudeBase && actor->spr.type < kDudeMax); - const DUDEINFO_EXTRA* pExtra = &gDudeInfoExtra[actor->spr.type - kDudeBase]; - auto markeractor = actor->GetTarget(); - if (markeractor && markeractor->spr.type == kMarkerPath) - { - int okDist = ClipLow(markeractor->spr.clipdist << 1, 4); - int oX = abs(markeractor->spr.pos.X - actor->spr.pos.X) >> 4; - int oY = abs(markeractor->spr.pos.Y - actor->spr.pos.Y) >> 4; + const DUDEINFO_EXTRA* pExtra = &gDudeInfoExtra[actor->spr.type - kDudeBase]; + auto markeractor = actor->GetTarget(); + if (markeractor && markeractor->spr.type == kMarkerPath) + { + int okDist = ClipLow(markeractor->spr.clipdist << 1, 4); + int oX = abs(markeractor->spr.pos.X - actor->spr.pos.X) >> 4; + int oY = abs(markeractor->spr.pos.Y - actor->spr.pos.Y) >> 4; - if (approxDist(oX, oY) <= okDist) - { - if (spriteIsUnderwater(actor) || pExtra->flying) - { - okDist = markeractor->spr.clipdist << 4; - int ztop, zbot, ztop2, zbot2; - GetActorExtents(actor, &ztop, &zbot); - GetActorExtents(markeractor, &ztop2, &zbot2); + if (approxDist(oX, oY) <= okDist) + { + if (spriteIsUnderwater(actor) || pExtra->flying) + { + okDist = markeractor->spr.clipdist << 4; + int ztop, zbot, ztop2, zbot2; + GetActorExtents(actor, &ztop, &zbot); + GetActorExtents(markeractor, &ztop2, &zbot2); - int oZ1 = abs(zbot - ztop2) >> 6; - int oZ2 = abs(ztop - zbot2) >> 6; - if (oZ1 > okDist && oZ2 > okDist) - return false; - } - return true; - } - } - return false; + int oZ1 = abs(zbot - ztop2) >> 6; + int oZ2 = abs(ztop - zbot2) >> 6; + if (oZ1 > okDist && oZ2 > okDist) + return false; + } + return true; + } + } + return false; } //--------------------------------------------------------------------------- @@ -7536,19 +7537,19 @@ bool aiPatrolMarkerReached(DBloodActor* actor) // //--------------------------------------------------------------------------- -DBloodActor* findNextMarker(DBloodActor* mark, bool back) +DBloodActor* findNextMarker(DBloodActor* mark, bool back) { - BloodStatIterator it(kStatPathMarker); - while (auto next = it.Next()) - { - if (!next->hasX() || next == mark) continue; + BloodStatIterator it(kStatPathMarker); + while (auto next = it.Next()) + { + if (!next->hasX() || next == mark) continue; - if ((next->xspr.locked || next->xspr.isTriggered || next->xspr.DudeLockout) || (back && next->xspr.data2 != mark->xspr.data1) || (!back && next->xspr.data1 != mark->xspr.data2)) - continue; + if ((next->xspr.locked || next->xspr.isTriggered || next->xspr.DudeLockout) || (back && next->xspr.data2 != mark->xspr.data1) || (!back && next->xspr.data1 != mark->xspr.data2)) + continue; - return next; - } - return nullptr; + return next; + } + return nullptr; } //--------------------------------------------------------------------------- @@ -7557,22 +7558,22 @@ DBloodActor* findNextMarker(DBloodActor* mark, bool back) // //--------------------------------------------------------------------------- -bool markerIsNode(DBloodActor* mark, bool back) +bool markerIsNode(DBloodActor* mark, bool back) { - int cnt = 0; + int cnt = 0; - BloodStatIterator it(kStatPathMarker); - while (auto next = it.Next()) - { - if (!next->hasX() || next == mark) continue; + BloodStatIterator it(kStatPathMarker); + while (auto next = it.Next()) + { + if (!next->hasX() || next == mark) continue; - if ((next->xspr.locked || next->xspr.isTriggered || next->xspr.DudeLockout) || (back && next->xspr.data2 != mark->xspr.data1) || (!back && next->xspr.data1 != mark->xspr.data2)) - continue; + if ((next->xspr.locked || next->xspr.isTriggered || next->xspr.DudeLockout) || (back && next->xspr.data2 != mark->xspr.data1) || (!back && next->xspr.data1 != mark->xspr.data2)) + continue; - if (++cnt > 1) - return true; - } - return false; + if (++cnt > 1) + return true; + } + return false; } //--------------------------------------------------------------------------- @@ -7583,97 +7584,97 @@ bool markerIsNode(DBloodActor* mark, bool back) void aiPatrolSetMarker(DBloodActor* actor) { - auto targetactor = actor->GetTarget(); + auto targetactor = actor->GetTarget(); - DBloodActor* selected = nullptr; - int closest = 200000; + DBloodActor* selected = nullptr; + int closest = 200000; - // select closest marker that dude can see - if (targetactor == nullptr) - { - int zt1, zb1, zt2, zb2, dist; - GetActorExtents(actor, &zt2, &zb2); + // select closest marker that dude can see + if (targetactor == nullptr) + { + int zt1, zb1, zt2, zb2, dist; + GetActorExtents(actor, &zt2, &zb2); - BloodStatIterator it(kStatPathMarker); - while (auto nextactor = it.Next()) - { - if (!nextactor->hasX()) continue; + BloodStatIterator it(kStatPathMarker); + while (auto nextactor = it.Next()) + { + if (!nextactor->hasX()) continue; - if (nextactor->xspr.locked || nextactor->xspr.isTriggered || nextactor->xspr.DudeLockout || (dist = approxDist(nextactor->spr.pos.X - actor->spr.pos.X, nextactor->spr.pos.Y - actor->spr.pos.Y)) > closest) - continue; + if (nextactor->xspr.locked || nextactor->xspr.isTriggered || nextactor->xspr.DudeLockout || (dist = approxDist(nextactor->spr.pos.X - actor->spr.pos.X, nextactor->spr.pos.Y - actor->spr.pos.Y)) > closest) + continue; - GetActorExtents(nextactor, &zt1, &zb1); - if (cansee(nextactor->spr.pos.X, nextactor->spr.pos.Y, zt1, nextactor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y, zt2, actor->spr.sector())) - { - closest = dist; - selected = nextactor; - } - } - } - // set next marker - else if (targetactor->spr.type == kMarkerPath && targetactor->hasX()) - { - // idea: which one of next (allowed) markers are closer to the potential target? - // idea: -3 select random next marker that dude can see in radius of reached marker - // if reached marker is in radius of another marker with -3, but greater radius, use that marker - // idea: for nodes only flag32 = specify if enemy must return back to node or allowed to select - // another marker which belongs that node? - DBloodActor* prevactor = nullptr; + GetActorExtents(nextactor, &zt1, &zb1); + if (cansee(nextactor->spr.pos.X, nextactor->spr.pos.Y, zt1, nextactor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y, zt2, actor->spr.sector())) + { + closest = dist; + selected = nextactor; + } + } + } + // set next marker + else if (targetactor->spr.type == kMarkerPath && targetactor->hasX()) + { + // idea: which one of next (allowed) markers are closer to the potential target? + // idea: -3 select random next marker that dude can see in radius of reached marker + // if reached marker is in radius of another marker with -3, but greater radius, use that marker + // idea: for nodes only flag32 = specify if enemy must return back to node or allowed to select + // another marker which belongs that node? + DBloodActor* prevactor = nullptr; - DBloodActor* firstFinePath = nullptr; - int next; + DBloodActor* firstFinePath = nullptr; + int next; - int breakChance = 0; - if (actor->prevmarker) - { - prevactor = actor->prevmarker; - } + int breakChance = 0; + if (actor->prevmarker) + { + prevactor = actor->prevmarker; + } - bool node = markerIsNode(targetactor, false); - actor->xspr.unused2 = aiPatrolGetPathDir(actor, targetactor); // decide if it should go back or forward - if (actor->xspr.unused2 == kPatrolMoveBackward && Chance(0x8000) && node) - actor->xspr.unused2 = kPatrolMoveForward; + bool node = markerIsNode(targetactor, false); + actor->xspr.unused2 = aiPatrolGetPathDir(actor, targetactor); // decide if it should go back or forward + if (actor->xspr.unused2 == kPatrolMoveBackward && Chance(0x8000) && node) + actor->xspr.unused2 = kPatrolMoveForward; - bool back = (actor->xspr.unused2 == kPatrolMoveBackward); next = (back) ? targetactor->xspr.data1 : targetactor->xspr.data2; - BloodStatIterator it(kStatPathMarker); - while(auto nextactor = it.Next()) - { - if (nextactor == targetactor || !nextactor->hasX()) continue; - else if (actor->xspr.targetX >= 0 && nextactor == prevactor && node) - { - if (targetactor->xspr.data2 == prevactor->xspr.data1) - continue; - } + bool back = (actor->xspr.unused2 == kPatrolMoveBackward); next = (back) ? targetactor->xspr.data1 : targetactor->xspr.data2; + BloodStatIterator it(kStatPathMarker); + while (auto nextactor = it.Next()) + { + if (nextactor == targetactor || !nextactor->hasX()) continue; + else if (actor->xspr.targetX >= 0 && nextactor == prevactor && node) + { + if (targetactor->xspr.data2 == prevactor->xspr.data1) + continue; + } - if ((nextactor->xspr.locked || nextactor->xspr.isTriggered || nextactor->xspr.DudeLockout) || (back && nextactor->xspr.data2 != next) || (!back && nextactor->xspr.data1 != next)) - continue; - - if (firstFinePath == nullptr) firstFinePath = nextactor; - if (aiPatrolMarkerBusy(actor, nextactor) && !Chance(0x0010)) continue; - else selected = nextactor; - - breakChance += nnExtRandom(1, 5); - if (breakChance >= 5) - break; + if ((nextactor->xspr.locked || nextactor->xspr.isTriggered || nextactor->xspr.DudeLockout) || (back && nextactor->xspr.data2 != next) || (!back && nextactor->xspr.data1 != next)) + continue; - } + if (firstFinePath == nullptr) firstFinePath = nextactor; + if (aiPatrolMarkerBusy(actor, nextactor) && !Chance(0x0010)) continue; + else selected = nextactor; - if (firstFinePath == nullptr) - { - viewSetSystemMessage("No markers with id #%d found for dude #%d! (back = %d)", next, actor->GetIndex(), back); - return; - } + breakChance += nnExtRandom(1, 5); + if (breakChance >= 5) + break; - if (selected == nullptr) - selected = firstFinePath; - } + } - if (!selected) - return; + if (firstFinePath == nullptr) + { + viewSetSystemMessage("No markers with id #%d found for dude #%d! (back = %d)", next, actor->GetIndex(), back); + return; + } - actor->SetTarget(selected); - selected->SetOwner(actor); - actor->prevmarker = targetactor; // keep previous marker index here, use actual sprite coords when selecting direction + if (selected == nullptr) + selected = firstFinePath; + } + + if (!selected) + return; + + actor->SetTarget(selected); + selected->SetOwner(actor); + actor->prevmarker = targetactor; // keep previous marker index here, use actual sprite coords when selecting direction } //--------------------------------------------------------------------------- @@ -7684,46 +7685,46 @@ void aiPatrolSetMarker(DBloodActor* actor) void aiPatrolStop(DBloodActor* actor, DBloodActor* targetactor, bool alarm) { - if (actor->hasX()) - { - actor->xspr.data3 = 0; // reset spot progress - actor->xspr.unused1 &= ~kDudeFlagCrouch; // reset the crouch status - actor->xspr.unused2 = kPatrolMoveForward; // reset path direction - actor->prevmarker = nullptr; - actor->xspr.targetX = -1; // reset the previous marker index - if (actor->xspr.health <= 0) - return; + if (actor->hasX()) + { + actor->xspr.data3 = 0; // reset spot progress + actor->xspr.unused1 &= ~kDudeFlagCrouch; // reset the crouch status + actor->xspr.unused2 = kPatrolMoveForward; // reset path direction + actor->prevmarker = nullptr; + actor->xspr.targetX = -1; // reset the previous marker index + if (actor->xspr.health <= 0) + return; - auto mytarget = actor->GetTarget(); + auto mytarget = actor->GetTarget(); - if (mytarget && mytarget->spr.type == kMarkerPath) - { - if (targetactor == nullptr) actor->spr.ang = mytarget->spr.ang & 2047; - actor->SetTarget(nullptr); - } + if (mytarget && mytarget->spr.type == kMarkerPath) + { + if (targetactor == nullptr) actor->spr.ang = mytarget->spr.ang & 2047; + actor->SetTarget(nullptr); + } - bool patrol = actor->xspr.dudeFlag4; - actor->xspr.dudeFlag4 = 0; - if (targetactor && targetactor->hasX() && targetactor->IsDudeActor()) - { - aiSetTarget(actor, targetactor); - aiActivateDude(actor); - - // alarm only when in non-recoil state? - //if (((actor->xspr.unused1 & kDudeFlagStealth) && stype != kAiStateRecoil) || !(actor->xspr.unused1 & kDudeFlagStealth)) { - if (alarm) aiPatrolAlarmFull(actor, targetactor, Chance(0x0100)); - else aiPatrolAlarmLite(actor, targetactor); - //} + bool patrol = actor->xspr.dudeFlag4; + actor->xspr.dudeFlag4 = 0; + if (targetactor && targetactor->hasX() && targetactor->IsDudeActor()) + { + aiSetTarget(actor, targetactor); + aiActivateDude(actor); - } - else - { - aiInitSprite(actor); - aiSetTarget(actor, actor->xspr.targetX, actor->xspr.targetY, actor->xspr.targetZ); - } - - actor->xspr.dudeFlag4 = patrol; // this must be kept so enemy can patrol after respawn again - } + // alarm only when in non-recoil state? + //if (((actor->xspr.unused1 & kDudeFlagStealth) && stype != kAiStateRecoil) || !(actor->xspr.unused1 & kDudeFlagStealth)) { + if (alarm) aiPatrolAlarmFull(actor, targetactor, Chance(0x0100)); + else aiPatrolAlarmLite(actor, targetactor); + //} + + } + else + { + aiInitSprite(actor); + aiSetTarget(actor, actor->xspr.targetX, actor->xspr.targetY, actor->xspr.targetZ); + } + + actor->xspr.dudeFlag4 = patrol; // this must be kept so enemy can patrol after respawn again + } } //--------------------------------------------------------------------------- @@ -7732,19 +7733,19 @@ void aiPatrolStop(DBloodActor* actor, DBloodActor* targetactor, bool alarm) // //--------------------------------------------------------------------------- -void aiPatrolRandGoalAng(DBloodActor* actor) +void aiPatrolRandGoalAng(DBloodActor* actor) { - int goal = kAng90; - if (Chance(0x4000)) - goal = kAng120; + int goal = kAng90; + if (Chance(0x4000)) + goal = kAng120; - if (Chance(0x4000)) - goal = kAng180; + if (Chance(0x4000)) + goal = kAng180; - if (Chance(0x8000)) - goal = -goal; + if (Chance(0x8000)) + goal = -goal; - actor->xspr.goalAng = (actor->spr.ang + goal) & 2047; + actor->xspr.goalAng = (actor->spr.ang + goal) & 2047; } //--------------------------------------------------------------------------- @@ -7755,9 +7756,9 @@ void aiPatrolRandGoalAng(DBloodActor* actor) void aiPatrolTurn(DBloodActor* actor) { - int nTurnRange = (getDudeInfo(actor->spr.type)->angSpeed << 1) >> 4; - int nAng = ((actor->xspr.goalAng + 1024 - actor->spr.ang) & 2047) - 1024; - actor->spr.ang = (actor->spr.ang + ClipRange(nAng, -nTurnRange, nTurnRange)) & 2047; + int nTurnRange = (getDudeInfo(actor->spr.type)->angSpeed << 1) >> 4; + int nAng = ((actor->xspr.goalAng + 1024 - actor->spr.ang) & 2047) - 1024; + actor->spr.ang = (actor->spr.ang + ClipRange(nAng, -nTurnRange, nTurnRange)) & 2047; } @@ -7767,70 +7768,70 @@ void aiPatrolTurn(DBloodActor* actor) // //--------------------------------------------------------------------------- -void aiPatrolMove(DBloodActor* actor) +void aiPatrolMove(DBloodActor* actor) { - auto targetactor = actor->GetTarget(); + auto targetactor = actor->GetTarget(); - if (!(actor->spr.type >= kDudeBase && actor->spr.type < kDudeMax) || !targetactor) - return; + if (!(actor->spr.type >= kDudeBase && actor->spr.type < kDudeMax) || !targetactor) + return; - int dudeIdx = actor->spr.type - kDudeBase; - switch (actor->spr.type) - { - case kDudeCultistShotgunProne: dudeIdx = kDudeCultistShotgun - kDudeBase; break; - case kDudeCultistTommyProne: dudeIdx = kDudeCultistTommy - kDudeBase; break; - } + int dudeIdx = actor->spr.type - kDudeBase; + switch (actor->spr.type) + { + case kDudeCultistShotgunProne: dudeIdx = kDudeCultistShotgun - kDudeBase; break; + case kDudeCultistTommyProne: dudeIdx = kDudeCultistTommy - kDudeBase; break; + } - DUDEINFO* pDudeInfo = &dudeInfo[dudeIdx]; - const DUDEINFO_EXTRA* pExtra = &gDudeInfoExtra[dudeIdx]; - - int dx = (targetactor->spr.pos.X - actor->spr.pos.X); - int dy = (targetactor->spr.pos.Y - actor->spr.pos.Y); - int dz = (targetactor->spr.pos.Z - (actor->spr.pos.Z - pDudeInfo->eyeHeight)) * 6; - int vel = (actor->xspr.unused1 & kDudeFlagCrouch) ? kMaxPatrolCrouchVelocity : kMaxPatrolVelocity; - int goalAng = 341; + DUDEINFO* pDudeInfo = &dudeInfo[dudeIdx]; + const DUDEINFO_EXTRA* pExtra = &gDudeInfoExtra[dudeIdx]; - if (pExtra->flying || spriteIsUnderwater(actor)) - { - goalAng >>= 1; - actor->zvel = dz; - if (actor->spr.flags & kPhysGravity) - actor->spr.flags &= ~kPhysGravity; - } - else if (!pExtra->flying) - { - actor->spr.flags |= kPhysGravity | kPhysFalling; - } + int dx = (targetactor->spr.pos.X - actor->spr.pos.X); + int dy = (targetactor->spr.pos.Y - actor->spr.pos.Y); + int dz = (targetactor->spr.pos.Z - (actor->spr.pos.Z - pDudeInfo->eyeHeight)) * 6; + int vel = (actor->xspr.unused1 & kDudeFlagCrouch) ? kMaxPatrolCrouchVelocity : kMaxPatrolVelocity; + int goalAng = 341; - int nTurnRange = (pDudeInfo->angSpeed << 2) >> 4; - int nAng = ((actor->xspr.goalAng + 1024 - actor->spr.ang) & 2047) - 1024; - actor->spr.ang = (actor->spr.ang + ClipRange(nAng, -nTurnRange, nTurnRange)) & 2047; - - if (abs(nAng) > goalAng || ((targetactor->xspr.waitTime > 0 || targetactor->xspr.data1 == targetactor->xspr.data2) && aiPatrolMarkerReached(actor))) - { - actor->xvel = 0; - actor->yvel = 0; - return; - } - - if (actor->hit.hit.type == kHitSprite) - { - auto hitactor = actor->hit.hit.actor(); - hitactor->xspr.dodgeDir = -1; - actor->xspr.dodgeDir = 1; - aiMoveDodge(hitactor); - } - else - { - int frontSpeed = aiPatrolGetVelocity(pDudeInfo->frontSpeed, targetactor->xspr.busyTime); - actor->xvel += MulScale(frontSpeed, Cos(actor->spr.ang), 30); - actor->yvel += MulScale(frontSpeed, Sin(actor->spr.ang), 30); - } + if (pExtra->flying || spriteIsUnderwater(actor)) + { + goalAng >>= 1; + actor->zvel = dz; + if (actor->spr.flags & kPhysGravity) + actor->spr.flags &= ~kPhysGravity; + } + else if (!pExtra->flying) + { + actor->spr.flags |= kPhysGravity | kPhysFalling; + } - vel = MulScale(vel, approxDist(dx, dy) << 6, 16); - actor->xvel = ClipRange(actor->xvel, -vel, vel); - actor->yvel = ClipRange(actor->yvel, -vel, vel); + int nTurnRange = (pDudeInfo->angSpeed << 2) >> 4; + int nAng = ((actor->xspr.goalAng + 1024 - actor->spr.ang) & 2047) - 1024; + actor->spr.ang = (actor->spr.ang + ClipRange(nAng, -nTurnRange, nTurnRange)) & 2047; + + if (abs(nAng) > goalAng || ((targetactor->xspr.waitTime > 0 || targetactor->xspr.data1 == targetactor->xspr.data2) && aiPatrolMarkerReached(actor))) + { + actor->xvel = 0; + actor->yvel = 0; + return; + } + + if (actor->hit.hit.type == kHitSprite) + { + auto hitactor = actor->hit.hit.actor(); + hitactor->xspr.dodgeDir = -1; + actor->xspr.dodgeDir = 1; + aiMoveDodge(hitactor); + } + else + { + int frontSpeed = aiPatrolGetVelocity(pDudeInfo->frontSpeed, targetactor->xspr.busyTime); + actor->xvel += MulScale(frontSpeed, Cos(actor->spr.ang), 30); + actor->yvel += MulScale(frontSpeed, Sin(actor->spr.ang), 30); + } + + vel = MulScale(vel, approxDist(dx, dy) << 6, 16); + actor->xvel = ClipRange(actor->xvel, -vel, vel); + actor->yvel = ClipRange(actor->yvel, -vel, vel); } //--------------------------------------------------------------------------- @@ -7839,43 +7840,43 @@ void aiPatrolMove(DBloodActor* actor) // //--------------------------------------------------------------------------- -void aiPatrolAlarmLite(DBloodActor* actor, DBloodActor* targetactor) +void aiPatrolAlarmLite(DBloodActor* actor, DBloodActor* targetactor) { - if (!actor->hasX() || !actor->IsDudeActor()) - return; + if (!actor->hasX() || !actor->IsDudeActor()) + return; - if (actor->xspr.health <= 0) - return; + if (actor->xspr.health <= 0) + return; - int zt1, zb1, zt2, zb2; //int eaz1 = (getDudeInfo(actor->spr.type)->eyeHeight * actor->spr.yrepeat) << 2; - GetActorExtents(actor, &zt1, &zb1); - GetActorExtents(targetactor, &zt2, &zb2); - - BloodStatIterator it(kStatDude); - while (auto dudeactor = it.Next()) - { - if (dudeactor == actor || !dudeactor->IsDudeActor() || dudeactor->IsPlayerActor() || !dudeactor->hasX()) - continue; + int zt1, zb1, zt2, zb2; //int eaz1 = (getDudeInfo(actor->spr.type)->eyeHeight * actor->spr.yrepeat) << 2; + GetActorExtents(actor, &zt1, &zb1); + GetActorExtents(targetactor, &zt2, &zb2); - if (dudeactor->xspr.health <= 0) - continue; + BloodStatIterator it(kStatDude); + while (auto dudeactor = it.Next()) + { + if (dudeactor == actor || !dudeactor->IsDudeActor() || dudeactor->IsPlayerActor() || !dudeactor->hasX()) + continue; - int eaz2 = (getDudeInfo(targetactor->spr.type)->eyeHeight * targetactor->spr.yrepeat) << 2; - int nDist = approxDist(dudeactor->spr.pos.X - actor->spr.pos.X, dudeactor->spr.pos.Y - actor->spr.pos.Y); - if (nDist >= kPatrolAlarmSeeDist || !cansee(actor->spr.pos.X, actor->spr.pos.Y, zt1, actor->spr.sector(), dudeactor->spr.pos.X, dudeactor->spr.pos.Y, dudeactor->spr.pos.Z - eaz2, dudeactor->spr.sector())) - { - nDist = approxDist(dudeactor->spr.pos.X - targetactor->spr.pos.X, dudeactor->spr.pos.Y - targetactor->spr.pos.Y); - if (nDist >= kPatrolAlarmSeeDist || !cansee(targetactor->spr.pos.X, targetactor->spr.pos.Y, zt2, targetactor->spr.sector(), dudeactor->spr.pos.X, dudeactor->spr.pos.Y, dudeactor->spr.pos.Z - eaz2, dudeactor->spr.sector())) - continue; - } + if (dudeactor->xspr.health <= 0) + continue; - if (aiInPatrolState(dudeactor->xspr.aiState)) aiPatrolStop(dudeactor, dudeactor->GetTarget()); - if (dudeactor->GetTarget() && dudeactor->GetTarget() == actor->GetTarget()) - continue; + int eaz2 = (getDudeInfo(targetactor->spr.type)->eyeHeight * targetactor->spr.yrepeat) << 2; + int nDist = approxDist(dudeactor->spr.pos.X - actor->spr.pos.X, dudeactor->spr.pos.Y - actor->spr.pos.Y); + if (nDist >= kPatrolAlarmSeeDist || !cansee(actor->spr.pos.X, actor->spr.pos.Y, zt1, actor->spr.sector(), dudeactor->spr.pos.X, dudeactor->spr.pos.Y, dudeactor->spr.pos.Z - eaz2, dudeactor->spr.sector())) + { + nDist = approxDist(dudeactor->spr.pos.X - targetactor->spr.pos.X, dudeactor->spr.pos.Y - targetactor->spr.pos.Y); + if (nDist >= kPatrolAlarmSeeDist || !cansee(targetactor->spr.pos.X, targetactor->spr.pos.Y, zt2, targetactor->spr.sector(), dudeactor->spr.pos.X, dudeactor->spr.pos.Y, dudeactor->spr.pos.Z - eaz2, dudeactor->spr.sector())) + continue; + } - aiSetTarget(dudeactor, targetactor); - aiActivateDude(dudeactor); - } + if (aiInPatrolState(dudeactor->xspr.aiState)) aiPatrolStop(dudeactor, dudeactor->GetTarget()); + if (dudeactor->GetTarget() && dudeactor->GetTarget() == actor->GetTarget()) + continue; + + aiSetTarget(dudeactor, targetactor); + aiActivateDude(dudeactor); + } } //--------------------------------------------------------------------------- @@ -7884,60 +7885,60 @@ void aiPatrolAlarmLite(DBloodActor* actor, DBloodActor* targetactor) // //--------------------------------------------------------------------------- -void aiPatrolAlarmFull(DBloodActor* actor, DBloodActor* targetactor, bool chain) +void aiPatrolAlarmFull(DBloodActor* actor, DBloodActor* targetactor, bool chain) { - if (!actor->hasX() || !actor->IsDudeActor()) - return; + if (!actor->hasX() || !actor->IsDudeActor()) + return; - if (actor->xspr.health <= 0) - return; + if (actor->xspr.health <= 0) + return; - int eaz2 = (getDudeInfo(actor->spr.type)->eyeHeight * actor->spr.yrepeat) << 2; - int x2 = actor->spr.pos.X, y2 = actor->spr.pos.Y, z2 = actor->spr.pos.Z - eaz2; - - auto pSect2 = actor->spr.sector(); - - int tzt, tzb; - GetActorExtents(targetactor, &tzt, &tzb); - int x3 = targetactor->spr.pos.X, y3 = targetactor->spr.pos.Y, z3 = tzt; - - auto pSect3 = targetactor->spr.sector(); + int eaz2 = (getDudeInfo(actor->spr.type)->eyeHeight * actor->spr.yrepeat) << 2; + int x2 = actor->spr.pos.X, y2 = actor->spr.pos.Y, z2 = actor->spr.pos.Z - eaz2; - BloodStatIterator it(kStatDude); - while (auto dudeactor = it.Next()) - { - if (dudeactor == actor || !dudeactor->IsDudeActor() || dudeactor->IsPlayerActor() || !dudeactor->hasX()) - continue; + auto pSect2 = actor->spr.sector(); - if (dudeactor->xspr.health <= 0) - continue; + int tzt, tzb; + GetActorExtents(targetactor, &tzt, &tzb); + int x3 = targetactor->spr.pos.X, y3 = targetactor->spr.pos.Y, z3 = tzt; - int eaz1 = (getDudeInfo(dudeactor->spr.type)->eyeHeight * dudeactor->spr.yrepeat) << 2; - int x1 = dudeactor->spr.pos.X, y1 = dudeactor->spr.pos.Y, z1 = dudeactor->spr.pos.Z - eaz1; - - auto pSect1 = dudeactor->spr.sector(); + auto pSect3 = targetactor->spr.sector(); - int nDist1 = approxDist(x1 - x2, y1 - y2); - int nDist2 = approxDist(x1 - x3, y1 - y3); - //int hdist = (dudeactor->xspr.dudeDeaf) ? 0 : getDudeInfo(dudeactor->spr.type)->hearDist / 4; - int sdist = (dudeactor->xspr.dudeGuard) ? 0 : getDudeInfo(dudeactor->spr.type)->seeDist / 2; + BloodStatIterator it(kStatDude); + while (auto dudeactor = it.Next()) + { + if (dudeactor == actor || !dudeactor->IsDudeActor() || dudeactor->IsPlayerActor() || !dudeactor->hasX()) + continue; - if (//(nDist1 < hdist || nDist2 < hdist) || - ((nDist1 < sdist && cansee(x1, y1, z1, pSect1, x2, y2, z2, pSect2)) || (nDist2 < sdist && cansee(x1, y1, z1, pSect1, x3, y3, z3, pSect3)))) { + if (dudeactor->xspr.health <= 0) + continue; - if (aiInPatrolState(dudeactor->xspr.aiState)) aiPatrolStop(dudeactor, dudeactor->GetTarget()); - if (dudeactor->GetTarget() && dudeactor->GetTarget() == actor->GetTarget()) - continue; + int eaz1 = (getDudeInfo(dudeactor->spr.type)->eyeHeight * dudeactor->spr.yrepeat) << 2; + int x1 = dudeactor->spr.pos.X, y1 = dudeactor->spr.pos.Y, z1 = dudeactor->spr.pos.Z - eaz1; - if (actor->GetTarget() ) aiSetTarget(dudeactor, actor->GetTarget()); - else aiSetTarget(dudeactor, actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z); - aiActivateDude(dudeactor); + auto pSect1 = dudeactor->spr.sector(); - if (chain) - aiPatrolAlarmFull(dudeactor, targetactor, Chance(0x0010)); - //Printf("Dude #%d alarms dude #%d", actor->GetIndex(), dudeactor->spr.index); - } - } + int nDist1 = approxDist(x1 - x2, y1 - y2); + int nDist2 = approxDist(x1 - x3, y1 - y3); + //int hdist = (dudeactor->xspr.dudeDeaf) ? 0 : getDudeInfo(dudeactor->spr.type)->hearDist / 4; + int sdist = (dudeactor->xspr.dudeGuard) ? 0 : getDudeInfo(dudeactor->spr.type)->seeDist / 2; + + if (//(nDist1 < hdist || nDist2 < hdist) || + ((nDist1 < sdist && cansee(x1, y1, z1, pSect1, x2, y2, z2, pSect2)) || (nDist2 < sdist && cansee(x1, y1, z1, pSect1, x3, y3, z3, pSect3)))) { + + if (aiInPatrolState(dudeactor->xspr.aiState)) aiPatrolStop(dudeactor, dudeactor->GetTarget()); + if (dudeactor->GetTarget() && dudeactor->GetTarget() == actor->GetTarget()) + continue; + + if (actor->GetTarget()) aiSetTarget(dudeactor, actor->GetTarget()); + else aiSetTarget(dudeactor, actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z); + aiActivateDude(dudeactor); + + if (chain) + aiPatrolAlarmFull(dudeactor, targetactor, Chance(0x0010)); + //Printf("Dude #%d alarms dude #%d", actor->GetIndex(), dudeactor->spr.index); + } + } } //--------------------------------------------------------------------------- @@ -7946,18 +7947,18 @@ void aiPatrolAlarmFull(DBloodActor* actor, DBloodActor* targetactor, bool chain) // //--------------------------------------------------------------------------- -bool spritesTouching(DBloodActor *actor1, DBloodActor* actor2) +bool spritesTouching(DBloodActor* actor1, DBloodActor* actor2) { - if (!actor1->hasX() || !actor2->hasX()) - return false; + if (!actor1->hasX() || !actor2->hasX()) + return false; - auto hit = &actor1->hit; - DBloodActor* hitactor = nullptr; - if (hit->hit.type == kHitSprite) hitactor = hit->hit.actor(); - else if (hit->florhit.type == kHitSprite) hitactor = hit->florhit.actor(); - else if (hit->ceilhit.type == kHitSprite) hitactor = hit->ceilhit.actor(); - else return false; - return hitactor->hasX() && hitactor == actor2; + auto hit = &actor1->hit; + DBloodActor* hitactor = nullptr; + if (hit->hit.type == kHitSprite) hitactor = hit->hit.actor(); + else if (hit->florhit.type == kHitSprite) hitactor = hit->florhit.actor(); + else if (hit->ceilhit.type == kHitSprite) hitactor = hit->ceilhit.actor(); + else return false; + return hitactor->hasX() && hitactor == actor2; } //--------------------------------------------------------------------------- @@ -7968,12 +7969,12 @@ bool spritesTouching(DBloodActor *actor1, DBloodActor* actor2) bool aiCanCrouch(DBloodActor* actor) { - if (actor->spr.type >= kDudeBase && actor->spr.type < kDudeVanillaMax) - return (gDudeInfoExtra[actor->spr.type - kDudeBase].idlcseqofs >= 0 && gDudeInfoExtra[actor->spr.type - kDudeBase].mvecseqofs >= 0); - else if (actor->spr.type == kDudeModernCustom || actor->spr.type == kDudeModernCustomBurning) - return actor->genDudeExtra.canDuck; + if (actor->spr.type >= kDudeBase && actor->spr.type < kDudeVanillaMax) + return (gDudeInfoExtra[actor->spr.type - kDudeBase].idlcseqofs >= 0 && gDudeInfoExtra[actor->spr.type - kDudeBase].mvecseqofs >= 0); + else if (actor->spr.type == kDudeModernCustom || actor->spr.type == kDudeModernCustomBurning) + return actor->genDudeExtra.canDuck; - return false; + return false; } @@ -7983,18 +7984,18 @@ bool aiCanCrouch(DBloodActor* actor) // //--------------------------------------------------------------------------- -bool readyForCrit(DBloodActor* hunter, DBloodActor* victim) +bool readyForCrit(DBloodActor* hunter, DBloodActor* victim) { - if (!(hunter->spr.type >= kDudeBase && hunter->spr.type < kDudeMax) || !(victim->spr.type >= kDudeBase && victim->spr.type < kDudeMax)) - return false; + if (!(hunter->spr.type >= kDudeBase && hunter->spr.type < kDudeMax) || !(victim->spr.type >= kDudeBase && victim->spr.type < kDudeMax)) + return false; - int dx, dy; - dx = victim->spr.pos.X - hunter->spr.pos.X; - dy = victim->spr.pos.Y - hunter->spr.pos.Y; - if (approxDist(dx, dy) >= (7000 / ClipLow(gGameOptions.nDifficulty >> 1, 1))) - return false; - - return (abs(((getangle(dx, dy) + 1024 - victim->spr.ang) & 2047) - 1024) <= kAng45); + int dx, dy; + dx = victim->spr.pos.X - hunter->spr.pos.X; + dy = victim->spr.pos.Y - hunter->spr.pos.Y; + if (approxDist(dx, dy) >= (7000 / ClipLow(gGameOptions.nDifficulty >> 1, 1))) + return false; + + return (abs(((getangle(dx, dy) + 1024 - victim->spr.ang) & 2047) - 1024) <= kAng45); } //--------------------------------------------------------------------------- @@ -8003,321 +8004,321 @@ bool readyForCrit(DBloodActor* hunter, DBloodActor* victim) // //--------------------------------------------------------------------------- -DBloodActor* aiPatrolSearchTargets(DBloodActor* actor) +DBloodActor* aiPatrolSearchTargets(DBloodActor* actor) { - enum { kMaxPatrolFoundSounds = 256 }; // should be the maximum amount of sound channels the engine can play at the same time. - PATROL_FOUND_SOUNDS patrolBonkles[kMaxPatrolFoundSounds]; + enum { kMaxPatrolFoundSounds = 256 }; // should be the maximum amount of sound channels the engine can play at the same time. + PATROL_FOUND_SOUNDS patrolBonkles[kMaxPatrolFoundSounds]; - assert(actor->spr.type >= kDudeBase && actor->spr.type < kDudeMax); - DUDEINFO* pDudeInfo = getDudeInfo(actor->spr.type); PLAYER* pPlayer = NULL; - - for (int i = 0; i < kMaxPatrolFoundSounds; i++) - { - patrolBonkles[i].snd = patrolBonkles[i].cur = 0; - patrolBonkles[i].max = ClipLow((gGameOptions.nDifficulty + 1) >> 1, 1); - } + assert(actor->spr.type >= kDudeBase && actor->spr.type < kDudeMax); + DUDEINFO* pDudeInfo = getDudeInfo(actor->spr.type); PLAYER* pPlayer = NULL; - int i, j, f, mod, x, y, z, dx, dy, nDist, eyeAboveZ, sndCnt = 0, seeDist, hearDist, feelDist, seeChance, hearChance; - bool stealth = (actor->xspr.unused1 & kDudeFlagStealth); - bool blind = (actor->xspr.dudeGuard); - bool deaf = (actor->xspr.dudeDeaf); + for (int i = 0; i < kMaxPatrolFoundSounds; i++) + { + patrolBonkles[i].snd = patrolBonkles[i].cur = 0; + patrolBonkles[i].max = ClipLow((gGameOptions.nDifficulty + 1) >> 1, 1); + } - DBloodActor* newtarget = nullptr; - // search for player targets - for (i = connecthead; i != -1; i = connectpoint2[i]) - { - pPlayer = &gPlayer[i]; - if (!pPlayer->actor->hasX()) continue; + int i, j, f, mod, x, y, z, dx, dy, nDist, eyeAboveZ, sndCnt = 0, seeDist, hearDist, feelDist, seeChance, hearChance; + bool stealth = (actor->xspr.unused1 & kDudeFlagStealth); + bool blind = (actor->xspr.dudeGuard); + bool deaf = (actor->xspr.dudeDeaf); - auto plActor = pPlayer->actor; - if (plActor->xspr.health <= 0) - continue; + DBloodActor* newtarget = nullptr; + // search for player targets + for (i = connecthead; i != -1; i = connectpoint2[i]) + { + pPlayer = &gPlayer[i]; + if (!pPlayer->actor->hasX()) continue; - newtarget = nullptr; - seeChance = hearChance = 0x0000; - x = plActor->spr.pos.X, y = plActor->spr.pos.Y, z = plActor->spr.pos.Z, dx = x - actor->spr.pos.X, dy = y - actor->spr.pos.Y; nDist = approxDist(dx, dy); - seeDist = (stealth) ? pDudeInfo->seeDist / 3 : pDudeInfo->seeDist >> 1; - hearDist = pDudeInfo->hearDist; feelDist = hearDist >> 1; + auto plActor = pPlayer->actor; + if (plActor->xspr.health <= 0) + continue; - // TO-DO: is there any dudes that sees this patrol dude and sees target? + newtarget = nullptr; + seeChance = hearChance = 0x0000; + x = plActor->spr.pos.X, y = plActor->spr.pos.Y, z = plActor->spr.pos.Z, dx = x - actor->spr.pos.X, dy = y - actor->spr.pos.Y; nDist = approxDist(dx, dy); + seeDist = (stealth) ? pDudeInfo->seeDist / 3 : pDudeInfo->seeDist >> 1; + hearDist = pDudeInfo->hearDist; feelDist = hearDist >> 1; + + // TO-DO: is there any dudes that sees this patrol dude and sees target? - if (nDist <= seeDist) - { - eyeAboveZ = (pDudeInfo->eyeHeight * actor->spr.yrepeat) << 2; - if (nDist < seeDist >> 3) GetActorExtents(pPlayer->actor, &z, &j); //use ztop of the target sprite - if (!cansee(x, y, z, plActor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z - eyeAboveZ, actor->spr.sector())) - continue; - } - else - continue; + if (nDist <= seeDist) + { + eyeAboveZ = (pDudeInfo->eyeHeight * actor->spr.yrepeat) << 2; + if (nDist < seeDist >> 3) GetActorExtents(pPlayer->actor, &z, &j); //use ztop of the target sprite + if (!cansee(x, y, z, plActor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z - eyeAboveZ, actor->spr.sector())) + continue; + } + else + continue; - bool invisible = (powerupCheck(pPlayer, kPwUpShadowCloak) > 0); - if (spritesTouching(actor, pPlayer->actor) || spritesTouching(pPlayer->actor, actor)) - { - DPrintf(DMSG_SPAMMY, "Patrol dude #%d spot the Player #%d via touch.", actor->GetIndex(), pPlayer->nPlayer + 1); - if (invisible) pPlayer->pwUpTime[kPwUpShadowCloak] = 0; - newtarget = pPlayer->actor; - break; - } + bool invisible = (powerupCheck(pPlayer, kPwUpShadowCloak) > 0); + if (spritesTouching(actor, pPlayer->actor) || spritesTouching(pPlayer->actor, actor)) + { + DPrintf(DMSG_SPAMMY, "Patrol dude #%d spot the Player #%d via touch.", actor->GetIndex(), pPlayer->nPlayer + 1); + if (invisible) pPlayer->pwUpTime[kPwUpShadowCloak] = 0; + newtarget = pPlayer->actor; + break; + } - if (!deaf) - { + if (!deaf) + { - soundEngine->EnumerateChannels([&](FSoundChan* chan) - { - int sndx = 0, sndy = 0; - sectortype* searchsect = nullptr; - if (chan->SourceType == SOURCE_Actor) - { - auto emitterActor = (DBloodActor*)chan->Source; - if (emitterActor == nullptr) return false; // not a valid source. - sndx = emitterActor->spr.pos.X; - sndy = emitterActor->spr.pos.Y; + soundEngine->EnumerateChannels([&](FSoundChan* chan) + { + int sndx = 0, sndy = 0; + sectortype* searchsect = nullptr; + if (chan->SourceType == SOURCE_Actor) + { + auto emitterActor = (DBloodActor*)chan->Source; + if (emitterActor == nullptr) return false; // not a valid source. + sndx = emitterActor->spr.pos.X; + sndy = emitterActor->spr.pos.Y; - // sound attached to the sprite - if (pPlayer->actor != emitterActor && emitterActor->GetOwner() != actor) - { + // sound attached to the sprite + if (pPlayer->actor != emitterActor && emitterActor->GetOwner() != actor) + { - if (!emitterActor->spr.insector()) return false; - searchsect = emitterActor->spr.sector(); - } - } - else if (chan->SourceType == SOURCE_Unattached) - { - if (chan->UserData < 0 || !validSectorIndex(chan->UserData)) return false; // not a vaild sector sound. - sndx = int(chan->Point[0] * 16); - sndy = int(chan->Point[1] * -16); - searchsect = §or[chan->UserData]; - } - if (searchsect == nullptr) return false; - int nDist = approxDist(sndx - actor->spr.pos.X, sndy - actor->spr.pos.Y); - if (nDist > hearDist) return false; + if (!emitterActor->spr.insector()) return false; + searchsect = emitterActor->spr.sector(); + } + } + else if (chan->SourceType == SOURCE_Unattached) + { + if (chan->UserData < 0 || !validSectorIndex(chan->UserData)) return false; // not a vaild sector sound. + sndx = int(chan->Point[0] * 16); + sndy = int(chan->Point[1] * -16); + searchsect = §or[chan->UserData]; + } + if (searchsect == nullptr) return false; + int nDist = approxDist(sndx - actor->spr.pos.X, sndy - actor->spr.pos.Y); + if (nDist > hearDist) return false; - int sndnum = chan->OrgID; + int sndnum = chan->OrgID; - // N same sounds per single enemy - for (int f = 0; f < sndCnt; f++) - { - if (patrolBonkles[f].snd != sndnum) continue; - else if (++patrolBonkles[f].cur >= patrolBonkles[f].max) - return false; - } - if (sndCnt < kMaxPatrolFoundSounds - 1) - patrolBonkles[sndCnt++].snd = sndnum; + // N same sounds per single enemy + for (int f = 0; f < sndCnt; f++) + { + if (patrolBonkles[f].snd != sndnum) continue; + else if (++patrolBonkles[f].cur >= patrolBonkles[f].max) + return false; + } + if (sndCnt < kMaxPatrolFoundSounds - 1) + patrolBonkles[sndCnt++].snd = sndnum; - bool found = false; - BloodSectIterator it(searchsect); - while (auto act = it.Next()) - { - if (act->GetOwner() == pPlayer->actor) - { - found = true; - break; - } - } - if (!found) return false; + bool found = false; + BloodSectIterator it(searchsect); + while (auto act = it.Next()) + { + if (act->GetOwner() == pPlayer->actor) + { + found = true; + break; + } + } + if (!found) return false; - f = ClipLow((hearDist - nDist) / 8, 0); - int sndvol = int(chan->Volume * (80.f / 0.8f)); - hearChance += mulscale8(sndvol, f) + Random(gGameOptions.nDifficulty); - return (hearChance >= kMaxPatrolSpotValue); - }); + f = ClipLow((hearDist - nDist) / 8, 0); + int sndvol = int(chan->Volume * (80.f / 0.8f)); + hearChance += mulscale8(sndvol, f) + Random(gGameOptions.nDifficulty); + return (hearChance >= kMaxPatrolSpotValue); + }); - if (invisible && hearChance >= kMaxPatrolSpotValue >> 2) - { - newtarget = pPlayer->actor; - pPlayer->pwUpTime[kPwUpShadowCloak] = 0; - invisible = false; - break; - } - } + if (invisible && hearChance >= kMaxPatrolSpotValue >> 2) + { + newtarget = pPlayer->actor; + pPlayer->pwUpTime[kPwUpShadowCloak] = 0; + invisible = false; + break; + } + } - if (!invisible && (!deaf || !blind)) - { - if (stealth) - { - switch (pPlayer->lifeMode) - { - case kModeHuman: - case kModeHumanShrink: - if (pPlayer->lifeMode == kModeHumanShrink) - { - seeDist -= mulscale8(164, seeDist); - feelDist -= mulscale8(164, feelDist); - } - if (pPlayer->posture == kPostureCrouch) - { - seeDist -= mulscale8(64, seeDist); - feelDist -= mulscale8(128, feelDist); - } - break; - case kModeHumanGrown: - if (pPlayer->posture != kPostureCrouch) - { - seeDist += mulscale8(72, seeDist); - feelDist += mulscale8(64, feelDist); - } - else - { - seeDist += mulscale8(48, seeDist); - } - break; - } - } + if (!invisible && (!deaf || !blind)) + { + if (stealth) + { + switch (pPlayer->lifeMode) + { + case kModeHuman: + case kModeHumanShrink: + if (pPlayer->lifeMode == kModeHumanShrink) + { + seeDist -= mulscale8(164, seeDist); + feelDist -= mulscale8(164, feelDist); + } + if (pPlayer->posture == kPostureCrouch) + { + seeDist -= mulscale8(64, seeDist); + feelDist -= mulscale8(128, feelDist); + } + break; + case kModeHumanGrown: + if (pPlayer->posture != kPostureCrouch) + { + seeDist += mulscale8(72, seeDist); + feelDist += mulscale8(64, feelDist); + } + else + { + seeDist += mulscale8(48, seeDist); + } + break; + } + } - bool itCanHear = false; bool itCanSee = false; - feelDist = ClipLow(feelDist, 0); - seeDist = ClipLow(seeDist, 0); + bool itCanHear = false; bool itCanSee = false; + feelDist = ClipLow(feelDist, 0); + seeDist = ClipLow(seeDist, 0); - if (hearDist) - { - DBloodActor* act = pPlayer->actor; - itCanHear = (!deaf && (nDist < hearDist || hearChance > 0)); - if (act && itCanHear && nDist < feelDist && (act->xvel || act->yvel || act->zvel)) - hearChance += ClipLow(mulscale8(1, ClipLow(((feelDist - nDist) + (abs(act->xvel) + abs(act->yvel) + abs(act->zvel))) >> 6, 0)), 0); - } + if (hearDist) + { + DBloodActor* act = pPlayer->actor; + itCanHear = (!deaf && (nDist < hearDist || hearChance > 0)); + if (act && itCanHear && nDist < feelDist && (act->xvel || act->yvel || act->zvel)) + hearChance += ClipLow(mulscale8(1, ClipLow(((feelDist - nDist) + (abs(act->xvel) + abs(act->yvel) + abs(act->zvel))) >> 6, 0)), 0); + } - if (seeDist) - { - int periphery = ClipLow(pDudeInfo->periphery, kAng60); - int nDeltaAngle = abs(((getangle(dx, dy) + 1024 - actor->spr.ang) & 2047) - 1024); - if ((itCanSee = (!blind && nDist < seeDist && nDeltaAngle < periphery)) == true) - { - int base = 100 + ((20 * gGameOptions.nDifficulty) - (nDeltaAngle / 5)); - //seeChance = base - MulScale(ClipRange(5 - gGameOptions.nDifficulty, 1, 4), nDist >> 1, 16); - //scale(0x40000, a6, dist2); - int d = nDist >> 2; - int m = DivScale(d, 0x2000, 8); - int t = MulScale(d, m, 8); - //int n = mulscale8(nDeltaAngle >> 2, 64); - seeChance = ClipRange(DivScale(base, t, 8), 0, kMaxPatrolSpotValue >> 1); - //seeChance = scale(0x1000, base, t); - //viewSetSystemMessage("SEE CHANCE: %d, BASE %d, DIST %d, T %d", seeChance, base, nDist, t); - //itCanSee = false; - } - } + if (seeDist) + { + int periphery = ClipLow(pDudeInfo->periphery, kAng60); + int nDeltaAngle = abs(((getangle(dx, dy) + 1024 - actor->spr.ang) & 2047) - 1024); + if ((itCanSee = (!blind && nDist < seeDist && nDeltaAngle < periphery)) == true) + { + int base = 100 + ((20 * gGameOptions.nDifficulty) - (nDeltaAngle / 5)); + //seeChance = base - MulScale(ClipRange(5 - gGameOptions.nDifficulty, 1, 4), nDist >> 1, 16); + //scale(0x40000, a6, dist2); + int d = nDist >> 2; + int m = DivScale(d, 0x2000, 8); + int t = MulScale(d, m, 8); + //int n = mulscale8(nDeltaAngle >> 2, 64); + seeChance = ClipRange(DivScale(base, t, 8), 0, kMaxPatrolSpotValue >> 1); + //seeChance = scale(0x1000, base, t); + //viewSetSystemMessage("SEE CHANCE: %d, BASE %d, DIST %d, T %d", seeChance, base, nDist, t); + //itCanSee = false; + } + } - if (!itCanSee && !itCanHear) - continue; + if (!itCanSee && !itCanHear) + continue; - if (stealth) - { - // search in stealth regions to modify spot chances - BloodStatIterator it(kStatModernStealthRegion); - while (auto steal = it.Next()) - { - if (!steal->hasX()) - continue; + if (stealth) + { + // search in stealth regions to modify spot chances + BloodStatIterator it(kStatModernStealthRegion); + while (auto steal = it.Next()) + { + if (!steal->hasX()) + continue; - if (steal->xspr.locked) // ignore locked regions - continue; + if (steal->xspr.locked) // ignore locked regions + continue; - bool fixd = (steal->spr.flags & kModernTypeFlag1); // fixed percent value - bool both = (steal->spr.flags & kModernTypeFlag4); // target AND dude must be in this region - bool dude = (both || (steal->spr.flags & kModernTypeFlag2)); // dude must be in this region - bool trgt = (both || !dude); // target must be in this region - bool crouch = (steal->spr.flags & kModernTypeFlag8); // target must crouch - //bool floor = (iactor->spr.cstat & CSTAT_SPRITE_BLOCK); // target (or dude?) must touch floor of the sector - if (trgt) - { + bool fixd = (steal->spr.flags & kModernTypeFlag1); // fixed percent value + bool both = (steal->spr.flags & kModernTypeFlag4); // target AND dude must be in this region + bool dude = (both || (steal->spr.flags & kModernTypeFlag2)); // dude must be in this region + bool trgt = (both || !dude); // target must be in this region + bool crouch = (steal->spr.flags & kModernTypeFlag8); // target must crouch + //bool floor = (iactor->spr.cstat & CSTAT_SPRITE_BLOCK); // target (or dude?) must touch floor of the sector + if (trgt) + { - if (steal->xspr.data1 > 0) - { - if (approxDist(abs(steal->spr.pos.X - plActor->spr.pos.X) >> 4, abs(steal->spr.pos.Y - plActor->spr.pos.Y) >> 4) >= steal->xspr.data1) - continue; + if (steal->xspr.data1 > 0) + { + if (approxDist(abs(steal->spr.pos.X - plActor->spr.pos.X) >> 4, abs(steal->spr.pos.Y - plActor->spr.pos.Y) >> 4) >= steal->xspr.data1) + continue; - } - else if (plActor->spr.sector() != steal->spr.sector()) - continue; + } + else if (plActor->spr.sector() != steal->spr.sector()) + continue; - if (crouch && pPlayer->posture == kPostureStand) - continue; - } + if (crouch && pPlayer->posture == kPostureStand) + continue; + } - if (dude) - { - if (steal->xspr.data1 > 0) - { - if (approxDist(abs(steal->spr.pos.X - actor->spr.pos.X) >> 4, abs(steal->spr.pos.Y - actor->spr.pos.Y) >> 4) >= steal->xspr.data1) - continue; + if (dude) + { + if (steal->xspr.data1 > 0) + { + if (approxDist(abs(steal->spr.pos.X - actor->spr.pos.X) >> 4, abs(steal->spr.pos.Y - actor->spr.pos.Y) >> 4) >= steal->xspr.data1) + continue; - } - else if (plActor->spr.sector() != steal->spr.sector()) - continue; - } + } + else if (plActor->spr.sector() != steal->spr.sector()) + continue; + } - if (itCanHear) - { - if (fixd) - hearChance = ClipLow(hearChance, steal->xspr.data2); + if (itCanHear) + { + if (fixd) + hearChance = ClipLow(hearChance, steal->xspr.data2); - mod = (hearChance * steal->xspr.data2) / kPercFull; - if (fixd) hearChance = mod; else hearChance += mod; + mod = (hearChance * steal->xspr.data2) / kPercFull; + if (fixd) hearChance = mod; else hearChance += mod; - hearChance = ClipRange(hearChance, -kMaxPatrolSpotValue, kMaxPatrolSpotValue); - } + hearChance = ClipRange(hearChance, -kMaxPatrolSpotValue, kMaxPatrolSpotValue); + } - if (itCanSee) - { - if (fixd) - seeChance = ClipLow(seeChance, steal->xspr.data3); + if (itCanSee) + { + if (fixd) + seeChance = ClipLow(seeChance, steal->xspr.data3); - mod = (seeChance * steal->xspr.data3) / kPercFull; - if (fixd) seeChance = mod; else seeChance += mod; + mod = (seeChance * steal->xspr.data3) / kPercFull; + if (fixd) seeChance = mod; else seeChance += mod; - seeChance = ClipRange(seeChance, -kMaxPatrolSpotValue, kMaxPatrolSpotValue); - } + seeChance = ClipRange(seeChance, -kMaxPatrolSpotValue, kMaxPatrolSpotValue); + } - // trigger this region if target gonna be spot - if (steal->xspr.txID && actor->xspr.data3 + hearChance + seeChance >= kMaxPatrolSpotValue) - trTriggerSprite(steal, kCmdToggle); - - // continue search another stealth regions to affect chances - } - } + // trigger this region if target gonna be spot + if (steal->xspr.txID && actor->xspr.data3 + hearChance + seeChance >= kMaxPatrolSpotValue) + trTriggerSprite(steal, kCmdToggle); - if (itCanHear && hearChance > 0) - { - DPrintf(DMSG_SPAMMY, "Patrol dude #%d hearing the Player #%d.", actor->GetIndex(), pPlayer->nPlayer + 1); - actor->xspr.data3 = ClipRange(actor->xspr.data3 + hearChance, -kMaxPatrolSpotValue, kMaxPatrolSpotValue); - if (!stealth) - { - newtarget = pPlayer->actor; - break; - } - } + // continue search another stealth regions to affect chances + } + } - if (itCanSee && seeChance > 0) - { - //DPrintf(DMSG_SPAMMY, "Patrol dude #%d seeing the Player #%d.", actor->GetIndex(), pPlayer->nPlayer + 1); - //actor->xspr.data3 += seeChance; - actor->xspr.data3 = ClipRange(actor->xspr.data3 + seeChance, -kMaxPatrolSpotValue, kMaxPatrolSpotValue); - if (!stealth) - { - newtarget = pPlayer->actor; - break; - } - } - } + if (itCanHear && hearChance > 0) + { + DPrintf(DMSG_SPAMMY, "Patrol dude #%d hearing the Player #%d.", actor->GetIndex(), pPlayer->nPlayer + 1); + actor->xspr.data3 = ClipRange(actor->xspr.data3 + hearChance, -kMaxPatrolSpotValue, kMaxPatrolSpotValue); + if (!stealth) + { + newtarget = pPlayer->actor; + break; + } + } - // add check for corpses? + if (itCanSee && seeChance > 0) + { + //DPrintf(DMSG_SPAMMY, "Patrol dude #%d seeing the Player #%d.", actor->GetIndex(), pPlayer->nPlayer + 1); + //actor->xspr.data3 += seeChance; + actor->xspr.data3 = ClipRange(actor->xspr.data3 + seeChance, -kMaxPatrolSpotValue, kMaxPatrolSpotValue); + if (!stealth) + { + newtarget = pPlayer->actor; + break; + } + } + } - if ((actor->xspr.data3 = ClipRange(actor->xspr.data3, 0, kMaxPatrolSpotValue)) == kMaxPatrolSpotValue) - { - newtarget = pPlayer->actor; - break; - } + // add check for corpses? - //int perc = (100 * ClipHigh(actor->xspr.data3, kMaxPatrolSpotValue)) / kMaxPatrolSpotValue; - //viewSetSystemMessage("%d / %d / %d / %d", hearChance, seeDist, seeChance, perc); + if ((actor->xspr.data3 = ClipRange(actor->xspr.data3, 0, kMaxPatrolSpotValue)) == kMaxPatrolSpotValue) + { + newtarget = pPlayer->actor; + break; + } - } + //int perc = (100 * ClipHigh(actor->xspr.data3, kMaxPatrolSpotValue)) / kMaxPatrolSpotValue; + //viewSetSystemMessage("%d / %d / %d / %d", hearChance, seeDist, seeChance, perc); - if (newtarget) return newtarget; - actor->xspr.data3 -= ClipLow(((kPercFull * actor->xspr.data3) / kMaxPatrolSpotValue) >> 2, 3); - return nullptr; + } + + if (newtarget) return newtarget; + actor->xspr.data3 -= ClipLow(((kPercFull * actor->xspr.data3) / kMaxPatrolSpotValue) >> 2, 3); + return nullptr; } //--------------------------------------------------------------------------- @@ -8326,43 +8327,43 @@ DBloodActor* aiPatrolSearchTargets(DBloodActor* actor) // //--------------------------------------------------------------------------- -void aiPatrolFlagsMgr(DBloodActor* sourceactor, DBloodActor* destactor, bool copy, bool init) +void aiPatrolFlagsMgr(DBloodActor* sourceactor, DBloodActor* destactor, bool copy, bool init) { - // copy flags - if (copy) - { - destactor->xspr.dudeFlag4 = sourceactor->xspr.dudeFlag4; - destactor->xspr.dudeAmbush = sourceactor->xspr.dudeAmbush; - destactor->xspr.dudeGuard = sourceactor->xspr.dudeGuard; - destactor->xspr.dudeDeaf = sourceactor->xspr.dudeDeaf; - destactor->xspr.unused1 = sourceactor->xspr.unused1; + // copy flags + if (copy) + { + destactor->xspr.dudeFlag4 = sourceactor->xspr.dudeFlag4; + destactor->xspr.dudeAmbush = sourceactor->xspr.dudeAmbush; + destactor->xspr.dudeGuard = sourceactor->xspr.dudeGuard; + destactor->xspr.dudeDeaf = sourceactor->xspr.dudeDeaf; + destactor->xspr.unused1 = sourceactor->xspr.unused1; - if (sourceactor->xspr.unused1 & kDudeFlagStealth) destactor->xspr.unused1 |= kDudeFlagStealth; - else destactor->xspr.unused1 &= ~kDudeFlagStealth; - } + if (sourceactor->xspr.unused1 & kDudeFlagStealth) destactor->xspr.unused1 |= kDudeFlagStealth; + else destactor->xspr.unused1 &= ~kDudeFlagStealth; + } - // do init - if (init) - { - if (!destactor->xspr.dudeFlag4) - { - if (aiInPatrolState(destactor->xspr.aiState)) - aiPatrolStop(destactor, nullptr); - } - else - { - if (aiInPatrolState(destactor->xspr.aiState)) - return; - - destactor->SetTarget(nullptr); - destactor->xspr.stateTimer = 0; - - aiPatrolSetMarker(destactor); - if (spriteIsUnderwater(destactor)) aiPatrolState(destactor, kAiStatePatrolWaitW); - else aiPatrolState(destactor, kAiStatePatrolWaitL); - destactor->xspr.data3 = 0; // reset the spot progress - } - } + // do init + if (init) + { + if (!destactor->xspr.dudeFlag4) + { + if (aiInPatrolState(destactor->xspr.aiState)) + aiPatrolStop(destactor, nullptr); + } + else + { + if (aiInPatrolState(destactor->xspr.aiState)) + return; + + destactor->SetTarget(nullptr); + destactor->xspr.stateTimer = 0; + + aiPatrolSetMarker(destactor); + if (spriteIsUnderwater(destactor)) aiPatrolState(destactor, kAiStatePatrolWaitW); + else aiPatrolState(destactor, kAiStatePatrolWaitL); + destactor->xspr.data3 = 0; // reset the spot progress + } + } } //--------------------------------------------------------------------------- @@ -8371,10 +8372,10 @@ void aiPatrolFlagsMgr(DBloodActor* sourceactor, DBloodActor* destactor, bool cop // //--------------------------------------------------------------------------- -bool aiPatrolGetPathDir(DBloodActor* actor, DBloodActor* marker) +bool aiPatrolGetPathDir(DBloodActor* actor, DBloodActor* marker) { - if (actor->xspr.unused2 == kPatrolMoveForward) return (marker->xspr.data2 == -2) ? (bool)kPatrolMoveBackward : (bool)kPatrolMoveForward; - else return (findNextMarker(marker, kPatrolMoveBackward) != nullptr) ? (bool)kPatrolMoveBackward : (bool)kPatrolMoveForward; + if (actor->xspr.unused2 == kPatrolMoveForward) return (marker->xspr.data2 == -2) ? (bool)kPatrolMoveBackward : (bool)kPatrolMoveForward; + else return (findNextMarker(marker, kPatrolMoveBackward) != nullptr) ? (bool)kPatrolMoveBackward : (bool)kPatrolMoveForward; } //--------------------------------------------------------------------------- @@ -8385,202 +8386,203 @@ bool aiPatrolGetPathDir(DBloodActor* actor, DBloodActor* marker) void aiPatrolThink(DBloodActor* actor) { - assert(actor->spr.type >= kDudeBase && actor->spr.type < kDudeMax); + assert(actor->spr.type >= kDudeBase && actor->spr.type < kDudeMax); - DBloodActor* targetactor; - int stateTimer; - auto markeractor = actor->GetTarget(); - if ((targetactor = aiPatrolSearchTargets(actor)) != nullptr) - { - aiPatrolStop(actor, targetactor, actor->xspr.dudeAmbush); - return; - } + DBloodActor* targetactor; + int stateTimer; + auto markeractor = actor->GetTarget(); + if ((targetactor = aiPatrolSearchTargets(actor)) != nullptr) + { + aiPatrolStop(actor, targetactor, actor->xspr.dudeAmbush); + return; + } - - bool crouch = (actor->xspr.unused1 & kDudeFlagCrouch), uwater = spriteIsUnderwater(actor); - if (markeractor == nullptr || (actor->spr.type == kDudeModernCustom && ((uwater && !canSwim(actor)) || !canWalk(actor)))) - { - aiPatrolStop(actor, nullptr); - return; - } - - const DUDEINFO_EXTRA* pExtra = &gDudeInfoExtra[actor->spr.type - kDudeBase]; - bool isFinal = ((!actor->xspr.unused2 && markeractor->xspr.data2 == -1) || (actor->xspr.unused2 && markeractor->xspr.data1 == -1)); - bool reached = false; - - if (aiPatrolWaiting(actor->xspr.aiState)) - { - //viewSetSystemMessage("WAIT %d / %d", actor->xspr.targetY, actor->xspr.stateTimer); - - if (actor->xspr.stateTimer > 0 || markeractor->xspr.data1 == markeractor->xspr.data2) - { - if (pExtra->flying) - actor->zvel = Random2(0x8000); - // turn while waiting - if (markeractor->spr.flags & kModernTypeFlag16) - { - stateTimer = actor->xspr.stateTimer; - - if (--actor->xspr.unused4 <= 0) - { - if (uwater) aiPatrolState(actor, kAiStatePatrolTurnW); - else if (crouch) aiPatrolState(actor, kAiStatePatrolTurnC); - else aiPatrolState(actor, kAiStatePatrolTurnL); - actor->xspr.unused4 = kMinPatrolTurnDelay + Random(kPatrolTurnDelayRange); - } + bool crouch = (actor->xspr.unused1 & kDudeFlagCrouch), uwater = spriteIsUnderwater(actor); + if (markeractor == nullptr || (actor->spr.type == kDudeModernCustom && ((uwater && !canSwim(actor)) || !canWalk(actor)))) + { + aiPatrolStop(actor, nullptr); + return; + } - // must restore stateTimer for waiting - actor->xspr.stateTimer = stateTimer; - } - return; - } + const DUDEINFO_EXTRA* pExtra = &gDudeInfoExtra[actor->spr.type - kDudeBase]; + bool isFinal = ((!actor->xspr.unused2 && markeractor->xspr.data2 == -1) || (actor->xspr.unused2 && markeractor->xspr.data1 == -1)); + bool reached = false; - // trigger at departure - if (markeractor->xspr.triggerOff) - { - // send command - if (markeractor->xspr.txID) - { - evSendActor(markeractor, markeractor->xspr.txID, (COMMAND_ID)markeractor->xspr.command); + if (aiPatrolWaiting(actor->xspr.aiState)) + { + //viewSetSystemMessage("WAIT %d / %d", actor->xspr.targetY, actor->xspr.stateTimer); - // copy dude flags for current dude - } - else if (markeractor->xspr.command == kCmdDudeFlagsSet) - { - aiPatrolFlagsMgr(markeractor, actor, true, true); - if (!actor->xspr.dudeFlag4) // this dude is not in patrol anymore - return; - } - } + if (actor->xspr.stateTimer > 0 || markeractor->xspr.data1 == markeractor->xspr.data2) + { + if (pExtra->flying) + actor->zvel = Random2(0x8000); - // release the enemy - if (isFinal) - { - aiPatrolStop(actor, nullptr); - return; - } + // turn while waiting + if (markeractor->spr.flags & kModernTypeFlag16) + { + stateTimer = actor->xspr.stateTimer; - // move next marker - aiPatrolSetMarker(actor); + if (--actor->xspr.unused4 <= 0) + { + if (uwater) aiPatrolState(actor, kAiStatePatrolTurnW); + else if (crouch) aiPatrolState(actor, kAiStatePatrolTurnC); + else aiPatrolState(actor, kAiStatePatrolTurnL); + actor->xspr.unused4 = kMinPatrolTurnDelay + Random(kPatrolTurnDelayRange); + } - } else if (aiPatrolTurning(actor->xspr.aiState)) - { - //viewSetSystemMessage("TURN"); - if ((int)actor->spr.ang == (int)actor->xspr.goalAng) - { - // save imer for waiting - stateTimer = actor->xspr.stateTimer; - - if (uwater) aiPatrolState(actor, kAiStatePatrolWaitW); - else if (crouch) aiPatrolState(actor, kAiStatePatrolWaitC); - else aiPatrolState(actor, kAiStatePatrolWaitL); - - // must restore it - actor->xspr.stateTimer = stateTimer; - } - return; + // must restore stateTimer for waiting + actor->xspr.stateTimer = stateTimer; + } + return; + } - } - else if ((reached = aiPatrolMarkerReached(actor)) == true) - { - markeractor->xspr.isTriggered = markeractor->xspr.triggerOnce; // can't select this marker for path anymore if true + // trigger at departure + if (markeractor->xspr.triggerOff) + { + // send command + if (markeractor->xspr.txID) + { + evSendActor(markeractor, markeractor->xspr.txID, (COMMAND_ID)markeractor->xspr.command); - if (markeractor->spr.flags > 0) - { - if ((markeractor->spr.flags & kModernTypeFlag2) && (markeractor->spr.flags & kModernTypeFlag1)) crouch = !crouch; - else if (markeractor->spr.flags & kModernTypeFlag2) crouch = false; - else if ((markeractor->spr.flags & kModernTypeFlag1) && aiCanCrouch(actor)) crouch = true; - } + // copy dude flags for current dude + } + else if (markeractor->xspr.command == kCmdDudeFlagsSet) + { + aiPatrolFlagsMgr(markeractor, actor, true, true); + if (!actor->xspr.dudeFlag4) // this dude is not in patrol anymore + return; + } + } - if (markeractor->xspr.waitTime > 0 || markeractor->xspr.data1 == markeractor->xspr.data2) - { - // take marker's angle - if (!(markeractor->spr.flags & kModernTypeFlag4)) - { - actor->xspr.goalAng = ((!(markeractor->spr.flags & kModernTypeFlag8) && actor->xspr.unused2) ? markeractor->spr.ang + kAng180 : markeractor->spr.ang) & 2047; - if ((int)actor->spr.ang != (int)actor->xspr.goalAng) // let the enemy play move animation while turning - return; - } + // release the enemy + if (isFinal) + { + aiPatrolStop(actor, nullptr); + return; + } - if (markeractor->GetOwner() == actor) - markeractor->SetOwner(aiPatrolMarkerBusy(actor, markeractor)); + // move next marker + aiPatrolSetMarker(actor); - // trigger at arrival - if (markeractor->xspr.triggerOn) - { - // send command - if (markeractor->xspr.txID) - { - evSendActor(markeractor, markeractor->xspr.txID, (COMMAND_ID)markeractor->xspr.command); - } - else if (markeractor->xspr.command == kCmdDudeFlagsSet) - { - // copy dude flags for current dude - aiPatrolFlagsMgr(markeractor, actor, true, true); - if (!actor->xspr.dudeFlag4) // this dude is not in patrol anymore - return; - } - } + } + else if (aiPatrolTurning(actor->xspr.aiState)) + { + //viewSetSystemMessage("TURN"); + if ((int)actor->spr.ang == (int)actor->xspr.goalAng) + { + // save imer for waiting + stateTimer = actor->xspr.stateTimer; - if (uwater) aiPatrolState(actor, kAiStatePatrolWaitW); - else if (crouch) aiPatrolState(actor, kAiStatePatrolWaitC); - else aiPatrolState(actor, kAiStatePatrolWaitL); + if (uwater) aiPatrolState(actor, kAiStatePatrolWaitW); + else if (crouch) aiPatrolState(actor, kAiStatePatrolWaitC); + else aiPatrolState(actor, kAiStatePatrolWaitL); - if (markeractor->xspr.waitTime) - actor->xspr.stateTimer = (markeractor->xspr.waitTime * 120) / 10; + // must restore it + actor->xspr.stateTimer = stateTimer; + } + return; - if (markeractor->spr.flags & kModernTypeFlag16) - actor->xspr.unused4 = kMinPatrolTurnDelay + Random(kPatrolTurnDelayRange); + } + else if ((reached = aiPatrolMarkerReached(actor)) == true) + { + markeractor->xspr.isTriggered = markeractor->xspr.triggerOnce; // can't select this marker for path anymore if true - return; - } - else - { - if (markeractor->GetOwner() == actor) - markeractor->SetOwner(aiPatrolMarkerBusy(actor, markeractor)); + if (markeractor->spr.flags > 0) + { + if ((markeractor->spr.flags & kModernTypeFlag2) && (markeractor->spr.flags & kModernTypeFlag1)) crouch = !crouch; + else if (markeractor->spr.flags & kModernTypeFlag2) crouch = false; + else if ((markeractor->spr.flags & kModernTypeFlag1) && aiCanCrouch(actor)) crouch = true; + } - if (markeractor->xspr.triggerOn || markeractor->xspr.triggerOff) - { - if (markeractor->xspr.txID) - { - // send command at arrival - if (markeractor->xspr.triggerOn) - evSendActor(markeractor, markeractor->xspr.txID, (COMMAND_ID)markeractor->xspr.command); + if (markeractor->xspr.waitTime > 0 || markeractor->xspr.data1 == markeractor->xspr.data2) + { + // take marker's angle + if (!(markeractor->spr.flags & kModernTypeFlag4)) + { + actor->xspr.goalAng = ((!(markeractor->spr.flags & kModernTypeFlag8) && actor->xspr.unused2) ? markeractor->spr.ang + kAng180 : markeractor->spr.ang) & 2047; + if ((int)actor->spr.ang != (int)actor->xspr.goalAng) // let the enemy play move animation while turning + return; + } - // send command at departure - if (markeractor->xspr.triggerOff) - evSendActor(markeractor, markeractor->xspr.txID, (COMMAND_ID)markeractor->xspr.command); + if (markeractor->GetOwner() == actor) + markeractor->SetOwner(aiPatrolMarkerBusy(actor, markeractor)); - // copy dude flags for current dude - } - else if (markeractor->xspr.command == kCmdDudeFlagsSet) - { - aiPatrolFlagsMgr(markeractor, actor, true, true); - if (!actor->xspr.dudeFlag4) // this dude is not in patrol anymore - return; - } - } + // trigger at arrival + if (markeractor->xspr.triggerOn) + { + // send command + if (markeractor->xspr.txID) + { + evSendActor(markeractor, markeractor->xspr.txID, (COMMAND_ID)markeractor->xspr.command); + } + else if (markeractor->xspr.command == kCmdDudeFlagsSet) + { + // copy dude flags for current dude + aiPatrolFlagsMgr(markeractor, actor, true, true); + if (!actor->xspr.dudeFlag4) // this dude is not in patrol anymore + return; + } + } - // release the enemy - if (isFinal) - { - aiPatrolStop(actor, nullptr); - return; - } + if (uwater) aiPatrolState(actor, kAiStatePatrolWaitW); + else if (crouch) aiPatrolState(actor, kAiStatePatrolWaitC); + else aiPatrolState(actor, kAiStatePatrolWaitL); - // move the next marker - aiPatrolSetMarker(actor); - } - } - - nnExtAiSetDirection(actor, getangle(markeractor->spr.pos.X - actor->spr.pos.X, markeractor->spr.pos.Y - actor->spr.pos.Y)); + if (markeractor->xspr.waitTime) + actor->xspr.stateTimer = (markeractor->xspr.waitTime * 120) / 10; - if (aiPatrolMoving(actor->xspr.aiState) && !reached) return; - else if (uwater) aiPatrolState(actor, kAiStatePatrolMoveW); - else if (crouch) aiPatrolState(actor, kAiStatePatrolMoveC); - else aiPatrolState(actor, kAiStatePatrolMoveL); - return; + if (markeractor->spr.flags & kModernTypeFlag16) + actor->xspr.unused4 = kMinPatrolTurnDelay + Random(kPatrolTurnDelayRange); + + return; + } + else + { + if (markeractor->GetOwner() == actor) + markeractor->SetOwner(aiPatrolMarkerBusy(actor, markeractor)); + + if (markeractor->xspr.triggerOn || markeractor->xspr.triggerOff) + { + if (markeractor->xspr.txID) + { + // send command at arrival + if (markeractor->xspr.triggerOn) + evSendActor(markeractor, markeractor->xspr.txID, (COMMAND_ID)markeractor->xspr.command); + + // send command at departure + if (markeractor->xspr.triggerOff) + evSendActor(markeractor, markeractor->xspr.txID, (COMMAND_ID)markeractor->xspr.command); + + // copy dude flags for current dude + } + else if (markeractor->xspr.command == kCmdDudeFlagsSet) + { + aiPatrolFlagsMgr(markeractor, actor, true, true); + if (!actor->xspr.dudeFlag4) // this dude is not in patrol anymore + return; + } + } + + // release the enemy + if (isFinal) + { + aiPatrolStop(actor, nullptr); + return; + } + + // move the next marker + aiPatrolSetMarker(actor); + } + } + + nnExtAiSetDirection(actor, getangle(markeractor->spr.pos.X - actor->spr.pos.X, markeractor->spr.pos.Y - actor->spr.pos.Y)); + + if (aiPatrolMoving(actor->xspr.aiState) && !reached) return; + else if (uwater) aiPatrolState(actor, kAiStatePatrolMoveW); + else if (crouch) aiPatrolState(actor, kAiStatePatrolMoveC); + else aiPatrolState(actor, kAiStatePatrolMoveL); + return; } @@ -8590,38 +8592,38 @@ void aiPatrolThink(DBloodActor* actor) // //--------------------------------------------------------------------------- -int listTx(DBloodActor* actor, int tx) +int listTx(DBloodActor* actor, int tx) { - if (txIsRanged(actor)) - { - if (tx == -1) tx = actor->xspr.data1; - else if (tx < actor->xspr.data4) tx++; - else tx = -1; - } - else - { - if (tx == -1) - { - for (int i = 0; i <= 3; i++) - { - if ((tx = GetDataVal(actor, i)) <= 0) continue; - else return tx; - } - } - else - { - int saved = tx; bool savedFound = false; - for (int i = 0; i <= 3; i++) - { - tx = GetDataVal(actor, i); - if (savedFound && tx > 0) return tx; - else if (tx != saved) continue; - else savedFound = true; - } - } - tx = -1; - } - return tx; + if (txIsRanged(actor)) + { + if (tx == -1) tx = actor->xspr.data1; + else if (tx < actor->xspr.data4) tx++; + else tx = -1; + } + else + { + if (tx == -1) + { + for (int i = 0; i <= 3; i++) + { + if ((tx = GetDataVal(actor, i)) <= 0) continue; + else return tx; + } + } + else + { + int saved = tx; bool savedFound = false; + for (int i = 0; i <= 3; i++) + { + tx = GetDataVal(actor, i); + if (savedFound && tx > 0) return tx; + else if (tx != saved) continue; + else savedFound = true; + } + } + tx = -1; + } + return tx; } //--------------------------------------------------------------------------- @@ -8630,20 +8632,20 @@ int listTx(DBloodActor* actor, int tx) // //--------------------------------------------------------------------------- -DBloodActor* evrIsRedirector(DBloodActor* actor) +DBloodActor* evrIsRedirector(DBloodActor* actor) { - if (actor) - { - switch (actor->spr.type) - { - case kModernRandomTX: - case kModernSequentialTX: - if (actor->hasX() && actor->xspr.command == kCmdLink && !actor->xspr.locked) return actor; - break; - } - } + if (actor) + { + switch (actor->spr.type) + { + case kModernRandomTX: + case kModernSequentialTX: + if (actor->hasX() && actor->xspr.command == kCmdLink && !actor->xspr.locked) return actor; + break; + } + } - return nullptr; + return nullptr; } //--------------------------------------------------------------------------- @@ -8652,54 +8654,54 @@ DBloodActor* evrIsRedirector(DBloodActor* actor) // //--------------------------------------------------------------------------- -DBloodActor* evrListRedirectors(int objType, sectortype* pSector, walltype* pWall, DBloodActor* objActor, DBloodActor* pXRedir, int* tx) +DBloodActor* evrListRedirectors(int objType, sectortype* pSector, walltype* pWall, DBloodActor* objActor, DBloodActor* pXRedir, int* tx) { - if (!gEventRedirectsUsed) return nullptr; - else if (pXRedir && (*tx = listTx(pXRedir, *tx)) != -1) - return pXRedir; + if (!gEventRedirectsUsed) return nullptr; + else if (pXRedir && (*tx = listTx(pXRedir, *tx)) != -1) + return pXRedir; - int id = 0; - switch (objType) - { - case OBJ_SECTOR: - { - if (!pSector->hasX()) return nullptr; - id = pSector->xs().txID; - break; - } - case OBJ_SPRITE: - if (!objActor) return nullptr; - id = objActor->xspr.txID; - break; - case OBJ_WALL: - { - if (!pWall->hasX()) return nullptr; - id = pWall->xw().txID; - break; - } - default: - return nullptr; - } + int id = 0; + switch (objType) + { + case OBJ_SECTOR: + { + if (!pSector->hasX()) return nullptr; + id = pSector->xs().txID; + break; + } + case OBJ_SPRITE: + if (!objActor) return nullptr; + id = objActor->xspr.txID; + break; + case OBJ_WALL: + { + if (!pWall->hasX()) return nullptr; + id = pWall->xw().txID; + break; + } + default: + return nullptr; + } - bool prevFound = false; - for (int i = bucketHead[id]; i < bucketHead[id + 1]; i++) - { - if (!rxBucket[i].isActor()) continue; - auto rxactor = rxBucket[i].actor(); + bool prevFound = false; + for (int i = bucketHead[id]; i < bucketHead[id + 1]; i++) + { + if (!rxBucket[i].isActor()) continue; + auto rxactor = rxBucket[i].actor(); - auto pXSpr = evrIsRedirector(rxactor); - if (!pXSpr) continue; - else if (prevFound || pXRedir == nullptr) - { - *tx = listTx(pXSpr, *tx); - return pXSpr; - } - else if (pXRedir != pXSpr) continue; - else prevFound = true; - } + auto pXSpr = evrIsRedirector(rxactor); + if (!pXSpr) continue; + else if (prevFound || pXRedir == nullptr) + { + *tx = listTx(pXSpr, *tx); + return pXSpr; + } + else if (pXRedir != pXSpr) continue; + else prevFound = true; + } - *tx = -1; - return NULL; + *tx = -1; + return NULL; } //--------------------------------------------------------------------------- @@ -8708,41 +8710,41 @@ DBloodActor* evrListRedirectors(int objType, sectortype* pSector, walltype* pWal // //--------------------------------------------------------------------------- -bool incDecGoalValueIsReached(DBloodActor* actor) +bool incDecGoalValueIsReached(DBloodActor* actor) { - if (actor->xspr.data3 != actor->xspr.sysData1) return false; - char buffer[7]; - snprintf(buffer, 7, "%d", abs(actor->xspr.data1)); - int len = int(strlen(buffer)); - int rx = -1; + if (actor->xspr.data3 != actor->xspr.sysData1) return false; + char buffer[7]; + snprintf(buffer, 7, "%d", abs(actor->xspr.data1)); + int len = int(strlen(buffer)); + int rx = -1; - for (int i = bucketHead[actor->xspr.txID]; i < bucketHead[actor->xspr.txID + 1]; i++) - { - if (!rxBucket[i].isActor()) continue; - auto rxactor = rxBucket[i].actor(); + for (int i = bucketHead[actor->xspr.txID]; i < bucketHead[actor->xspr.txID + 1]; i++) + { + if (!rxBucket[i].isActor()) continue; + auto rxactor = rxBucket[i].actor(); - if (evrIsRedirector(rxactor)) continue; - for (int a = 0; a < len; a++) - { - if (getDataFieldOfObject(rxBucket[i], (buffer[a] - 52) + 4) != actor->xspr.data3) - return false; - } - } + if (evrIsRedirector(rxactor)) continue; + for (int a = 0; a < len; a++) + { + if (getDataFieldOfObject(rxBucket[i], (buffer[a] - 52) + 4) != actor->xspr.data3) + return false; + } + } - DBloodActor* pXRedir = nullptr; // check redirected TX buckets - while ((pXRedir = evrListRedirectors(OBJ_SPRITE, nullptr, nullptr, actor, pXRedir, &rx)) != nullptr) - { - for (int i = bucketHead[rx]; i < bucketHead[rx + 1]; i++) - { - for (int a = 0; a < len; a++) - { - if (getDataFieldOfObject(rxBucket[i], (buffer[a] - 52) + 4) != actor->xspr.data3) - return false; - } - } - } - - return true; + DBloodActor* pXRedir = nullptr; // check redirected TX buckets + while ((pXRedir = evrListRedirectors(OBJ_SPRITE, nullptr, nullptr, actor, pXRedir, &rx)) != nullptr) + { + for (int i = bucketHead[rx]; i < bucketHead[rx + 1]; i++) + { + for (int a = 0; a < len; a++) + { + if (getDataFieldOfObject(rxBucket[i], (buffer[a] - 52) + 4) != actor->xspr.data3) + return false; + } + } + } + + return true; } //--------------------------------------------------------------------------- @@ -8751,18 +8753,18 @@ bool incDecGoalValueIsReached(DBloodActor* actor) // //--------------------------------------------------------------------------- -void seqSpawnerOffSameTx(DBloodActor* actor) +void seqSpawnerOffSameTx(DBloodActor* actor) { - BloodSpriteIterator it; - while (auto iactor = it.Next()) - { - if (iactor->spr.type != kModernSeqSpawner || !iactor->hasX() || iactor == actor) continue; - if (iactor->xspr.txID == actor->xspr.txID && iactor->xspr.state == 1) - { - evKillActor(iactor); - iactor->xspr.state = 0; - } - } + BloodSpriteIterator it; + while (auto iactor = it.Next()) + { + if (iactor->spr.type != kModernSeqSpawner || !iactor->hasX() || iactor == actor) continue; + if (iactor->xspr.txID == actor->xspr.txID && iactor->xspr.state == 1) + { + evKillActor(iactor); + iactor->xspr.state = 0; + } + } } //--------------------------------------------------------------------------- @@ -8772,10 +8774,10 @@ void seqSpawnerOffSameTx(DBloodActor* actor) // //--------------------------------------------------------------------------- -void levelEndLevelCustom(int nLevel) +void levelEndLevelCustom(int nLevel) { - gGameOptions.uGameFlags |= GF_AdvanceLevel; - gNextLevel = FindMapByIndex(currentLevel->cluster, nLevel + 1); + gGameOptions.uGameFlags |= GF_AdvanceLevel; + gNextLevel = FindMapByIndex(currentLevel->cluster, nLevel + 1); } //--------------------------------------------------------------------------- @@ -8786,54 +8788,54 @@ void levelEndLevelCustom(int nLevel) void callbackUniMissileBurst(DBloodActor* actor, sectortype*) // 22 { - if (!actor) return; - if (actor->spr.statnum != kStatProjectile) return; - int nAngle = getangle(actor->xvel, actor->yvel); - int nRadius = 0x55555; + if (!actor) return; + if (actor->spr.statnum != kStatProjectile) return; + int nAngle = getangle(actor->xvel, actor->yvel); + int nRadius = 0x55555; - for (int i = 0; i < 8; i++) - { - auto burstactor = actSpawnSprite(actor, 5); - if (!burstactor) break; + for (int i = 0; i < 8; i++) + { + auto burstactor = actSpawnSprite(actor, 5); + if (!burstactor) break; - burstactor->spr.type = actor->spr.type; - burstactor->spr.shade = actor->spr.shade; - burstactor->spr.picnum = actor->spr.picnum; + burstactor->spr.type = actor->spr.type; + burstactor->spr.shade = actor->spr.shade; + burstactor->spr.picnum = actor->spr.picnum; - - burstactor->spr.cstat = actor->spr.cstat; - if ((burstactor->spr.cstat & CSTAT_SPRITE_BLOCK)) - { - burstactor->spr.cstat &= ~CSTAT_SPRITE_BLOCK; // we don't want missiles impact each other - evPostActor(burstactor, 100, kCallbackMissileSpriteBlock); // so set blocking flag a bit later - } - burstactor->spr.pal = actor->spr.pal; - burstactor->spr.clipdist = actor->spr.clipdist / 4; - burstactor->spr.flags = actor->spr.flags; - burstactor->spr.xrepeat = actor->spr.xrepeat / 2; - burstactor->spr.yrepeat = actor->spr.yrepeat / 2; - burstactor->spr.ang = ((actor->spr.ang + missileInfo[actor->spr.type - kMissileBase].angleOfs) & 2047); - burstactor->SetOwner(actor); + burstactor->spr.cstat = actor->spr.cstat; + if ((burstactor->spr.cstat & CSTAT_SPRITE_BLOCK)) + { + burstactor->spr.cstat &= ~CSTAT_SPRITE_BLOCK; // we don't want missiles impact each other + evPostActor(burstactor, 100, kCallbackMissileSpriteBlock); // so set blocking flag a bit later + } - actBuildMissile(burstactor, actor); + burstactor->spr.pal = actor->spr.pal; + burstactor->spr.clipdist = actor->spr.clipdist / 4; + burstactor->spr.flags = actor->spr.flags; + burstactor->spr.xrepeat = actor->spr.xrepeat / 2; + burstactor->spr.yrepeat = actor->spr.yrepeat / 2; + burstactor->spr.ang = ((actor->spr.ang + missileInfo[actor->spr.type - kMissileBase].angleOfs) & 2047); + burstactor->SetOwner(actor); - int nAngle2 = (i << 11) / 8; - int dx = 0; - int dy = mulscale30r(nRadius, Sin(nAngle2)); - int dz = mulscale30r(nRadius, -Cos(nAngle2)); - if (i & 1) - { - dy >>= 1; - dz >>= 1; - } - RotateVector(&dx, &dy, nAngle); - burstactor->xvel += dx; - burstactor->yvel += dy; - burstactor->zvel += dz; - evPostActor(burstactor, 960, kCallbackRemove); - } - evPostActor(actor, 0, kCallbackRemove); + actBuildMissile(burstactor, actor); + + int nAngle2 = (i << 11) / 8; + int dx = 0; + int dy = mulscale30r(nRadius, Sin(nAngle2)); + int dz = mulscale30r(nRadius, -Cos(nAngle2)); + if (i & 1) + { + dy >>= 1; + dz >>= 1; + } + RotateVector(&dx, &dy, nAngle); + burstactor->xvel += dx; + burstactor->yvel += dy; + burstactor->zvel += dz; + evPostActor(burstactor, 960, kCallbackRemove); + } + evPostActor(actor, 0, kCallbackRemove); } @@ -8845,28 +8847,28 @@ void callbackUniMissileBurst(DBloodActor* actor, sectortype*) // 22 void callbackMakeMissileBlocking(DBloodActor* actor, sectortype*) // 23 { - if (!actor || actor->spr.statnum != kStatProjectile) return; - actor->spr.cstat |= CSTAT_SPRITE_BLOCK; + if (!actor || actor->spr.statnum != kStatProjectile) return; + actor->spr.cstat |= CSTAT_SPRITE_BLOCK; } void callbackGenDudeUpdate(DBloodActor* actor, sectortype*) // 24 { - if (actor) - genDudeUpdate(actor); + if (actor) + genDudeUpdate(actor); } -void clampSprite(DBloodActor* actor, int which) +void clampSprite(DBloodActor* actor, int which) { - int zTop, zBot; - if (actor->spr.insector()) - { - GetActorExtents(actor, &zTop, &zBot); - if (which & 0x01) - actor->spr.pos.Z += ClipHigh(getflorzofslopeptr(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y) - zBot, 0); - if (which & 0x02) - actor->spr.pos.Z += ClipLow(getceilzofslopeptr(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y) - zTop, 0); + int zTop, zBot; + if (actor->spr.insector()) + { + GetActorExtents(actor, &zTop, &zBot); + if (which & 0x01) + actor->spr.pos.Z += ClipHigh(getflorzofslopeptr(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y) - zBot, 0); + if (which & 0x02) + actor->spr.pos.Z += ClipLow(getceilzofslopeptr(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y) - zTop, 0); - } + } } @@ -8878,90 +8880,90 @@ void clampSprite(DBloodActor* actor, int which) FSerializer& Serialize(FSerializer& arc, const char* keyname, GENDUDEEXTRA& w, GENDUDEEXTRA* def) { - if (arc.BeginObject(keyname)) - { - arc.Array("initvals", w.initVals, 3) - .Array("availdeaths", w.availDeaths, kDamageMax) - ("movespeed", w.moveSpeed) - ("firedist", w.fireDist) - ("throwdist", w.throwDist) - ("curweapon", w.curWeapon) - ("weapontype", w.weaponType) - ("basedispersion", w.baseDispersion) - ("slavecount", w.slaveCount) - ("lifeleech", w.pLifeLeech) - .Array("slaves", w.slave, w.slaveCount) - .Array("dmgcontrol", w.dmgControl, kDamageMax) - .Array("updreq", w.updReq, kGenDudePropertyMax) - ("flags", w.flags) - .EndObject(); - } - return arc; + if (arc.BeginObject(keyname)) + { + arc.Array("initvals", w.initVals, 3) + .Array("availdeaths", w.availDeaths, kDamageMax) + ("movespeed", w.moveSpeed) + ("firedist", w.fireDist) + ("throwdist", w.throwDist) + ("curweapon", w.curWeapon) + ("weapontype", w.weaponType) + ("basedispersion", w.baseDispersion) + ("slavecount", w.slaveCount) + ("lifeleech", w.pLifeLeech) + .Array("slaves", w.slave, w.slaveCount) + .Array("dmgcontrol", w.dmgControl, kDamageMax) + .Array("updreq", w.updReq, kGenDudePropertyMax) + ("flags", w.flags) + .EndObject(); + } + return arc; } FSerializer& Serialize(FSerializer& arc, const char* keyname, SPRITEMASS& w, SPRITEMASS* def) { - static SPRITEMASS nul; - if (arc.isReading()) w = {}; - if (arc.BeginObject(keyname)) - { - arc ("seq", w.seqId, &nul.seqId) - ("picnum", w.picnum, &nul.picnum) - ("xrepeat", w.xrepeat, &nul.xrepeat) - ("yrepeat", w.yrepeat, &nul.yrepeat) - ("clipdist", w.clipdist) - ("mass", w.mass) - ("airvel", w.airVel) - ("fraction", w.fraction) - .EndObject(); - } - return arc; + static SPRITEMASS nul; + if (arc.isReading()) w = {}; + if (arc.BeginObject(keyname)) + { + arc("seq", w.seqId, &nul.seqId) + ("picnum", w.picnum, &nul.picnum) + ("xrepeat", w.xrepeat, &nul.xrepeat) + ("yrepeat", w.yrepeat, &nul.yrepeat) + ("clipdist", w.clipdist) + ("mass", w.mass) + ("airvel", w.airVel) + ("fraction", w.fraction) + .EndObject(); + } + 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("obj", w.obj, &nul.obj) - ("cmd", w.cmd, &nul.cmd) - .EndObject(); - } - return arc; + static OBJECTS_TO_TRACK nul; + if (arc.isReading()) w = {}; + if (arc.BeginObject(keyname)) + { + arc("obj", w.obj, &nul.obj) + ("cmd", 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.actor, &nul.actor) - .Array("obj", w.obj, w.length) - .EndObject(); - } - return arc; + static TRCONDITION nul; + if (arc.isReading()) w = {}; + if (arc.BeginObject(keyname)) + { + arc("length", w.length, &nul.length) + ("xindex", w.actor, &nul.actor) + .Array("obj", w.obj, w.length) + .EndObject(); + } + return arc; } void SerializeNNExts(FSerializer& arc) { - if (arc.BeginObject("nnexts")) - { - arc ("proxyspritescount", gProxySpritesCount) - .Array("proxyspriteslist", gProxySpritesList, gProxySpritesCount) - ("sightspritescount", gSightSpritesCount) - .Array("sightspriteslist", gSightSpritesList, gSightSpritesCount) - ("physspritescount", gPhysSpritesCount) - .Array("physspriteslist", gPhysSpritesList, gPhysSpritesCount) - ("impactspritescount", gImpactSpritesCount) - .Array("impactspriteslist", gImpactSpritesList, gImpactSpritesCount) - ("eventredirects", gEventRedirectsUsed) - ("trconditioncount", gTrackingCondsCount) - .Array("trcondition", gCondition, gTrackingCondsCount) - .EndObject(); - } + if (arc.BeginObject("nnexts")) + { + arc("proxyspritescount", gProxySpritesCount) + .Array("proxyspriteslist", gProxySpritesList, gProxySpritesCount) + ("sightspritescount", gSightSpritesCount) + .Array("sightspriteslist", gSightSpritesList, gSightSpritesCount) + ("physspritescount", gPhysSpritesCount) + .Array("physspriteslist", gPhysSpritesList, gPhysSpritesCount) + ("impactspritescount", gImpactSpritesCount) + .Array("impactspriteslist", gImpactSpritesList, gImpactSpritesCount) + ("eventredirects", gEventRedirectsUsed) + ("trconditioncount", gTrackingCondsCount) + .Array("trcondition", gCondition, gTrackingCondsCount) + .EndObject(); + } } /////////////////////////////////////////////////////////////////// diff --git a/source/games/blood/src/nnexts.h b/source/games/blood/src/nnexts.h index 3c89cbe1b..a56d0cebd 100644 --- a/source/games/blood/src/nnexts.h +++ b/source/games/blood/src/nnexts.h @@ -42,222 +42,222 @@ BEGIN_BLD_NS enum { - // CONSTANTS - // additional non-thing proximity, sight and physics sprites - kMaxSuperXSprites = 512, - kMaxTrackingConditions = 64, - kMaxTracedObjects = 32, // per one tracking condition + // CONSTANTS + // additional non-thing proximity, sight and physics sprites + kMaxSuperXSprites = 512, + kMaxTrackingConditions = 64, + kMaxTracedObjects = 32, // per one tracking condition - // additional physics attributes for debris sprites - kPhysDebrisFloat = 0x0008, // *debris* slowly goes up and down from it's position - kPhysDebrisFly = 0x0010, // *debris* affected by negative gravity (fly instead of falling) - kPhysDebrisSwim = 0x0020, // *debris* can swim underwater (instead of drowning) - kPhysDebrisTouch = 0x0040, // *debris* can be moved via touch - kPhysDebrisVector = 0x0400, // *debris* can be affected by vector weapons - kPhysDebrisExplode = 0x0800, // *debris* can be affected by explosions + // additional physics attributes for debris sprites + kPhysDebrisFloat = 0x0008, // *debris* slowly goes up and down from it's position + kPhysDebrisFly = 0x0010, // *debris* affected by negative gravity (fly instead of falling) + kPhysDebrisSwim = 0x0020, // *debris* can swim underwater (instead of drowning) + kPhysDebrisTouch = 0x0040, // *debris* can be moved via touch + kPhysDebrisVector = 0x0400, // *debris* can be affected by vector weapons + kPhysDebrisExplode = 0x0800, // *debris* can be affected by explosions - // *modern types only hitag* - kModernTypeFlag0 = 0x0000, - kModernTypeFlag1 = 0x0001, - kModernTypeFlag2 = 0x0002, - kModernTypeFlag3 = 0x0003, - kModernTypeFlag4 = 0x0004, - kModernTypeFlag8 = 0x0008, - kModernTypeFlag16 = 0x0010, + // *modern types only hitag* + kModernTypeFlag0 = 0x0000, + kModernTypeFlag1 = 0x0001, + kModernTypeFlag2 = 0x0002, + kModernTypeFlag3 = 0x0003, + kModernTypeFlag4 = 0x0004, + kModernTypeFlag8 = 0x0008, + kModernTypeFlag16 = 0x0010, - kMaxRandomizeRetries = 16, - kPercFull = 100, - kCondRange = 100, + kMaxRandomizeRetries = 16, + kPercFull = 100, + kCondRange = 100, }; enum { - kPatrolStateSize = 42, - kPatrolAlarmSeeDist = 10000, - kPatrolAlarmHearDist = 10000, - kMaxPatrolVelocity = 500000, - kMaxPatrolCrouchVelocity = (kMaxPatrolVelocity >> 1), - kMaxPatrolSpotValue = 500, - kMinPatrolTurnDelay = 8, - kPatrolTurnDelayRange = 20, + kPatrolStateSize = 42, + kPatrolAlarmSeeDist = 10000, + kPatrolAlarmHearDist = 10000, + kMaxPatrolVelocity = 500000, + kMaxPatrolCrouchVelocity = (kMaxPatrolVelocity >> 1), + kMaxPatrolSpotValue = 500, + kMinPatrolTurnDelay = 8, + kPatrolTurnDelayRange = 20, - kDudeFlagStealth = 0x0001, - kDudeFlagCrouch = 0x0002, + kDudeFlagStealth = 0x0001, + kDudeFlagCrouch = 0x0002, - kSlopeDist = 0x20, - kEffectGenCallbackBase = 200, - kTriggerSpriteScreen = 0x0001, - kTriggerSpriteAim = 0x0002, + kSlopeDist = 0x20, + kEffectGenCallbackBase = 200, + kTriggerSpriteScreen = 0x0001, + kTriggerSpriteAim = 0x0002, - kMinAllowedPowerup = kPwUpFeatherFall, - kMaxAllowedPowerup = kMaxPowerUps + kMinAllowedPowerup = kPwUpFeatherFall, + kMaxAllowedPowerup = kMaxPowerUps }; // modern statnums enum { -kStatModernBase = 20, -kStatModernDudeTargetChanger = kStatModernBase, -kStatModernCondition = 21, -kStatModernEventRedirector = 22, -kStatModernPlayerLinker = 23, -kStatModernBrokenDudeLeech = 24, -kStatModernQavScene = 25, -kStatModernWindGen = 26, -kStatModernStealthRegion = 27, -kStatModernTmp = 39, -kStatModernMax = 40, + kStatModernBase = 20, + kStatModernDudeTargetChanger = kStatModernBase, + kStatModernCondition = 21, + kStatModernEventRedirector = 22, + kStatModernPlayerLinker = 23, + kStatModernBrokenDudeLeech = 24, + kStatModernQavScene = 25, + kStatModernWindGen = 26, + kStatModernStealthRegion = 27, + kStatModernTmp = 39, + kStatModernMax = 40, }; // modern sprite types enum { -kModernStealthRegion = 16, -kModernCustomDudeSpawn = 24, -kModernRandomTX = 25, -kModernSequentialTX = 26, -kModernSeqSpawner = 27, -kModernObjPropertiesChanger = 28, -kModernObjPicnumChanger = 29, -kModernObjSizeChanger = 31, -kModernDudeTargetChanger = 33, -kModernSectorFXChanger = 34, -kModernObjDataChanger = 35, -kModernSpriteDamager = 36, -kModernObjDataAccumulator = 37, -kModernEffectSpawner = 38, -kModernWindGenerator = 39, -kModernRandom = 40, -kModernRandom2 = 80, -kItemShroomGrow = 129, -kItemShroomShrink = 130, -kItemModernMapLevel = 150, // once picked up, draws whole minimap -kDudeModernCustom = kDudeVanillaMax, -kDudeModernCustomBurning = 255, -kModernThingTNTProx = 433, // detects only players -kModernThingThrowableRock = 434, // does small damage if hits target -kModernThingEnemyLifeLeech = 435, // the same as normal, except it aims in specified target only -kModernPlayerControl = 500, /// WIP -kModernCondition = 501, /// WIP, sends command only if specified conditions == true -kModernConditionFalse = 502, /// WIP, sends command only if specified conditions != true -kModernSlopeChanger = 504, -kGenModernMissileUniversal = 704, -kGenModernSound = 708, + kModernStealthRegion = 16, + kModernCustomDudeSpawn = 24, + kModernRandomTX = 25, + kModernSequentialTX = 26, + kModernSeqSpawner = 27, + kModernObjPropertiesChanger = 28, + kModernObjPicnumChanger = 29, + kModernObjSizeChanger = 31, + kModernDudeTargetChanger = 33, + kModernSectorFXChanger = 34, + kModernObjDataChanger = 35, + kModernSpriteDamager = 36, + kModernObjDataAccumulator = 37, + kModernEffectSpawner = 38, + kModernWindGenerator = 39, + kModernRandom = 40, + kModernRandom2 = 80, + kItemShroomGrow = 129, + kItemShroomShrink = 130, + kItemModernMapLevel = 150, // once picked up, draws whole minimap + kDudeModernCustom = kDudeVanillaMax, + kDudeModernCustomBurning = 255, + kModernThingTNTProx = 433, // detects only players + kModernThingThrowableRock = 434, // does small damage if hits target + kModernThingEnemyLifeLeech = 435, // the same as normal, except it aims in specified target only + kModernPlayerControl = 500, /// WIP + kModernCondition = 501, /// WIP, sends command only if specified conditions == true + kModernConditionFalse = 502, /// WIP, sends command only if specified conditions != true + kModernSlopeChanger = 504, + kGenModernMissileUniversal = 704, + kGenModernSound = 708, }; // type of random enum { -kRandomizeItem = 0, -kRandomizeDude = 1, -kRandomizeTX = 2, + kRandomizeItem = 0, + kRandomizeDude = 1, + kRandomizeTX = 2, }; // type of object enum { -OBJ_WALL = 0, -OBJ_SPRITE = 3, -OBJ_SECTOR = 6, + OBJ_WALL = 0, + OBJ_SPRITE = 3, + OBJ_SECTOR = 6, }; enum { -kCondGameBase = 0, -kCondGameMax = 50, -kCondMixedBase = 100, -kCondMixedMax = 200, -kCondWallBase = 200, -kCondWallMax = 300, -kCondSectorBase = 300, -kCondSectorMax = 400, -kCondPlayerBase = 400, -kCondPlayerMax = 450, -kCondDudeBase = 450, -kCondDudeMax = 500, -kCondSpriteBase = 500, -kCondSpriteMax = 600, + kCondGameBase = 0, + kCondGameMax = 50, + kCondMixedBase = 100, + kCondMixedMax = 200, + kCondWallBase = 200, + kCondWallMax = 300, + kCondSectorBase = 300, + kCondSectorMax = 400, + kCondPlayerBase = 400, + kCondPlayerMax = 450, + kCondDudeBase = 450, + kCondDudeMax = 500, + kCondSpriteBase = 500, + kCondSpriteMax = 600, }; enum { -kCondSerialSector = 100000, -kCondSerialWall = 200000, -kCondSerialSprite = 300000, -kCondSerialMax = 400000, + kCondSerialSector = 100000, + kCondSerialWall = 200000, + kCondSerialSprite = 300000, + kCondSerialMax = 400000, }; enum { -kPatrolMoveForward = 0, -kPatrolMoveBackward = 1, + kPatrolMoveForward = 0, + kPatrolMoveBackward = 1, }; // - STRUCTS ------------------------------------------------------------------ struct SPRITEMASS { // sprite mass info for getSpriteMassBySize(); - int seqId; - int16_t picnum; // mainly needs for moving debris - int16_t xrepeat; - int16_t yrepeat; - int16_t clipdist; // mass multiplier - int mass; - int16_t airVel; // mainly needs for moving debris - int fraction; // mainly needs for moving debris + int seqId; + int16_t picnum; // mainly needs for moving debris + int16_t xrepeat; + int16_t yrepeat; + int16_t clipdist; // mass multiplier + int mass; + int16_t airVel; // mainly needs for moving debris + int fraction; // mainly needs for moving debris }; struct QAVSCENE { // this one stores qavs anims that can be played by trigger - DBloodActor* initiator = nullptr; // index of sprite which triggered qav scene - QAV* qavResrc = nullptr; - short dummy = -1; + DBloodActor* initiator = nullptr; // index of sprite which triggered qav scene + QAV* qavResrc = nullptr; + short dummy = -1; }; struct THINGINFO_EXTRA { - bool allowThrow; // indicates if kDudeModernCustom can throw it + bool allowThrow; // indicates if kDudeModernCustom can throw it }; struct VECTORINFO_EXTRA { - int fireSound[2]; // predefined fire sounds. used by kDudeModernCustom, but can be used for something else. + int fireSound[2]; // predefined fire sounds. used by kDudeModernCustom, but can be used for something else. }; struct MISSILEINFO_EXTRA { - int fireSound[2]; // predefined fire sounds. used by kDudeModernCustom, but can be used for something else. - bool dmgType[kDamageMax]; // list of damages types missile can use - bool allowImpact; // allow to trigger object with Impact flag enabled with this missile + int fireSound[2]; // predefined fire sounds. used by kDudeModernCustom, but can be used for something else. + bool dmgType[kDamageMax]; // list of damages types missile can use + bool allowImpact; // allow to trigger object with Impact flag enabled with this missile }; struct DUDEINFO_EXTRA { - bool flying; // used by kModernDudeTargetChanger (ai fight) - bool melee; // used by kModernDudeTargetChanger (ai fight) - int idlgseqofs : 6; // used for patrol - int mvegseqofs : 6; // used for patrol - int idlwseqofs : 6; // used for patrol - int mvewseqofs : 6; // used for patrol - int idlcseqofs : 6; // used for patrol - int mvecseqofs : 6; // used for patrol - + bool flying; // used by kModernDudeTargetChanger (ai fight) + bool melee; // used by kModernDudeTargetChanger (ai fight) + int idlgseqofs : 6; // used for patrol + int mvegseqofs : 6; // used for patrol + int idlwseqofs : 6; // used for patrol + int mvewseqofs : 6; // used for patrol + int idlcseqofs : 6; // used for patrol + int mvecseqofs : 6; // used for patrol + }; struct TRPLAYERCTRL { // this one for controlling the player using triggers (movement speed, jumps and other stuff) - QAVSCENE qavScene; + QAVSCENE qavScene; }; struct OBJECTS_TO_TRACK { - uint8_t cmd; - EventObject obj; + uint8_t cmd; + EventObject obj; }; struct TRCONDITION { - DBloodActor* actor; - uint8_t length; - OBJECTS_TO_TRACK obj[kMaxTracedObjects]; + DBloodActor* actor; + uint8_t length; + OBJECTS_TO_TRACK obj[kMaxTracedObjects]; }; struct PATROL_FOUND_SOUNDS { - int snd; - int max; - int cur; + int snd; + int max; + int cur; }; struct CONDITION_TYPE_NAMES { - int rng1; - int rng2; - char name[32]; + int rng1; + int rng2; + char name[32]; }; @@ -331,7 +331,7 @@ void seqTxSendCmdAll(DBloodActor* pXSource, DBloodActor* nIndex, COMMAND_ID cmd, void trPlayerCtrlLink(DBloodActor* pXSource, PLAYER* pPlayer, bool checkCondition); void trPlayerCtrlStopScene(PLAYER* pPlayer); // ------------------------------------------------------------------------- // -void modernTypeTrigger(int type, sectortype*sect, walltype* wal, DBloodActor* actor, EVENT& event); +void modernTypeTrigger(int type, sectortype* sect, walltype* wal, DBloodActor* actor, EVENT& event); bool modernTypeOperateSector(sectortype* pSector, const EVENT& event); bool modernTypeOperateSprite(DBloodActor*, EVENT& event); bool modernTypeOperateWall(walltype* pWall, const EVENT& event); @@ -348,7 +348,7 @@ void playerQavScenePlay(PLAYER* pPlayer); void playerQavSceneDraw(PLAYER* pPlayer, int a2, double a3, double a4, int a5); void playerQavSceneReset(PLAYER* pPlayer); // ------------------------------------------------------------------------- // -void callbackUniMissileBurst(DBloodActor*actor, sectortype* nSprite); +void callbackUniMissileBurst(DBloodActor* actor, sectortype* nSprite); void callbackMakeMissileBlocking(DBloodActor* actor, sectortype* nSprite); void callbackGenDudeUpdate(DBloodActor* actor, sectortype* nSprite); // ------------------------------------------------------------------------- // @@ -387,27 +387,27 @@ void aiPatrolFlagsMgr(DBloodActor* sourceactor, DBloodActor* destactor, bool cop void aiPatrolRandGoalAng(DBloodActor* actor); void aiPatrolTurn(DBloodActor* actor); inline int aiPatrolGetVelocity(int speed, int value) { - return (value > 0) ? ClipRange((speed / 3) + (2500 * value), 0, 0x47956) : speed; + return (value > 0) ? ClipRange((speed / 3) + (2500 * value), 0, 0x47956) : speed; } inline bool aiPatrolWaiting(AISTATE* pAiState) { - return (pAiState && pAiState->stateType >= kAiStatePatrolWaitL && pAiState->stateType <= kAiStatePatrolWaitW); + return (pAiState && pAiState->stateType >= kAiStatePatrolWaitL && pAiState->stateType <= kAiStatePatrolWaitW); } inline bool aiPatrolMoving(AISTATE* pAiState) { - return (pAiState && pAiState->stateType >= kAiStatePatrolMoveL && pAiState->stateType <= kAiStatePatrolMoveW); + return (pAiState && pAiState->stateType >= kAiStatePatrolMoveL && pAiState->stateType <= kAiStatePatrolMoveW); } inline bool aiPatrolTurning(AISTATE* pAiState) { - return (pAiState && pAiState->stateType >= kAiStatePatrolTurnL && pAiState->stateType <= kAiStatePatrolTurnW); + return (pAiState && pAiState->stateType >= kAiStatePatrolTurnL && pAiState->stateType <= kAiStatePatrolTurnW); } inline bool aiInPatrolState(AISTATE* pAiState) { - return (pAiState && pAiState->stateType >= kAiStatePatrolBase && pAiState->stateType < kAiStatePatrolMax); + return (pAiState && pAiState->stateType >= kAiStatePatrolBase && pAiState->stateType < kAiStatePatrolMax); } inline bool aiInPatrolState(int nAiStateType) { - return (nAiStateType >= kAiStatePatrolBase && nAiStateType < kAiStatePatrolMax); + return (nAiStateType >= kAiStatePatrolBase && nAiStateType < kAiStatePatrolMax); } // ------------------------------------------------------------------------- // bool readyForCrit(DBloodActor* pHunter, DBloodActor* pVictim); @@ -416,7 +416,7 @@ void clampSprite(DBloodActor* actor, int which = 3); inline bool valueIsBetween(int val, int min, int max) { - return (val > min && val < max); + return (val > min && val < max); } diff --git a/source/games/blood/src/osdcmd.cpp b/source/games/blood/src/osdcmd.cpp index 7f4a5af4e..398ff4261 100644 --- a/source/games/blood/src/osdcmd.cpp +++ b/source/games/blood/src/osdcmd.cpp @@ -33,62 +33,62 @@ BEGIN_BLD_NS void GameInterface::WarpToCoords(int x, int y, int z, int ang, int horz) { - PLAYER *pPlayer = &gPlayer[myconnectindex]; - VIEW* pView = &gPrevView[myconnectindex]; + PLAYER* pPlayer = &gPlayer[myconnectindex]; + VIEW* pView = &gPrevView[myconnectindex]; - pPlayer->actor->spr.pos.X = pView->x = gView->actor->spr.pos.X = x; - pPlayer->actor->spr.pos.Y = pView->y = gView->actor->spr.pos.Y = y; - pPlayer->zView = pView->viewz = gView->zView = z; + pPlayer->actor->spr.pos.X = pView->x = gView->actor->spr.pos.X = x; + pPlayer->actor->spr.pos.Y = pView->y = gView->actor->spr.pos.Y = y; + pPlayer->zView = pView->viewz = gView->zView = z; - if (ang != INT_MIN) - { - pPlayer->angle.oang = pPlayer->angle.ang = pView->angle = gView->angle.ang = buildang(ang); - } + if (ang != INT_MIN) + { + pPlayer->angle.oang = pPlayer->angle.ang = pView->angle = gView->angle.ang = buildang(ang); + } - if (horz != INT_MIN) - { - pPlayer->horizon.ohoriz = pPlayer->horizon.horiz = pView->horiz = gView->horizon.horiz = buildhoriz(horz); - } + if (horz != INT_MIN) + { + pPlayer->horizon.ohoriz = pPlayer->horizon.horiz = pView->horiz = gView->horizon.horiz = buildhoriz(horz); + } } void GameInterface::ToggleThirdPerson() { - if (gamestate != GS_LEVEL) return; - if (gViewPos > VIEWPOS_0) - gViewPos = VIEWPOS_0; - else - gViewPos = VIEWPOS_1; + if (gamestate != GS_LEVEL) return; + if (gViewPos > VIEWPOS_0) + gViewPos = VIEWPOS_0; + else + gViewPos = VIEWPOS_1; } void GameInterface::SwitchCoopView() { - if (gamestate != GS_LEVEL) return; - if (gGameOptions.nGameType == 1) - { - gViewIndex = connectpoint2[gViewIndex]; - if (gViewIndex == -1) - gViewIndex = connecthead; - gView = &gPlayer[gViewIndex]; - } - else if (gGameOptions.nGameType == 3) - { - int oldViewIndex = gViewIndex; - do - { - gViewIndex = connectpoint2[gViewIndex]; - if (gViewIndex == -1) - gViewIndex = connecthead; - if (oldViewIndex == gViewIndex || gMe->teamId == gPlayer[gViewIndex].teamId) - break; - } while (oldViewIndex != gViewIndex); - gView = &gPlayer[gViewIndex]; - } + if (gamestate != GS_LEVEL) return; + if (gGameOptions.nGameType == 1) + { + gViewIndex = connectpoint2[gViewIndex]; + if (gViewIndex == -1) + gViewIndex = connecthead; + gView = &gPlayer[gViewIndex]; + } + else if (gGameOptions.nGameType == 3) + { + int oldViewIndex = gViewIndex; + do + { + gViewIndex = connectpoint2[gViewIndex]; + if (gViewIndex == -1) + gViewIndex = connecthead; + if (oldViewIndex == gViewIndex || gMe->teamId == gPlayer[gViewIndex].teamId) + break; + } while (oldViewIndex != gViewIndex); + gView = &gPlayer[gViewIndex]; + } } void GameInterface::ToggleShowWeapon() { - if (gamestate != GS_LEVEL) return; - cl_showweapon = (cl_showweapon + 1) & 3; + if (gamestate != GS_LEVEL) return; + cl_showweapon = (cl_showweapon + 1) & 3; } END_BLD_NS diff --git a/source/games/blood/src/player.cpp b/source/games/blood/src/player.cpp index 5cbffc1bb..70dd19310 100644 --- a/source/games/blood/src/player.cpp +++ b/source/games/blood/src/player.cpp @@ -35,1292 +35,1456 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. BEGIN_BLD_NS PLAYER gPlayer[kMaxPlayers]; -PLAYER *gMe, *gView; +PLAYER* gMe, * gView; bool gBlueFlagDropped = false; bool gRedFlagDropped = false; // V = has effect in game, X = no effect in game POWERUPINFO gPowerUpInfo[kMaxPowerUps] = { - { -1, 1, 1, 1 }, // 00: V keys - { -1, 1, 1, 1 }, // 01: V keys - { -1, 1, 1, 1 }, // 02: V keys - { -1, 1, 1, 1 }, // 03: V keys - { -1, 1, 1, 1 }, // 04: V keys - { -1, 1, 1, 1 }, // 05: V keys - { -1, 1, 1, 1 }, // 06: V keys - { -1, 0, 100, 100 }, // 07: V doctor's bag - { -1, 0, 50, 100 }, // 08: V medicine pouch - { -1, 0, 20, 100 }, // 09: V life essense - { -1, 0, 100, 200 }, // 10: V life seed - { -1, 0, 2, 200 }, // 11: V red potion - { 783, 0, 3600, 432000 }, // 12: V feather fall - { 896, 0, 3600, 432000 }, // 13: V cloak of invisibility - { 825, 1, 3600, 432000 }, // 14: V death mask (invulnerability) - { 827, 0, 3600, 432000 }, // 15: V jump boots - { 828, 0, 3600, 432000 }, // 16: X raven flight - { 829, 0, 3600, 1728000 }, // 17: V guns akimbo - { 830, 0, 3600, 432000 }, // 18: V diving suit - { 831, 0, 3600, 432000 }, // 19: V gas mask - { -1, 0, 3600, 432000 }, // 20: X clone - { 2566, 0, 3600, 432000 }, // 21: V crystal ball - { 836, 0, 3600, 432000 }, // 22: X decoy - { 853, 0, 3600, 432000 }, // 23: V doppleganger - { 2428, 0, 3600, 432000 }, // 24: V reflective shots - { 839, 0, 3600, 432000 }, // 25: V beast vision - { 768, 0, 3600, 432000 }, // 26: X cloak of shadow (useless) - { 840, 0, 3600, 432000 }, // 27: X rage shroom - { 841, 0, 900, 432000 }, // 28: V delirium shroom - { 842, 0, 3600, 432000 }, // 29: V grow shroom (gModernMap only) - { 843, 0, 3600, 432000 }, // 30: V shrink shroom (gModernMap only) - { -1, 0, 3600, 432000 }, // 31: X death mask (useless) - { -1, 0, 3600, 432000 }, // 32: X wine goblet - { -1, 0, 3600, 432000 }, // 33: X wine bottle - { -1, 0, 3600, 432000 }, // 34: X skull grail - { -1, 0, 3600, 432000 }, // 35: X silver grail - { -1, 0, 3600, 432000 }, // 36: X tome - { -1, 0, 3600, 432000 }, // 37: X black chest - { -1, 0, 3600, 432000 }, // 38: X wooden chest - { 837, 1, 3600, 432000 }, // 39: V asbestos armor - { -1, 0, 1, 432000 }, // 40: V basic armor - { -1, 0, 1, 432000 }, // 41: V body armor - { -1, 0, 1, 432000 }, // 42: V fire armor - { -1, 0, 1, 432000 }, // 43: V spirit armor - { -1, 0, 1, 432000 }, // 44: V super armor - { 0, 0, 0, 0 }, // 45: ? unknown - { 0, 0, 0, 0 }, // 46: ? unknown - { 0, 0, 0, 0 }, // 47: ? unknown - { 0, 0, 0, 0 }, // 48: ? unknown - { 0, 0, 0, 0 }, // 49: X dummy - { 833, 1, 1, 1 } // 50: V kModernItemLevelMap (gModernMap only) + { -1, 1, 1, 1 }, // 00: V keys + { -1, 1, 1, 1 }, // 01: V keys + { -1, 1, 1, 1 }, // 02: V keys + { -1, 1, 1, 1 }, // 03: V keys + { -1, 1, 1, 1 }, // 04: V keys + { -1, 1, 1, 1 }, // 05: V keys + { -1, 1, 1, 1 }, // 06: V keys + { -1, 0, 100, 100 }, // 07: V doctor's bag + { -1, 0, 50, 100 }, // 08: V medicine pouch + { -1, 0, 20, 100 }, // 09: V life essense + { -1, 0, 100, 200 }, // 10: V life seed + { -1, 0, 2, 200 }, // 11: V red potion + { 783, 0, 3600, 432000 }, // 12: V feather fall + { 896, 0, 3600, 432000 }, // 13: V cloak of invisibility + { 825, 1, 3600, 432000 }, // 14: V death mask (invulnerability) + { 827, 0, 3600, 432000 }, // 15: V jump boots + { 828, 0, 3600, 432000 }, // 16: X raven flight + { 829, 0, 3600, 1728000 }, // 17: V guns akimbo + { 830, 0, 3600, 432000 }, // 18: V diving suit + { 831, 0, 3600, 432000 }, // 19: V gas mask + { -1, 0, 3600, 432000 }, // 20: X clone + { 2566, 0, 3600, 432000 }, // 21: V crystal ball + { 836, 0, 3600, 432000 }, // 22: X decoy + { 853, 0, 3600, 432000 }, // 23: V doppleganger + { 2428, 0, 3600, 432000 }, // 24: V reflective shots + { 839, 0, 3600, 432000 }, // 25: V beast vision + { 768, 0, 3600, 432000 }, // 26: X cloak of shadow (useless) + { 840, 0, 3600, 432000 }, // 27: X rage shroom + { 841, 0, 900, 432000 }, // 28: V delirium shroom + { 842, 0, 3600, 432000 }, // 29: V grow shroom (gModernMap only) + { 843, 0, 3600, 432000 }, // 30: V shrink shroom (gModernMap only) + { -1, 0, 3600, 432000 }, // 31: X death mask (useless) + { -1, 0, 3600, 432000 }, // 32: X wine goblet + { -1, 0, 3600, 432000 }, // 33: X wine bottle + { -1, 0, 3600, 432000 }, // 34: X skull grail + { -1, 0, 3600, 432000 }, // 35: X silver grail + { -1, 0, 3600, 432000 }, // 36: X tome + { -1, 0, 3600, 432000 }, // 37: X black chest + { -1, 0, 3600, 432000 }, // 38: X wooden chest + { 837, 1, 3600, 432000 }, // 39: V asbestos armor + { -1, 0, 1, 432000 }, // 40: V basic armor + { -1, 0, 1, 432000 }, // 41: V body armor + { -1, 0, 1, 432000 }, // 42: V fire armor + { -1, 0, 1, 432000 }, // 43: V spirit armor + { -1, 0, 1, 432000 }, // 44: V super armor + { 0, 0, 0, 0 }, // 45: ? unknown + { 0, 0, 0, 0 }, // 46: ? unknown + { 0, 0, 0, 0 }, // 47: ? unknown + { 0, 0, 0, 0 }, // 48: ? unknown + { 0, 0, 0, 0 }, // 49: X dummy + { 833, 1, 1, 1 } // 50: V kModernItemLevelMap (gModernMap only) }; int Handicap[] = { - 144, 208, 256, 304, 368 + 144, 208, 256, 304, 368 }; POSTURE gPostureDefaults[kModeMax][kPostureMax] = { - - // normal human - { - { 0x4000, 0x4000, 0x4000, 14, 17, 24, 16, 32, 80, 0x1600, 0x1200, 0xc00, 0x90, -0xbaaaa, -0x175555 }, - { 0x1200, 0x1200, 0x1200, 14, 17, 24, 16, 32, 80, 0x1400, 0x1000, -0x600, 0xb0, 0x5b05, 0 }, - { 0x2000, 0x2000, 0x2000, 22, 28, 24, 16, 16, 40, 0x800, 0x600, -0x600, 0xb0, 0, 0 }, - }, - // normal beast - { - { 0x4000, 0x4000, 0x4000, 14, 17, 24, 16, 32, 80, 0x1600, 0x1200, 0xc00, 0x90, -0xbaaaa, -0x175555 }, - { 0x1200, 0x1200, 0x1200, 14, 17, 24, 16, 32, 80, 0x1400, 0x1000, -0x600, 0xb0, 0x5b05, 0 }, - { 0x2000, 0x2000, 0x2000, 22, 28, 24, 16, 16, 40, 0x800, 0x600, -0x600, 0xb0, 0, 0 }, - }, + // normal human + { + { 0x4000, 0x4000, 0x4000, 14, 17, 24, 16, 32, 80, 0x1600, 0x1200, 0xc00, 0x90, -0xbaaaa, -0x175555 }, + { 0x1200, 0x1200, 0x1200, 14, 17, 24, 16, 32, 80, 0x1400, 0x1000, -0x600, 0xb0, 0x5b05, 0 }, + { 0x2000, 0x2000, 0x2000, 22, 28, 24, 16, 16, 40, 0x800, 0x600, -0x600, 0xb0, 0, 0 }, + }, - // shrink human - { - { 10384, 10384, 10384, 14, 17, 24, 16, 32, 80, 5632, 4608, 3072, 144, -564586, -1329173 }, - { 2108, 2108, 2108, 14, 17, 24, 16, 32, 80, 5120, 4096, -1536, 176, 0x5b05, 0 }, - { 2192, 2192, 2192, 22, 28, 24, 16, 16, 40, 2048, 1536, -1536, 176, 0, 0 }, - }, + // normal beast + { + { 0x4000, 0x4000, 0x4000, 14, 17, 24, 16, 32, 80, 0x1600, 0x1200, 0xc00, 0x90, -0xbaaaa, -0x175555 }, + { 0x1200, 0x1200, 0x1200, 14, 17, 24, 16, 32, 80, 0x1400, 0x1000, -0x600, 0xb0, 0x5b05, 0 }, + { 0x2000, 0x2000, 0x2000, 22, 28, 24, 16, 16, 40, 0x800, 0x600, -0x600, 0xb0, 0, 0 }, + }, - // grown human - { - { 19384, 19384, 19384, 14, 17, 24, 16, 32, 80, 5632, 4608, 3072, 144, -1014586, -1779173 }, - { 5608, 5608, 5608, 14, 17, 24, 16, 32, 80, 5120, 4096, -1536, 176, 0x5b05, 0 }, - { 11192, 11192, 11192, 22, 28, 24, 16, 16, 40, 2048, 1536, -1536, 176, 0, 0 }, - }, + // shrink human + { + { 10384, 10384, 10384, 14, 17, 24, 16, 32, 80, 5632, 4608, 3072, 144, -564586, -1329173 }, + { 2108, 2108, 2108, 14, 17, 24, 16, 32, 80, 5120, 4096, -1536, 176, 0x5b05, 0 }, + { 2192, 2192, 2192, 22, 28, 24, 16, 16, 40, 2048, 1536, -1536, 176, 0, 0 }, + }, + + // grown human + { + { 19384, 19384, 19384, 14, 17, 24, 16, 32, 80, 5632, 4608, 3072, 144, -1014586, -1779173 }, + { 5608, 5608, 5608, 14, 17, 24, 16, 32, 80, 5120, 4096, -1536, 176, 0x5b05, 0 }, + { 11192, 11192, 11192, 22, 28, 24, 16, 16, 40, 2048, 1536, -1536, 176, 0, 0 }, + }, }; AMMOINFO gAmmoInfo[] = { - { 0, -1 }, - { 100, -1 }, - { 100, 4 }, - { 500, 5 }, - { 100, -1 }, - { 50, -1 }, - { 2880, -1 }, - { 250, -1 }, - { 100, -1 }, - { 100, -1 }, - { 50, -1 }, - { 50, -1 }, + { 0, -1 }, + { 100, -1 }, + { 100, 4 }, + { 500, 5 }, + { 100, -1 }, + { 50, -1 }, + { 2880, -1 }, + { 250, -1 }, + { 100, -1 }, + { 100, -1 }, + { 50, -1 }, + { 50, -1 }, }; struct ARMORDATA { - int armor0; - int armor0max; - int armor1; - int armor1max; - int armor2; - int armor2max; + int armor0; + int armor0max; + int armor1; + int armor1max; + int armor2; + int armor2max; }; ARMORDATA armorData[5] = { - { 0x320, 0x640, 0x320, 0x640, 0x320, 0x640 }, - { 0x640, 0x640, 0, 0x640, 0, 0x640 }, - { 0, 0x640, 0x640, 0x640, 0, 0x640 }, - { 0, 0x640, 0, 0x640, 0x640, 0x640 }, - { 0xc80, 0xc80, 0xc80, 0xc80, 0xc80, 0xc80 } + { 0x320, 0x640, 0x320, 0x640, 0x320, 0x640 }, + { 0x640, 0x640, 0, 0x640, 0, 0x640 }, + { 0, 0x640, 0x640, 0x640, 0, 0x640 }, + { 0, 0x640, 0, 0x640, 0x640, 0x640 }, + { 0xc80, 0xc80, 0xc80, 0xc80, 0xc80, 0xc80 } }; struct VICTORY { - const char *message; - int Kills; + const char* message; + int Kills; }; VICTORY gVictory[] = { - { "%s boned %s like a fish", 4100 }, - { "%s castrated %s", 4101 }, - { "%s creamed %s", 4102 }, - { "%s destroyed %s", 4103 }, - { "%s diced %s", 4104 }, - { "%s disemboweled %s", 4105 }, - { "%s flattened %s", 4106 }, - { "%s gave %s Anal Justice", 4107 }, - { "%s gave AnAl MaDnEsS to %s", 4108 }, - { "%s hurt %s real bad", 4109 }, - { "%s killed %s", 4110 }, - { "%s made mincemeat out of %s", 4111 }, - { "%s massacred %s", 4112 }, - { "%s mutilated %s", 4113 }, - { "%s reamed %s", 4114 }, - { "%s ripped %s a new orifice", 4115 }, - { "%s slaughtered %s", 4116 }, - { "%s sliced %s", 4117 }, - { "%s smashed %s", 4118 }, - { "%s sodomized %s", 4119 }, - { "%s splattered %s", 4120 }, - { "%s squashed %s", 4121 }, - { "%s throttled %s", 4122 }, - { "%s wasted %s", 4123 }, - { "%s body bagged %s", 4124 }, + { "%s boned %s like a fish", 4100 }, + { "%s castrated %s", 4101 }, + { "%s creamed %s", 4102 }, + { "%s destroyed %s", 4103 }, + { "%s diced %s", 4104 }, + { "%s disemboweled %s", 4105 }, + { "%s flattened %s", 4106 }, + { "%s gave %s Anal Justice", 4107 }, + { "%s gave AnAl MaDnEsS to %s", 4108 }, + { "%s hurt %s real bad", 4109 }, + { "%s killed %s", 4110 }, + { "%s made mincemeat out of %s", 4111 }, + { "%s massacred %s", 4112 }, + { "%s mutilated %s", 4113 }, + { "%s reamed %s", 4114 }, + { "%s ripped %s a new orifice", 4115 }, + { "%s slaughtered %s", 4116 }, + { "%s sliced %s", 4117 }, + { "%s smashed %s", 4118 }, + { "%s sodomized %s", 4119 }, + { "%s splattered %s", 4120 }, + { "%s squashed %s", 4121 }, + { "%s throttled %s", 4122 }, + { "%s wasted %s", 4123 }, + { "%s body bagged %s", 4124 }, }; struct SUICIDE { - const char *message; - int Kills; + const char* message; + int Kills; }; SUICIDE gSuicide[] = { - { "%s is excrement", 4202 }, - { "%s is hamburger", 4203 }, - { "%s suffered scrotum separation", 4204 }, - { "%s volunteered for population control", 4206 }, - { "%s has suicided", 4207 }, + { "%s is excrement", 4202 }, + { "%s is hamburger", 4203 }, + { "%s suffered scrotum separation", 4204 }, + { "%s volunteered for population control", 4206 }, + { "%s has suicided", 4207 }, }; struct DAMAGEINFO { - int armorType; - int Kills[3]; - int at10[3]; + int armorType; + int Kills[3]; + int at10[3]; }; DAMAGEINFO damageInfo[7] = { - { -1, 731, 732, 733, 710, 710, 710 }, - { 1, 742, 743, 744, 711, 711, 711 }, - { 0, 731, 732, 733, 712, 712, 712 }, - { 1, 731, 732, 733, 713, 713, 713 }, - { -1, 724, 724, 724, 714, 714, 714 }, - { 2, 731, 732, 733, 715, 715, 715 }, - { 0, 0, 0, 0, 0, 0, 0 } + { -1, 731, 732, 733, 710, 710, 710 }, + { 1, 742, 743, 744, 711, 711, 711 }, + { 0, 731, 732, 733, 712, 712, 712 }, + { 1, 731, 732, 733, 713, 713, 713 }, + { -1, 724, 724, 724, 714, 714, 714 }, + { 2, 731, 732, 733, 715, 715, 715 }, + { 0, 0, 0, 0, 0, 0, 0 } }; +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + inline bool IsTargetTeammate(PLAYER* pSourcePlayer, DBloodActor* target) { - if (pSourcePlayer == nullptr) - return false; - if (!target->IsPlayerActor()) - return false; - if (gGameOptions.nGameType == 1 || gGameOptions.nGameType == 3) - { - PLAYER* pTargetPlayer = &gPlayer[target->spr.type - kDudePlayer1]; - if (pSourcePlayer != pTargetPlayer) - { - if (gGameOptions.nGameType == 1) - return true; - if (gGameOptions.nGameType == 3 && (pSourcePlayer->teamId & 3) == (pTargetPlayer->teamId & 3)) - return true; - } - } + if (pSourcePlayer == nullptr) + return false; + if (!target->IsPlayerActor()) + return false; + if (gGameOptions.nGameType == 1 || gGameOptions.nGameType == 3) + { + PLAYER* pTargetPlayer = &gPlayer[target->spr.type - kDudePlayer1]; + if (pSourcePlayer != pTargetPlayer) + { + if (gGameOptions.nGameType == 1) + return true; + if (gGameOptions.nGameType == 3 && (pSourcePlayer->teamId & 3) == (pTargetPlayer->teamId & 3)) + return true; + } + } - return false; + return false; } -int powerupCheck(PLAYER *pPlayer, int nPowerUp) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +int powerupCheck(PLAYER* pPlayer, int nPowerUp) { - assert(pPlayer != NULL); - assert(nPowerUp >= 0 && nPowerUp < kMaxPowerUps); - int nPack = powerupToPackItem(nPowerUp); - if (nPack >= 0 && !packItemActive(pPlayer, nPack)) - return 0; - return pPlayer->pwUpTime[nPowerUp]; + assert(pPlayer != NULL); + assert(nPowerUp >= 0 && nPowerUp < kMaxPowerUps); + int nPack = powerupToPackItem(nPowerUp); + if (nPack >= 0 && !packItemActive(pPlayer, nPack)) + return 0; + return pPlayer->pwUpTime[nPowerUp]; } -bool powerupActivate(PLAYER *pPlayer, int nPowerUp) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +bool powerupActivate(PLAYER* pPlayer, int nPowerUp) { - if (powerupCheck(pPlayer, nPowerUp) > 0 && gPowerUpInfo[nPowerUp].pickupOnce) - return 0; - if (!pPlayer->pwUpTime[nPowerUp]) - pPlayer->pwUpTime[nPowerUp] = gPowerUpInfo[nPowerUp].bonusTime; - int nPack = powerupToPackItem(nPowerUp); - if (nPack >= 0) - pPlayer->packSlots[nPack].isActive = 1; - - switch (nPowerUp + kItemBase) { - #ifdef NOONE_EXTENSIONS - case kItemModernMapLevel: - if (gModernMap) gFullMap = true; - break; - case kItemShroomShrink: - if (!gModernMap) break; - else if (isGrown(pPlayer->actor)) playerDeactivateShrooms(pPlayer); - else playerSizeShrink(pPlayer, 2); - break; - case kItemShroomGrow: - if (!gModernMap) break; - else if (isShrinked(pPlayer->actor)) playerDeactivateShrooms(pPlayer); - else { - playerSizeGrow(pPlayer, 2); - if (powerupCheck(&gPlayer[pPlayer->actor->spr.type - kDudePlayer1], kPwUpShadowCloak) > 0) { - powerupDeactivate(pPlayer, kPwUpShadowCloak); - pPlayer->pwUpTime[kPwUpShadowCloak] = 0; - } + if (powerupCheck(pPlayer, nPowerUp) > 0 && gPowerUpInfo[nPowerUp].pickupOnce) + return 0; + if (!pPlayer->pwUpTime[nPowerUp]) + pPlayer->pwUpTime[nPowerUp] = gPowerUpInfo[nPowerUp].bonusTime; + int nPack = powerupToPackItem(nPowerUp); + if (nPack >= 0) + pPlayer->packSlots[nPack].isActive = 1; - if (ceilIsTooLow(pPlayer->actor)) - actDamageSprite(pPlayer->actor, pPlayer->actor, kDamageExplode, 65535); - } - break; - #endif - case kItemFeatherFall: - case kItemJumpBoots: - pPlayer->damageControl[0]++; - break; - case kItemReflectShots: // reflective shots - if (pPlayer == gMe && gGameOptions.nGameType == 0) - sfxSetReverb2(1); - break; - case kItemDeathMask: - for (int i = 0; i < 7; i++) - pPlayer->damageControl[i]++; - break; - case kItemDivingSuit: // diving suit - pPlayer->damageControl[4]++; - if (pPlayer == gMe && gGameOptions.nGameType == 0) - sfxSetReverb(1); - break; - case kItemGasMask: - pPlayer->damageControl[4]++; - break; - case kItemArmorAsbest: - pPlayer->damageControl[1]++; - break; - case kItemTwoGuns: - pPlayer->newWeapon = pPlayer->curWeapon; - WeaponRaise(pPlayer); - break; - } - sfxPlay3DSound(pPlayer->actor, 776, -1, 0); - return 1; + switch (nPowerUp + kItemBase) { +#ifdef NOONE_EXTENSIONS + case kItemModernMapLevel: + if (gModernMap) gFullMap = true; + break; + case kItemShroomShrink: + if (!gModernMap) break; + else if (isGrown(pPlayer->actor)) playerDeactivateShrooms(pPlayer); + else playerSizeShrink(pPlayer, 2); + break; + case kItemShroomGrow: + if (!gModernMap) break; + else if (isShrinked(pPlayer->actor)) playerDeactivateShrooms(pPlayer); + else { + playerSizeGrow(pPlayer, 2); + if (powerupCheck(&gPlayer[pPlayer->actor->spr.type - kDudePlayer1], kPwUpShadowCloak) > 0) { + powerupDeactivate(pPlayer, kPwUpShadowCloak); + pPlayer->pwUpTime[kPwUpShadowCloak] = 0; + } + + if (ceilIsTooLow(pPlayer->actor)) + actDamageSprite(pPlayer->actor, pPlayer->actor, kDamageExplode, 65535); + } + break; +#endif + case kItemFeatherFall: + case kItemJumpBoots: + pPlayer->damageControl[0]++; + break; + case kItemReflectShots: // reflective shots + if (pPlayer == gMe && gGameOptions.nGameType == 0) + sfxSetReverb2(1); + break; + case kItemDeathMask: + for (int i = 0; i < 7; i++) + pPlayer->damageControl[i]++; + break; + case kItemDivingSuit: // diving suit + pPlayer->damageControl[4]++; + if (pPlayer == gMe && gGameOptions.nGameType == 0) + sfxSetReverb(1); + break; + case kItemGasMask: + pPlayer->damageControl[4]++; + break; + case kItemArmorAsbest: + pPlayer->damageControl[1]++; + break; + case kItemTwoGuns: + pPlayer->newWeapon = pPlayer->curWeapon; + WeaponRaise(pPlayer); + break; + } + sfxPlay3DSound(pPlayer->actor, 776, -1, 0); + return 1; } -void powerupDeactivate(PLAYER *pPlayer, int nPowerUp) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void powerupDeactivate(PLAYER* pPlayer, int nPowerUp) { - int nPack = powerupToPackItem(nPowerUp); - if (nPack >= 0) - pPlayer->packSlots[nPack].isActive = 0; - - switch (nPowerUp + kItemBase) { - #ifdef NOONE_EXTENSIONS - case kItemShroomShrink: - if (gModernMap) { - playerSizeReset(pPlayer); - if (ceilIsTooLow(pPlayer->actor)) - actDamageSprite(pPlayer->actor, pPlayer->actor, kDamageExplode, 65535); - } - break; - case kItemShroomGrow: - if (gModernMap) playerSizeReset(pPlayer); - break; - #endif - case kItemFeatherFall: - case kItemJumpBoots: - pPlayer->damageControl[0]--; - break; - case kItemDeathMask: - for (int i = 0; i < 7; i++) - pPlayer->damageControl[i]--; - break; - case kItemDivingSuit: - pPlayer->damageControl[4]--; - if (pPlayer == gMe && VanillaMode() ? true : pPlayer->pwUpTime[24] == 0) - sfxSetReverb(0); - break; - case kItemReflectShots: - if (pPlayer == gMe && VanillaMode() ? true : pPlayer->packSlots[1].isActive == 0) - sfxSetReverb(0); - break; - case kItemGasMask: - pPlayer->damageControl[4]--; - break; - case kItemArmorAsbest: - pPlayer->damageControl[1]--; - break; - case kItemTwoGuns: - pPlayer->newWeapon = pPlayer->curWeapon; - WeaponRaise(pPlayer); - break; - } + int nPack = powerupToPackItem(nPowerUp); + if (nPack >= 0) + pPlayer->packSlots[nPack].isActive = 0; + + switch (nPowerUp + kItemBase) { +#ifdef NOONE_EXTENSIONS + case kItemShroomShrink: + if (gModernMap) { + playerSizeReset(pPlayer); + if (ceilIsTooLow(pPlayer->actor)) + actDamageSprite(pPlayer->actor, pPlayer->actor, kDamageExplode, 65535); + } + break; + case kItemShroomGrow: + if (gModernMap) playerSizeReset(pPlayer); + break; +#endif + case kItemFeatherFall: + case kItemJumpBoots: + pPlayer->damageControl[0]--; + break; + case kItemDeathMask: + for (int i = 0; i < 7; i++) + pPlayer->damageControl[i]--; + break; + case kItemDivingSuit: + pPlayer->damageControl[4]--; + if (pPlayer == gMe && VanillaMode() ? true : pPlayer->pwUpTime[24] == 0) + sfxSetReverb(0); + break; + case kItemReflectShots: + if (pPlayer == gMe && VanillaMode() ? true : pPlayer->packSlots[1].isActive == 0) + sfxSetReverb(0); + break; + case kItemGasMask: + pPlayer->damageControl[4]--; + break; + case kItemArmorAsbest: + pPlayer->damageControl[1]--; + break; + case kItemTwoGuns: + pPlayer->newWeapon = pPlayer->curWeapon; + WeaponRaise(pPlayer); + break; + } } -void powerupSetState(PLAYER *pPlayer, int nPowerUp, bool bState) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void powerupSetState(PLAYER* pPlayer, int nPowerUp, bool bState) { - if (!bState) - powerupActivate(pPlayer, nPowerUp); - else - powerupDeactivate(pPlayer, nPowerUp); + if (!bState) + powerupActivate(pPlayer, nPowerUp); + else + powerupDeactivate(pPlayer, nPowerUp); } -void powerupProcess(PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void powerupProcess(PLAYER* pPlayer) { - pPlayer->packItemTime = ClipLow(pPlayer->packItemTime-4, 0); - for (int i = kMaxPowerUps-1; i >= 0; i--) - { - int nPack = powerupToPackItem(i); - if (nPack >= 0) - { - if (pPlayer->packSlots[nPack].isActive) - { - pPlayer->pwUpTime[i] = ClipLow(pPlayer->pwUpTime[i]-4, 0); - if (pPlayer->pwUpTime[i]) - pPlayer->packSlots[nPack].curAmount = (100*pPlayer->pwUpTime[i])/gPowerUpInfo[i].bonusTime; - else - { - powerupDeactivate(pPlayer, i); - if (pPlayer->packItemId == nPack) - pPlayer->packItemId = 0; - } - } - } - else if (pPlayer->pwUpTime[i] > 0) - { - pPlayer->pwUpTime[i] = ClipLow(pPlayer->pwUpTime[i]-4, 0); - if (!pPlayer->pwUpTime[i]) - powerupDeactivate(pPlayer, i); - } - } + pPlayer->packItemTime = ClipLow(pPlayer->packItemTime - 4, 0); + for (int i = kMaxPowerUps - 1; i >= 0; i--) + { + int nPack = powerupToPackItem(i); + if (nPack >= 0) + { + if (pPlayer->packSlots[nPack].isActive) + { + pPlayer->pwUpTime[i] = ClipLow(pPlayer->pwUpTime[i] - 4, 0); + if (pPlayer->pwUpTime[i]) + pPlayer->packSlots[nPack].curAmount = (100 * pPlayer->pwUpTime[i]) / gPowerUpInfo[i].bonusTime; + else + { + powerupDeactivate(pPlayer, i); + if (pPlayer->packItemId == nPack) + pPlayer->packItemId = 0; + } + } + } + else if (pPlayer->pwUpTime[i] > 0) + { + pPlayer->pwUpTime[i] = ClipLow(pPlayer->pwUpTime[i] - 4, 0); + if (!pPlayer->pwUpTime[i]) + powerupDeactivate(pPlayer, i); + } + } } -void powerupClear(PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void powerupClear(PLAYER* pPlayer) { - for (int i = kMaxPowerUps-1; i >= 0; i--) - { - pPlayer->pwUpTime[i] = 0; - } + for (int i = kMaxPowerUps - 1; i >= 0; i--) + { + pPlayer->pwUpTime[i] = 0; + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + int packItemToPowerup(int nPack) { - int nPowerUp = -1; - switch (nPack) { - case 0: - break; - case 1: - nPowerUp = kPwUpDivingSuit; - break; - case 2: - nPowerUp = kPwUpCrystalBall; - break; - case 3: - nPowerUp = kPwUpBeastVision; - break; - case 4: - nPowerUp = kPwUpJumpBoots; - break; - default: - I_Error("Unhandled pack item %d", nPack); - break; - } - return nPowerUp; + int nPowerUp = -1; + switch (nPack) { + case 0: + break; + case 1: + nPowerUp = kPwUpDivingSuit; + break; + case 2: + nPowerUp = kPwUpCrystalBall; + break; + case 3: + nPowerUp = kPwUpBeastVision; + break; + case 4: + nPowerUp = kPwUpJumpBoots; + break; + default: + I_Error("Unhandled pack item %d", nPack); + break; + } + return nPowerUp; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + int powerupToPackItem(int nPowerUp) { - switch (nPowerUp) { - case kPwUpDivingSuit: - return 1; - case kPwUpCrystalBall: - return 2; - case kPwUpBeastVision: - return 3; - case kPwUpJumpBoots: - return 4; - } - return -1; + switch (nPowerUp) { + case kPwUpDivingSuit: + return 1; + case kPwUpCrystalBall: + return 2; + case kPwUpBeastVision: + return 3; + case kPwUpJumpBoots: + return 4; + } + return -1; } -bool packAddItem(PLAYER *pPlayer, unsigned int nPack) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +bool packAddItem(PLAYER* pPlayer, unsigned int nPack) { - if (nPack <= 4) - { - if (pPlayer->packSlots[nPack].curAmount >= 100) - return 0; - pPlayer->packSlots[nPack].curAmount = 100; - int nPowerUp = packItemToPowerup(nPack); - if (nPowerUp >= 0) - pPlayer->pwUpTime[nPowerUp] = gPowerUpInfo[nPowerUp].bonusTime; - if (pPlayer->packItemId == -1) - pPlayer->packItemId = nPack; - if (!pPlayer->packSlots[pPlayer->packItemId].curAmount) - pPlayer->packItemId = nPack; - } - else - I_Error("Unhandled pack item %d", nPack); - return 1; + if (nPack <= 4) + { + if (pPlayer->packSlots[nPack].curAmount >= 100) + return 0; + pPlayer->packSlots[nPack].curAmount = 100; + int nPowerUp = packItemToPowerup(nPack); + if (nPowerUp >= 0) + pPlayer->pwUpTime[nPowerUp] = gPowerUpInfo[nPowerUp].bonusTime; + if (pPlayer->packItemId == -1) + pPlayer->packItemId = nPack; + if (!pPlayer->packSlots[pPlayer->packItemId].curAmount) + pPlayer->packItemId = nPack; + } + else + I_Error("Unhandled pack item %d", nPack); + return 1; } -int packCheckItem(PLAYER *pPlayer, int nPack) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +int packCheckItem(PLAYER* pPlayer, int nPack) { - return pPlayer->packSlots[nPack].curAmount; + return pPlayer->packSlots[nPack].curAmount; } -bool packItemActive(PLAYER *pPlayer, int nPack) +bool packItemActive(PLAYER* pPlayer, int nPack) { - return pPlayer->packSlots[nPack].isActive; + return pPlayer->packSlots[nPack].isActive; } -void packUseItem(PLAYER *pPlayer, int nPack) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void packUseItem(PLAYER* pPlayer, int nPack) { - bool v4 = 0; - int nPowerUp = -1; - if (pPlayer->packSlots[nPack].curAmount > 0) - { + bool v4 = 0; + int nPowerUp = -1; + if (pPlayer->packSlots[nPack].curAmount > 0) + { pPlayer->packItemId = nPack; - switch (nPack) - { - case 0: - { - unsigned int health = pPlayer->actor->xspr.health>>4; - if (health < 100) - { - int heal = ClipHigh(100-health, pPlayer->packSlots[0].curAmount); - actHealDude(pPlayer->actor, heal, 100); - pPlayer->packSlots[0].curAmount -= heal; - } - break; - } - case 1: - v4 = 1; - nPowerUp = kPwUpDivingSuit; - break; - case 2: - v4 = 1; - nPowerUp = kPwUpCrystalBall; - break; - case 3: - v4 = 1; - nPowerUp = kPwUpBeastVision; - break; - case 4: - v4 = 1; - nPowerUp = kPwUpJumpBoots; - break; - default: - I_Error("Unhandled pack item %d", nPack); - return; - } - } - pPlayer->packItemTime = 0; - if (v4) - powerupSetState(pPlayer, nPowerUp, pPlayer->packSlots[nPack].isActive); + switch (nPack) + { + case 0: + { + unsigned int health = pPlayer->actor->xspr.health >> 4; + if (health < 100) + { + int heal = ClipHigh(100 - health, pPlayer->packSlots[0].curAmount); + actHealDude(pPlayer->actor, heal, 100); + pPlayer->packSlots[0].curAmount -= heal; + } + break; + } + case 1: + v4 = 1; + nPowerUp = kPwUpDivingSuit; + break; + case 2: + v4 = 1; + nPowerUp = kPwUpCrystalBall; + break; + case 3: + v4 = 1; + nPowerUp = kPwUpBeastVision; + break; + case 4: + v4 = 1; + nPowerUp = kPwUpJumpBoots; + break; + default: + I_Error("Unhandled pack item %d", nPack); + return; + } + } + pPlayer->packItemTime = 0; + if (v4) + powerupSetState(pPlayer, nPowerUp, pPlayer->packSlots[nPack].isActive); } -void packPrevItem(PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void packPrevItem(PLAYER* pPlayer) { - if (pPlayer->packItemTime > 0) - { - for (int i = 0; i < 2; i++) - { - for (int nPrev = pPlayer->packItemId-1; nPrev >= 0; nPrev--) - { - if (pPlayer->packSlots[nPrev].curAmount) - { - pPlayer->packItemId = nPrev; - pPlayer->packItemTime = 600; - return; - } - } - pPlayer->packItemId = 4; - if (pPlayer->packSlots[4].curAmount) break; - } - } - - pPlayer->packItemTime = 600; + if (pPlayer->packItemTime > 0) + { + for (int i = 0; i < 2; i++) + { + for (int nPrev = pPlayer->packItemId - 1; nPrev >= 0; nPrev--) + { + if (pPlayer->packSlots[nPrev].curAmount) + { + pPlayer->packItemId = nPrev; + pPlayer->packItemTime = 600; + return; + } + } + pPlayer->packItemId = 4; + if (pPlayer->packSlots[4].curAmount) break; + } + } + + pPlayer->packItemTime = 600; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void packNextItem(PLAYER* pPlayer) { - if (pPlayer->packItemTime > 0) - { - for (int i = 0; i < 2; i++) - { - for (int nNext = pPlayer->packItemId + 1; nNext < 5; nNext++) - { - if (pPlayer->packSlots[nNext].curAmount) - { - pPlayer->packItemId = nNext; - pPlayer->packItemTime = 600; - return; - } - } - pPlayer->packItemId = 0; - if (pPlayer->packSlots[0].curAmount) break; - } - } - pPlayer->packItemTime = 600; + if (pPlayer->packItemTime > 0) + { + for (int i = 0; i < 2; i++) + { + for (int nNext = pPlayer->packItemId + 1; nNext < 5; nNext++) + { + if (pPlayer->packSlots[nNext].curAmount) + { + pPlayer->packItemId = nNext; + pPlayer->packItemTime = 600; + return; + } + } + pPlayer->packItemId = 0; + if (pPlayer->packSlots[0].curAmount) break; + } + } + pPlayer->packItemTime = 600; } -bool playerSeqPlaying(PLAYER * pPlayer, int nSeq) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +bool playerSeqPlaying(PLAYER* pPlayer, int nSeq) { - int nCurSeq = seqGetID(pPlayer->actor); - if (pPlayer->pDudeInfo->seqStartID+nSeq == nCurSeq && seqGetStatus(pPlayer->actor) >= 0) - return 1; - return 0; + int nCurSeq = seqGetID(pPlayer->actor); + if (pPlayer->pDudeInfo->seqStartID + nSeq == nCurSeq && seqGetStatus(pPlayer->actor) >= 0) + return 1; + return 0; } -void playerSetRace(PLAYER *pPlayer, int nLifeMode) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void playerSetRace(PLAYER* pPlayer, int nLifeMode) { - assert(nLifeMode >= kModeHuman && nLifeMode <= kModeHumanGrown); - DUDEINFO *pDudeInfo = pPlayer->pDudeInfo; - *pDudeInfo = gPlayerTemplate[nLifeMode]; - pPlayer->lifeMode = nLifeMode; - - // By NoOne: don't forget to change clipdist for grow and shrink modes - pPlayer->actor->spr.clipdist = pDudeInfo->clipdist; - - for (int i = 0; i < 7; i++) - pDudeInfo->damageVal[i] = MulScale(Handicap[gSkill], pDudeInfo->startDamage[i], 8); + assert(nLifeMode >= kModeHuman && nLifeMode <= kModeHumanGrown); + DUDEINFO* pDudeInfo = pPlayer->pDudeInfo; + *pDudeInfo = gPlayerTemplate[nLifeMode]; + pPlayer->lifeMode = nLifeMode; + + // By NoOne: don't forget to change clipdist for grow and shrink modes + pPlayer->actor->spr.clipdist = pDudeInfo->clipdist; + + for (int i = 0; i < 7; i++) + pDudeInfo->damageVal[i] = MulScale(Handicap[gSkill], pDudeInfo->startDamage[i], 8); } -void playerSetGodMode(PLAYER *pPlayer, bool bGodMode) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void playerSetGodMode(PLAYER* pPlayer, bool bGodMode) { - pPlayer->godMode = bGodMode; + pPlayer->godMode = bGodMode; } -void playerResetInertia(PLAYER *pPlayer) +void playerResetInertia(PLAYER* pPlayer) { - POSTURE *pPosture = &pPlayer->pPosture[pPlayer->lifeMode][pPlayer->posture]; - pPlayer->zView = pPlayer->actor->spr.pos.Z-pPosture->eyeAboveZ; - pPlayer->zWeapon = pPlayer->actor->spr.pos.Z-pPosture->weaponAboveZ; - viewBackupView(pPlayer->nPlayer); + POSTURE* pPosture = &pPlayer->pPosture[pPlayer->lifeMode][pPlayer->posture]; + pPlayer->zView = pPlayer->actor->spr.pos.Z - pPosture->eyeAboveZ; + pPlayer->zWeapon = pPlayer->actor->spr.pos.Z - pPosture->weaponAboveZ; + viewBackupView(pPlayer->nPlayer); } -void playerCorrectInertia(PLAYER* pPlayer, vec3_t const *oldpos) +void playerCorrectInertia(PLAYER* pPlayer, vec3_t const* oldpos) { - pPlayer->zView += pPlayer->actor->spr.pos.Z-oldpos->Z; - pPlayer->zWeapon += pPlayer->actor->spr.pos.Z-oldpos->Z; - viewCorrectViewOffsets(pPlayer->nPlayer, oldpos); + pPlayer->zView += pPlayer->actor->spr.pos.Z - oldpos->Z; + pPlayer->zWeapon += pPlayer->actor->spr.pos.Z - oldpos->Z; + viewCorrectViewOffsets(pPlayer->nPlayer, oldpos); } void playerResetPowerUps(PLAYER* pPlayer) { - for (int i = 0; i < kMaxPowerUps; i++) { - if (!VanillaMode() && (i == kPwUpJumpBoots || i == kPwUpDivingSuit || i == kPwUpCrystalBall || i == kPwUpBeastVision)) - continue; - pPlayer->pwUpTime[i] = 0; - } + for (int i = 0; i < kMaxPowerUps; i++) { + if (!VanillaMode() && (i == kPwUpJumpBoots || i == kPwUpDivingSuit || i == kPwUpCrystalBall || i == kPwUpBeastVision)) + continue; + pPlayer->pwUpTime[i] = 0; + } } void playerResetPosture(PLAYER* pPlayer) { - memcpy(pPlayer->pPosture, gPostureDefaults, sizeof(gPostureDefaults)); + memcpy(pPlayer->pPosture, gPostureDefaults, sizeof(gPostureDefaults)); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void playerStart(int nPlayer, int bNewLevel) { - PLAYER* pPlayer = &gPlayer[nPlayer]; - InputPacket* pInput = &pPlayer->input; - ZONE* pStartZone = NULL; + PLAYER* pPlayer = &gPlayer[nPlayer]; + InputPacket* pInput = &pPlayer->input; + ZONE* pStartZone = NULL; - // normal start position - if (gGameOptions.nGameType <= 1) - pStartZone = &gStartZone[nPlayer]; - - #ifdef NOONE_EXTENSIONS - // let's check if there is positions of teams is specified - // if no, pick position randomly, just like it works in vanilla. - else if (gModernMap && gGameOptions.nGameType == 3 && gTeamsSpawnUsed == true) { - int maxRetries = 5; - while (maxRetries-- > 0) { - if (pPlayer->teamId == 0) pStartZone = &gStartZoneTeam1[Random(3)]; - else pStartZone = &gStartZoneTeam2[Random(3)]; + // normal start position + if (gGameOptions.nGameType <= 1) + pStartZone = &gStartZone[nPlayer]; - if (maxRetries != 0) { - // check if there is no spawned player in selected zone - BloodSectIterator it(pStartZone->sector); - while (auto act = it.Next()) - { - if (pStartZone->x == act->spr.pos.X && pStartZone->y == act->spr.pos.Y && act->IsPlayerActor()) { - pStartZone = NULL; - break; - } - } - } +#ifdef NOONE_EXTENSIONS + // let's check if there is positions of teams is specified + // if no, pick position randomly, just like it works in vanilla. + else if (gModernMap && gGameOptions.nGameType == 3 && gTeamsSpawnUsed == true) { + int maxRetries = 5; + while (maxRetries-- > 0) { + if (pPlayer->teamId == 0) pStartZone = &gStartZoneTeam1[Random(3)]; + else pStartZone = &gStartZoneTeam2[Random(3)]; - if (pStartZone != NULL) - break; - } - - } - #endif - else { - pStartZone = &gStartZone[Random(8)]; - } + if (maxRetries != 0) { + // check if there is no spawned player in selected zone + BloodSectIterator it(pStartZone->sector); + while (auto act = it.Next()) + { + if (pStartZone->x == act->spr.pos.X && pStartZone->y == act->spr.pos.Y && act->IsPlayerActor()) { + pStartZone = NULL; + break; + } + } + } - auto actor = actSpawnSprite(pStartZone->sector, pStartZone->x, pStartZone->y, pStartZone->z, 6, 1); - assert(actor->hasX()); - pPlayer->actor = actor; - DUDEINFO *pDudeInfo = &dudeInfo[kDudePlayer1 + nPlayer - kDudeBase]; - pPlayer->pDudeInfo = pDudeInfo; - playerSetRace(pPlayer, kModeHuman); - playerResetPosture(pPlayer); - seqSpawn(pDudeInfo->seqStartID, actor, -1); - if (pPlayer == gMe) - actor->spr.cstat2 |= CSTAT2_SPRITE_MAPPED; - int top, bottom; - GetActorExtents(actor, &top, &bottom); - actor->spr.pos.Z -= bottom - actor->spr.pos.Z; - actor->spr.pal = 11+(pPlayer->teamId&3); - actor->spr.ang = pStartZone->ang; - pPlayer->angle.ang = buildang(actor->spr.ang); - actor->spr.type = kDudePlayer1+nPlayer; - actor->spr.clipdist = pDudeInfo->clipdist; - actor->spr.flags = 15; - actor->xspr.burnTime = 0; - actor->SetBurnSource(nullptr); - pPlayer->actor->xspr.health = pDudeInfo->startHealth<<4; - pPlayer->actor->spr.cstat &= ~CSTAT_SPRITE_INVISIBLE; - pPlayer->bloodlust = 0; - pPlayer->horizon.horiz = pPlayer->horizon.horizoff = q16horiz(0); - pPlayer->slope = 0; - pPlayer->fragger = nullptr; - pPlayer->underwaterTime = 1200; - pPlayer->bubbleTime = 0; - pPlayer->restTime = 0; - pPlayer->kickPower = 0; - pPlayer->laughCount = 0; - pPlayer->angle.spin = 0; - pPlayer->posture = 0; - pPlayer->voodooTarget = nullptr; - pPlayer->voodooTargets = 0; - pPlayer->voodooVar1 = 0; - pPlayer->vodooVar2 = 0; - playerResetInertia(pPlayer); - pPlayer->zWeaponVel = 0; - pPlayer->relAim.dx = 0x4000; - pPlayer->relAim.dy = 0; - pPlayer->relAim.dz = 0; - pPlayer->aimTarget = nullptr; - pPlayer->zViewVel = pPlayer->zWeaponVel; - if (!(gGameOptions.nGameType == 1 && gGameOptions.bKeepKeysOnRespawn && !bNewLevel)) - for (int i = 0; i < 8; i++) - pPlayer->hasKey[i] = gGameOptions.nGameType >= 2; - pPlayer->hasFlag = 0; - for (int i = 0; i < 2; i++) - pPlayer->ctfFlagState[i] = nullptr; - for (int i = 0; i < 7; i++) - pPlayer->damageControl[i] = 0; - if (pPlayer->godMode) - playerSetGodMode(pPlayer, 1); - gInfiniteAmmo = 0; - gFullMap = 0; - pPlayer->throwPower = 0; - pPlayer->deathTime = 0; - pPlayer->nextWeapon = kWeapNone; - actor->xvel = actor->yvel = actor->zvel = 0; - pInput->avel = 0; - pInput->actions = 0; - pInput->fvel = 0; - pInput->svel = 0; - pInput->horz = 0; - pPlayer->flickerEffect = 0; - pPlayer->quakeEffect = 0; - pPlayer->tiltEffect = 0; - pPlayer->visibility = 0; - pPlayer->painEffect = 0; - pPlayer->blindEffect = 0; - pPlayer->chokeEffect = 0; - pPlayer->handTime = 0; - pPlayer->weaponTimer = 0; - pPlayer->weaponState = 0; - pPlayer->weaponQav = kQAVNone; - pPlayer->qavLastTick = 0; - pPlayer->qavTimer = 0; - #ifdef NOONE_EXTENSIONS - playerQavSceneReset(pPlayer); // reset qav scene - - // assign or update player's sprite index for conditions - if (gModernMap) { + if (pStartZone != NULL) + break; + } - BloodStatIterator it(kStatModernPlayerLinker); - while (auto iactor = it.Next()) - { - if (iactor->xspr.data1 == pPlayer->nPlayer + 1) - { - DBloodActor* SpriteOld = iactor->prevmarker; - trPlayerCtrlLink(iactor, pPlayer, (SpriteOld == nullptr)); // this modifies iactor's prevmarker field! - if (SpriteOld) - condUpdateObjectIndex(SpriteOld, iactor->prevmarker); - } - } + } +#endif + else { + pStartZone = &gStartZone[Random(8)]; + } - } + auto actor = actSpawnSprite(pStartZone->sector, pStartZone->x, pStartZone->y, pStartZone->z, 6, 1); + assert(actor->hasX()); + pPlayer->actor = actor; + DUDEINFO* pDudeInfo = &dudeInfo[kDudePlayer1 + nPlayer - kDudeBase]; + pPlayer->pDudeInfo = pDudeInfo; + playerSetRace(pPlayer, kModeHuman); + playerResetPosture(pPlayer); + seqSpawn(pDudeInfo->seqStartID, actor, -1); + if (pPlayer == gMe) + actor->spr.cstat2 |= CSTAT2_SPRITE_MAPPED; + int top, bottom; + GetActorExtents(actor, &top, &bottom); + actor->spr.pos.Z -= bottom - actor->spr.pos.Z; + actor->spr.pal = 11 + (pPlayer->teamId & 3); + actor->spr.ang = pStartZone->ang; + pPlayer->angle.ang = buildang(actor->spr.ang); + actor->spr.type = kDudePlayer1 + nPlayer; + actor->spr.clipdist = pDudeInfo->clipdist; + actor->spr.flags = 15; + actor->xspr.burnTime = 0; + actor->SetBurnSource(nullptr); + pPlayer->actor->xspr.health = pDudeInfo->startHealth << 4; + pPlayer->actor->spr.cstat &= ~CSTAT_SPRITE_INVISIBLE; + pPlayer->bloodlust = 0; + pPlayer->horizon.horiz = pPlayer->horizon.horizoff = q16horiz(0); + pPlayer->slope = 0; + pPlayer->fragger = nullptr; + pPlayer->underwaterTime = 1200; + pPlayer->bubbleTime = 0; + pPlayer->restTime = 0; + pPlayer->kickPower = 0; + pPlayer->laughCount = 0; + pPlayer->angle.spin = 0; + pPlayer->posture = 0; + pPlayer->voodooTarget = nullptr; + pPlayer->voodooTargets = 0; + pPlayer->voodooVar1 = 0; + pPlayer->vodooVar2 = 0; + playerResetInertia(pPlayer); + pPlayer->zWeaponVel = 0; + pPlayer->relAim.dx = 0x4000; + pPlayer->relAim.dy = 0; + pPlayer->relAim.dz = 0; + pPlayer->aimTarget = nullptr; + pPlayer->zViewVel = pPlayer->zWeaponVel; + if (!(gGameOptions.nGameType == 1 && gGameOptions.bKeepKeysOnRespawn && !bNewLevel)) + for (int i = 0; i < 8; i++) + pPlayer->hasKey[i] = gGameOptions.nGameType >= 2; + pPlayer->hasFlag = 0; + for (int i = 0; i < 2; i++) + pPlayer->ctfFlagState[i] = nullptr; + for (int i = 0; i < 7; i++) + pPlayer->damageControl[i] = 0; + if (pPlayer->godMode) + playerSetGodMode(pPlayer, 1); + gInfiniteAmmo = 0; + gFullMap = 0; + pPlayer->throwPower = 0; + pPlayer->deathTime = 0; + pPlayer->nextWeapon = kWeapNone; + actor->xvel = actor->yvel = actor->zvel = 0; + pInput->avel = 0; + pInput->actions = 0; + pInput->fvel = 0; + pInput->svel = 0; + pInput->horz = 0; + pPlayer->flickerEffect = 0; + pPlayer->quakeEffect = 0; + pPlayer->tiltEffect = 0; + pPlayer->visibility = 0; + pPlayer->painEffect = 0; + pPlayer->blindEffect = 0; + pPlayer->chokeEffect = 0; + pPlayer->handTime = 0; + pPlayer->weaponTimer = 0; + pPlayer->weaponState = 0; + pPlayer->weaponQav = kQAVNone; + pPlayer->qavLastTick = 0; + pPlayer->qavTimer = 0; +#ifdef NOONE_EXTENSIONS + playerQavSceneReset(pPlayer); // reset qav scene - #endif - pPlayer->hand = 0; - pPlayer->nWaterPal = 0; - playerResetPowerUps(pPlayer); + // assign or update player's sprite index for conditions + if (gModernMap) { - if (pPlayer == gMe) - { - viewInitializePrediction(); - } - if (IsUnderwaterSector(actor->spr.sector())) - { - pPlayer->posture = 1; - pPlayer->actor->xspr.medium = kMediumWater; - } + BloodStatIterator it(kStatModernPlayerLinker); + while (auto iactor = it.Next()) + { + if (iactor->xspr.data1 == pPlayer->nPlayer + 1) + { + DBloodActor* SpriteOld = iactor->prevmarker; + trPlayerCtrlLink(iactor, pPlayer, (SpriteOld == nullptr)); // this modifies iactor's prevmarker field! + if (SpriteOld) + condUpdateObjectIndex(SpriteOld, iactor->prevmarker); + } + } + + } + +#endif + pPlayer->hand = 0; + pPlayer->nWaterPal = 0; + playerResetPowerUps(pPlayer); + + if (pPlayer == gMe) + { + viewInitializePrediction(); + } + if (IsUnderwaterSector(actor->spr.sector())) + { + pPlayer->posture = 1; + pPlayer->actor->xspr.medium = kMediumWater; + } } -void playerReset(PLAYER *pPlayer) -{ - static int dword_136400[] = { - 3, 4, 2, 8, 9, 10, 7, 1, 1, 1, 1, 1, 1, 1 - }; - static int dword_136438[] = { - 3, 4, 2, 8, 9, 10, 7, 1, 1, 1, 1, 1, 1, 1 - }; - assert(pPlayer != NULL); - for (int i = 0; i < 14; i++) - { - pPlayer->hasWeapon[i] = gInfiniteAmmo; - pPlayer->weaponMode[i] = 0; - } - pPlayer->hasWeapon[1] = 1; - pPlayer->curWeapon = kWeapNone; - pPlayer->qavCallback = -1; - pPlayer->newWeapon = kWeapPitchFork; - for (int i = 0; i < 14; i++) - { - pPlayer->weaponOrder[0][i] = dword_136400[i]; - pPlayer->weaponOrder[1][i] = dword_136438[i]; - } - for (int i = 0; i < 12; i++) - { - if (gInfiniteAmmo) - pPlayer->ammoCount[i] = gAmmoInfo[i].max; - else - pPlayer->ammoCount[i] = 0; - } - for (int i = 0; i < 3; i++) - pPlayer->armor[i] = 0; - pPlayer->weaponTimer = 0; - pPlayer->weaponState = 0; - pPlayer->weaponQav = kQAVNone; - pPlayer->qavLoop = 0; - pPlayer->qavLastTick = 0; - pPlayer->qavTimer = 0; - pPlayer->packItemId = -1; +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- - for (int i = 0; i < 5; i++) { - pPlayer->packSlots[i].isActive = 0; - pPlayer->packSlots[i].curAmount = 0; - } - #ifdef NOONE_EXTENSIONS - playerQavSceneReset(pPlayer); - #endif - // reset posture (mainly required for resetting movement speed and jump height) - playerResetPosture(pPlayer); +void playerReset(PLAYER* pPlayer) +{ + static int dword_136400[] = { + 3, 4, 2, 8, 9, 10, 7, 1, 1, 1, 1, 1, 1, 1 + }; + static int dword_136438[] = { + 3, 4, 2, 8, 9, 10, 7, 1, 1, 1, 1, 1, 1, 1 + }; + assert(pPlayer != NULL); + for (int i = 0; i < 14; i++) + { + pPlayer->hasWeapon[i] = gInfiniteAmmo; + pPlayer->weaponMode[i] = 0; + } + pPlayer->hasWeapon[1] = 1; + pPlayer->curWeapon = kWeapNone; + pPlayer->qavCallback = -1; + pPlayer->newWeapon = kWeapPitchFork; + for (int i = 0; i < 14; i++) + { + pPlayer->weaponOrder[0][i] = dword_136400[i]; + pPlayer->weaponOrder[1][i] = dword_136438[i]; + } + for (int i = 0; i < 12; i++) + { + if (gInfiniteAmmo) + pPlayer->ammoCount[i] = gAmmoInfo[i].max; + else + pPlayer->ammoCount[i] = 0; + } + for (int i = 0; i < 3; i++) + pPlayer->armor[i] = 0; + pPlayer->weaponTimer = 0; + pPlayer->weaponState = 0; + pPlayer->weaponQav = kQAVNone; + pPlayer->qavLoop = 0; + pPlayer->qavLastTick = 0; + pPlayer->qavTimer = 0; + pPlayer->packItemId = -1; + + for (int i = 0; i < 5; i++) { + pPlayer->packSlots[i].isActive = 0; + pPlayer->packSlots[i].curAmount = 0; + } +#ifdef NOONE_EXTENSIONS + playerQavSceneReset(pPlayer); +#endif + // reset posture (mainly required for resetting movement speed and jump height) + playerResetPosture(pPlayer); } int team_score[8]; int team_ticker[8]; +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void playerInit(int nPlayer, unsigned int a2) { - if (!(a2&1)) - gPlayer[nPlayer] = {}; + if (!(a2 & 1)) + gPlayer[nPlayer] = {}; - PLAYER *pPlayer = &gPlayer[nPlayer]; - pPlayer->nPlayer = nPlayer; - pPlayer->teamId = nPlayer; - if (gGameOptions.nGameType == 3) - pPlayer->teamId = nPlayer&1; - pPlayer->fragCount = 0; - memset(team_score, 0, sizeof(team_score)); - memset(team_ticker, 0, sizeof(team_ticker)); - memset(pPlayer->fragInfo, 0, sizeof(pPlayer->fragInfo)); + PLAYER* pPlayer = &gPlayer[nPlayer]; + pPlayer->nPlayer = nPlayer; + pPlayer->teamId = nPlayer; + if (gGameOptions.nGameType == 3) + pPlayer->teamId = nPlayer & 1; + pPlayer->fragCount = 0; + memset(team_score, 0, sizeof(team_score)); + memset(team_ticker, 0, sizeof(team_ticker)); + memset(pPlayer->fragInfo, 0, sizeof(pPlayer->fragInfo)); - if (!(a2&1)) - playerReset(pPlayer); + if (!(a2 & 1)) + playerReset(pPlayer); } -bool findDroppedLeech(PLAYER *a1, DBloodActor *a2) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +bool findDroppedLeech(PLAYER* a1, DBloodActor* a2) { - BloodStatIterator it(kStatThing); - while (auto actor = it.Next()) - { - if (a2 == actor) - continue; - if (actor->spr.type == kThingDroppedLifeLeech && actor->GetOwner() == a1->actor) - return 1; - } - return 0; + BloodStatIterator it(kStatThing); + while (auto actor = it.Next()) + { + if (a2 == actor) + continue; + if (actor->spr.type == kThingDroppedLifeLeech && actor->GetOwner() == a1->actor) + return 1; + } + return 0; } -bool PickupItem(PLAYER *pPlayer, DBloodActor* itemactor) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +bool PickupItem(PLAYER* pPlayer, DBloodActor* itemactor) { - char buffer[80]; + char buffer[80]; int pickupSnd = 775; int nType = itemactor->spr.type - kItemBase; - auto plActor = pPlayer->actor; + auto plActor = pPlayer->actor; - switch (itemactor->spr.type) { - case kItemShadowCloak: - #ifdef NOONE_EXTENSIONS - if (isGrown(pPlayer->actor) || !powerupActivate(pPlayer, nType)) return false; - #else - if (!powerupActivate(pPlayer, nType)) return false; - #endif - break; - #ifdef NOONE_EXTENSIONS - case kItemShroomShrink: - case kItemShroomGrow: - - if (gModernMap) { - switch (itemactor->spr.type) { - case kItemShroomShrink: - if (isShrinked(pPlayer->actor)) return false; - break; - case kItemShroomGrow: - if (isGrown(pPlayer->actor)) return false; - break; - } + switch (itemactor->spr.type) { + case kItemShadowCloak: +#ifdef NOONE_EXTENSIONS + if (isGrown(pPlayer->actor) || !powerupActivate(pPlayer, nType)) return false; +#else + if (!powerupActivate(pPlayer, nType)) return false; +#endif + break; +#ifdef NOONE_EXTENSIONS + case kItemShroomShrink: + case kItemShroomGrow: - powerupActivate(pPlayer, nType); - } - - break; - #endif - case kItemFlagABase: - case kItemFlagBBase: { - if (gGameOptions.nGameType != 3 || !itemactor->hasX()) return 0; - if (itemactor->spr.type == kItemFlagABase) { - if (pPlayer->teamId == 1) { - if ((pPlayer->hasFlag & 1) == 0 && itemactor->xspr.state) { - pPlayer->hasFlag |= 1; - pPlayer->ctfFlagState[0] = itemactor; - trTriggerSprite(itemactor, kCmdOff); - sprintf(buffer, "%s stole Blue Flag", PlayerName(pPlayer->nPlayer)); - sndStartSample(8007, 255, 2, 0); - viewSetMessage(buffer); - } - } + if (gModernMap) { + switch (itemactor->spr.type) { + case kItemShroomShrink: + if (isShrinked(pPlayer->actor)) return false; + break; + case kItemShroomGrow: + if (isGrown(pPlayer->actor)) return false; + break; + } - if (pPlayer->teamId == 0) { + powerupActivate(pPlayer, nType); + } - if ((pPlayer->hasFlag & 1) != 0 && !itemactor->xspr.state) { - pPlayer->hasFlag &= ~1; - pPlayer->ctfFlagState[0] = nullptr; - trTriggerSprite(itemactor, kCmdOn); - sprintf(buffer, "%s returned Blue Flag", PlayerName(pPlayer->nPlayer)); - sndStartSample(8003, 255, 2, 0); - viewSetMessage(buffer); - } + break; +#endif + case kItemFlagABase: + case kItemFlagBBase: { + if (gGameOptions.nGameType != 3 || !itemactor->hasX()) return 0; + if (itemactor->spr.type == kItemFlagABase) { + if (pPlayer->teamId == 1) { + if ((pPlayer->hasFlag & 1) == 0 && itemactor->xspr.state) { + pPlayer->hasFlag |= 1; + pPlayer->ctfFlagState[0] = itemactor; + trTriggerSprite(itemactor, kCmdOff); + sprintf(buffer, "%s stole Blue Flag", PlayerName(pPlayer->nPlayer)); + sndStartSample(8007, 255, 2, 0); + viewSetMessage(buffer); + } + } - if ((pPlayer->hasFlag & 2) != 0 && itemactor->xspr.state) { - pPlayer->hasFlag &= ~2; - pPlayer->ctfFlagState[1] = nullptr; - team_score[pPlayer->teamId] += 10; - team_ticker[pPlayer->teamId] += 240; - evSendGame(81, kCmdOn); - sprintf(buffer, "%s captured Red Flag!", PlayerName(pPlayer->nPlayer)); - sndStartSample(8001, 255, 2, 0); - viewSetMessage(buffer); - } - } + if (pPlayer->teamId == 0) { - } - else if (itemactor->spr.type == kItemFlagBBase) { + if ((pPlayer->hasFlag & 1) != 0 && !itemactor->xspr.state) { + pPlayer->hasFlag &= ~1; + pPlayer->ctfFlagState[0] = nullptr; + trTriggerSprite(itemactor, kCmdOn); + sprintf(buffer, "%s returned Blue Flag", PlayerName(pPlayer->nPlayer)); + sndStartSample(8003, 255, 2, 0); + viewSetMessage(buffer); + } - if (pPlayer->teamId == 0) { - if ((pPlayer->hasFlag & 2) == 0 && itemactor->xspr.state) { - pPlayer->hasFlag |= 2; - pPlayer->ctfFlagState[1] = itemactor; - trTriggerSprite(itemactor, kCmdOff); - sprintf(buffer, "%s stole Red Flag", PlayerName(pPlayer->nPlayer)); - sndStartSample(8006, 255, 2, 0); - viewSetMessage(buffer); - } - } + if ((pPlayer->hasFlag & 2) != 0 && itemactor->xspr.state) { + pPlayer->hasFlag &= ~2; + pPlayer->ctfFlagState[1] = nullptr; + team_score[pPlayer->teamId] += 10; + team_ticker[pPlayer->teamId] += 240; + evSendGame(81, kCmdOn); + sprintf(buffer, "%s captured Red Flag!", PlayerName(pPlayer->nPlayer)); + sndStartSample(8001, 255, 2, 0); + viewSetMessage(buffer); + } + } - if (pPlayer->teamId == 1) { - if ((pPlayer->hasFlag & 2) != 0 && !itemactor->xspr.state) - { - pPlayer->hasFlag &= ~2; - pPlayer->ctfFlagState[1] = nullptr; - trTriggerSprite(itemactor, kCmdOn); - sprintf(buffer, "%s returned Red Flag", PlayerName(pPlayer->nPlayer)); - sndStartSample(8002, 255, 2, 0); - viewSetMessage(buffer); - } - if ((pPlayer->hasFlag & 1) != 0 && itemactor->xspr.state) - { - pPlayer->hasFlag &= ~1; - pPlayer->ctfFlagState[0] = nullptr; - team_score[pPlayer->teamId] += 10; - team_ticker[pPlayer->teamId] += 240; - evSendGame(80, kCmdOn); - sprintf(buffer, "%s captured Blue Flag!", PlayerName(pPlayer->nPlayer)); - sndStartSample(8000, 255, 2, 0); - viewSetMessage(buffer); - } - } - } - } - return 0; - case kItemFlagA: { - if (gGameOptions.nGameType != 3) return 0; - gBlueFlagDropped = false; - const bool enemyTeam = (pPlayer->teamId&1) == 1; - if (!enemyTeam && itemactor->GetOwner()) - { - pPlayer->hasFlag &= ~1; - pPlayer->ctfFlagState[0] = nullptr; - trTriggerSprite(itemactor->GetOwner(), kCmdOn); - sprintf(buffer, "%s returned Blue Flag", PlayerName(pPlayer->nPlayer)); - sndStartSample(8003, 255, 2, 0); - viewSetMessage(buffer); - break; - } - pPlayer->hasFlag |= 1; - pPlayer->ctfFlagState[0] = itemactor->GetOwner(); - 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; - gRedFlagDropped = false; - const bool enemyTeam = (pPlayer->teamId&1) == 0; - if (!enemyTeam && itemactor->GetOwner()) - { - pPlayer->hasFlag &= ~2; - pPlayer->ctfFlagState[1] = nullptr; - trTriggerSprite(itemactor->GetOwner(), kCmdOn); - sprintf(buffer, "%s returned Red Flag", PlayerName(pPlayer->nPlayer)); - sndStartSample(8002, 255, 2, 0); - viewSetMessage(buffer); - break; - } - pPlayer->hasFlag |= 2; - pPlayer->ctfFlagState[1] = itemactor->GetOwner(); - 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: - case kItemArmorSpirit: - case kItemArmorSuper: { - ARMORDATA *pArmorData = &armorData[itemactor->spr.type - kItemArmorBasic]; bool pickedUp = false; - if (pPlayer->armor[1] < pArmorData->armor1max) { - pPlayer->armor[1] = ClipHigh(pPlayer->armor[1]+pArmorData->armor1, pArmorData->armor1max); - pickedUp = true; - } - - if (pPlayer->armor[0] < pArmorData->armor0max) { - pPlayer->armor[0] = ClipHigh(pPlayer->armor[0]+pArmorData->armor0, pArmorData->armor0max); - pickedUp = true; - } + } + else if (itemactor->spr.type == kItemFlagBBase) { - if (pPlayer->armor[2] < pArmorData->armor2max) { - pPlayer->armor[2] = ClipHigh(pPlayer->armor[2]+pArmorData->armor2, pArmorData->armor2max); - pickedUp = true; - } - - if (!pickedUp) return 0; - pickupSnd = 779; - break; - } - case kItemCrystalBall: - if (gGameOptions.nGameType == 0 || !packAddItem(pPlayer, gItemData[nType].packSlot)) return 0; - break; - case kItemKeySkull: - case kItemKeyEye: - case kItemKeyFire: - case kItemKeyDagger: - case kItemKeySpider: - case kItemKeyMoon: - case kItemKeyKey7: - if (pPlayer->hasKey[itemactor->spr.type-99]) return 0; - pPlayer->hasKey[itemactor->spr.type-99] = 1; - pickupSnd = 781; - break; - case kItemHealthMedPouch: - case kItemHealthLifeEssense: - case kItemHealthLifeSeed: - case kItemHealthRedPotion: { - int addPower = gPowerUpInfo[nType].bonusTime; - #ifdef NOONE_EXTENSIONS - // allow custom amount for item - if (gModernMap && itemactor->hasX() && itemactor->xspr.data1 > 0) - addPower = itemactor->xspr.data1; - #endif - - if (!actHealDude(pPlayer->actor, addPower, gPowerUpInfo[nType].maxTime)) return 0; - return 1; - } - case kItemHealthDoctorBag: - case kItemJumpBoots: - case kItemDivingSuit: - case kItemBeastVision: - if (!packAddItem(pPlayer, gItemData[nType].packSlot)) return 0; - break; - default: - if (!powerupActivate(pPlayer, nType)) return 0; - return 1; - } - - sfxPlay3DSound(plActor->spr.pos.X, plActor->spr.pos.Y, plActor->spr.pos.Z, pickupSnd, plActor->spr.sector()); - return 1; + if (pPlayer->teamId == 0) { + if ((pPlayer->hasFlag & 2) == 0 && itemactor->xspr.state) { + pPlayer->hasFlag |= 2; + pPlayer->ctfFlagState[1] = itemactor; + trTriggerSprite(itemactor, kCmdOff); + sprintf(buffer, "%s stole Red Flag", PlayerName(pPlayer->nPlayer)); + sndStartSample(8006, 255, 2, 0); + viewSetMessage(buffer); + } + } + + if (pPlayer->teamId == 1) { + if ((pPlayer->hasFlag & 2) != 0 && !itemactor->xspr.state) + { + pPlayer->hasFlag &= ~2; + pPlayer->ctfFlagState[1] = nullptr; + trTriggerSprite(itemactor, kCmdOn); + sprintf(buffer, "%s returned Red Flag", PlayerName(pPlayer->nPlayer)); + sndStartSample(8002, 255, 2, 0); + viewSetMessage(buffer); + } + if ((pPlayer->hasFlag & 1) != 0 && itemactor->xspr.state) + { + pPlayer->hasFlag &= ~1; + pPlayer->ctfFlagState[0] = nullptr; + team_score[pPlayer->teamId] += 10; + team_ticker[pPlayer->teamId] += 240; + evSendGame(80, kCmdOn); + sprintf(buffer, "%s captured Blue Flag!", PlayerName(pPlayer->nPlayer)); + sndStartSample(8000, 255, 2, 0); + viewSetMessage(buffer); + } + } + } + } + return 0; + case kItemFlagA: { + if (gGameOptions.nGameType != 3) return 0; + gBlueFlagDropped = false; + const bool enemyTeam = (pPlayer->teamId & 1) == 1; + if (!enemyTeam && itemactor->GetOwner()) + { + pPlayer->hasFlag &= ~1; + pPlayer->ctfFlagState[0] = nullptr; + trTriggerSprite(itemactor->GetOwner(), kCmdOn); + sprintf(buffer, "%s returned Blue Flag", PlayerName(pPlayer->nPlayer)); + sndStartSample(8003, 255, 2, 0); + viewSetMessage(buffer); + break; + } + pPlayer->hasFlag |= 1; + pPlayer->ctfFlagState[0] = itemactor->GetOwner(); + 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; + gRedFlagDropped = false; + const bool enemyTeam = (pPlayer->teamId & 1) == 0; + if (!enemyTeam && itemactor->GetOwner()) + { + pPlayer->hasFlag &= ~2; + pPlayer->ctfFlagState[1] = nullptr; + trTriggerSprite(itemactor->GetOwner(), kCmdOn); + sprintf(buffer, "%s returned Red Flag", PlayerName(pPlayer->nPlayer)); + sndStartSample(8002, 255, 2, 0); + viewSetMessage(buffer); + break; + } + pPlayer->hasFlag |= 2; + pPlayer->ctfFlagState[1] = itemactor->GetOwner(); + 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: + case kItemArmorSpirit: + case kItemArmorSuper: { + ARMORDATA* pArmorData = &armorData[itemactor->spr.type - kItemArmorBasic]; bool pickedUp = false; + if (pPlayer->armor[1] < pArmorData->armor1max) { + pPlayer->armor[1] = ClipHigh(pPlayer->armor[1] + pArmorData->armor1, pArmorData->armor1max); + pickedUp = true; + } + + if (pPlayer->armor[0] < pArmorData->armor0max) { + pPlayer->armor[0] = ClipHigh(pPlayer->armor[0] + pArmorData->armor0, pArmorData->armor0max); + pickedUp = true; + } + + if (pPlayer->armor[2] < pArmorData->armor2max) { + pPlayer->armor[2] = ClipHigh(pPlayer->armor[2] + pArmorData->armor2, pArmorData->armor2max); + pickedUp = true; + } + + if (!pickedUp) return 0; + pickupSnd = 779; + break; + } + case kItemCrystalBall: + if (gGameOptions.nGameType == 0 || !packAddItem(pPlayer, gItemData[nType].packSlot)) return 0; + break; + case kItemKeySkull: + case kItemKeyEye: + case kItemKeyFire: + case kItemKeyDagger: + case kItemKeySpider: + case kItemKeyMoon: + case kItemKeyKey7: + if (pPlayer->hasKey[itemactor->spr.type - 99]) return 0; + pPlayer->hasKey[itemactor->spr.type - 99] = 1; + pickupSnd = 781; + break; + case kItemHealthMedPouch: + case kItemHealthLifeEssense: + case kItemHealthLifeSeed: + case kItemHealthRedPotion: { + int addPower = gPowerUpInfo[nType].bonusTime; +#ifdef NOONE_EXTENSIONS + // allow custom amount for item + if (gModernMap && itemactor->hasX() && itemactor->xspr.data1 > 0) + addPower = itemactor->xspr.data1; +#endif + + if (!actHealDude(pPlayer->actor, addPower, gPowerUpInfo[nType].maxTime)) return 0; + return 1; + } + case kItemHealthDoctorBag: + case kItemJumpBoots: + case kItemDivingSuit: + case kItemBeastVision: + if (!packAddItem(pPlayer, gItemData[nType].packSlot)) return 0; + break; + default: + if (!powerupActivate(pPlayer, nType)) return 0; + return 1; + } + + sfxPlay3DSound(plActor->spr.pos.X, plActor->spr.pos.Y, plActor->spr.pos.Z, pickupSnd, plActor->spr.sector()); + return 1; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + bool PickupAmmo(PLAYER* pPlayer, DBloodActor* ammoactor) { - const AMMOITEMDATA* pAmmoItemData = &gAmmoItemData[ammoactor->spr.type - kItemAmmoBase]; - int nAmmoType = pAmmoItemData->type; + const AMMOITEMDATA* pAmmoItemData = &gAmmoItemData[ammoactor->spr.type - kItemAmmoBase]; + int nAmmoType = pAmmoItemData->type; - if (pPlayer->ammoCount[nAmmoType] >= gAmmoInfo[nAmmoType].max) return 0; - #ifdef NOONE_EXTENSIONS - else if (gModernMap && ammoactor->hasX() && ammoactor->xspr.data1 > 0) // allow custom amount for item - pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + ammoactor->xspr.data1, gAmmoInfo[nAmmoType].max); - #endif - else - pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType]+pAmmoItemData->count, gAmmoInfo[nAmmoType].max); + if (pPlayer->ammoCount[nAmmoType] >= gAmmoInfo[nAmmoType].max) return 0; +#ifdef NOONE_EXTENSIONS + else if (gModernMap && ammoactor->hasX() && ammoactor->xspr.data1 > 0) // allow custom amount for item + pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + ammoactor->xspr.data1, gAmmoInfo[nAmmoType].max); +#endif + else + pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + pAmmoItemData->count, gAmmoInfo[nAmmoType].max); - if (pAmmoItemData->weaponType) pPlayer->hasWeapon[pAmmoItemData->weaponType] = 1; - sfxPlay3DSound(pPlayer->actor, 782, -1, 0); - return 1; + if (pAmmoItemData->weaponType) pPlayer->hasWeapon[pAmmoItemData->weaponType] = 1; + sfxPlay3DSound(pPlayer->actor, 782, -1, 0); + return 1; } -bool PickupWeapon(PLAYER *pPlayer, DBloodActor* weaponactor) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +bool PickupWeapon(PLAYER* pPlayer, DBloodActor* weaponactor) { - const WEAPONITEMDATA *pWeaponItemData = &gWeaponItemData[weaponactor->spr.type - kItemWeaponBase]; - int nWeaponType = pWeaponItemData->type; - int nAmmoType = pWeaponItemData->ammoType; - if (!pPlayer->hasWeapon[nWeaponType] || gGameOptions.nWeaponSettings == 2 || gGameOptions.nWeaponSettings == 3) { - if (weaponactor->spr.type == kItemWeaponLifeLeech && gGameOptions.nGameType > 1 && findDroppedLeech(pPlayer, NULL)) - return 0; - pPlayer->hasWeapon[nWeaponType] = 1; - if (nAmmoType == -1) return 0; - // allow to set custom ammo count for weapon pickups - #ifdef NOONE_EXTENSIONS - else if (gModernMap && weaponactor->hasX() && weaponactor->xspr.data1 > 0) - pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + weaponactor->xspr.data1, gAmmoInfo[nAmmoType].max); - #endif - else - pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + pWeaponItemData->count, gAmmoInfo[nAmmoType].max); + const WEAPONITEMDATA* pWeaponItemData = &gWeaponItemData[weaponactor->spr.type - kItemWeaponBase]; + int nWeaponType = pWeaponItemData->type; + int nAmmoType = pWeaponItemData->ammoType; + if (!pPlayer->hasWeapon[nWeaponType] || gGameOptions.nWeaponSettings == 2 || gGameOptions.nWeaponSettings == 3) { + if (weaponactor->spr.type == kItemWeaponLifeLeech && gGameOptions.nGameType > 1 && findDroppedLeech(pPlayer, NULL)) + return 0; + pPlayer->hasWeapon[nWeaponType] = 1; + if (nAmmoType == -1) return 0; + // allow to set custom ammo count for weapon pickups +#ifdef NOONE_EXTENSIONS + else if (gModernMap && weaponactor->hasX() && weaponactor->xspr.data1 > 0) + pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + weaponactor->xspr.data1, gAmmoInfo[nAmmoType].max); +#endif + else + pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + pWeaponItemData->count, gAmmoInfo[nAmmoType].max); - int nNewWeapon = WeaponUpgrade(pPlayer, nWeaponType); - if (nNewWeapon != pPlayer->curWeapon) { - pPlayer->weaponState = 0; - pPlayer->nextWeapon = nNewWeapon; - } - sfxPlay3DSound(pPlayer->actor, 777, -1, 0); - return 1; - } - - if (!actGetRespawnTime(weaponactor) || nAmmoType == -1 || pPlayer->ammoCount[nAmmoType] >= gAmmoInfo[nAmmoType].max) return 0; - #ifdef NOONE_EXTENSIONS - else if (gModernMap && weaponactor->hasX() && weaponactor->xspr.data1 > 0) - pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + weaponactor->xspr.data1, gAmmoInfo[nAmmoType].max); - #endif - else - pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType]+pWeaponItemData->count, gAmmoInfo[nAmmoType].max); + int nNewWeapon = WeaponUpgrade(pPlayer, nWeaponType); + if (nNewWeapon != pPlayer->curWeapon) { + pPlayer->weaponState = 0; + pPlayer->nextWeapon = nNewWeapon; + } + sfxPlay3DSound(pPlayer->actor, 777, -1, 0); + return 1; + } - sfxPlay3DSound(pPlayer->actor, 777, -1, 0); - return 1; + if (!actGetRespawnTime(weaponactor) || nAmmoType == -1 || pPlayer->ammoCount[nAmmoType] >= gAmmoInfo[nAmmoType].max) return 0; +#ifdef NOONE_EXTENSIONS + else if (gModernMap && weaponactor->hasX() && weaponactor->xspr.data1 > 0) + pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + weaponactor->xspr.data1, gAmmoInfo[nAmmoType].max); +#endif + else + pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + pWeaponItemData->count, gAmmoInfo[nAmmoType].max); + + sfxPlay3DSound(pPlayer->actor, 777, -1, 0); + return 1; } -void PickUp(PLAYER *pPlayer, DBloodActor* actor) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void PickUp(PLAYER* pPlayer, DBloodActor* actor) { - const char *msg = nullptr; - int nType = actor->spr.type; - bool pickedUp = 0; - int customMsg = -1; - #ifdef NOONE_EXTENSIONS - if (gModernMap && actor->hasX()) { // allow custom INI message instead "Picked up" - if (actor->xspr.txID != 3 && actor->xspr.lockMsg > 0) - customMsg = actor->xspr.lockMsg; - } - #endif + const char* msg = nullptr; + int nType = actor->spr.type; + bool pickedUp = 0; + int customMsg = -1; +#ifdef NOONE_EXTENSIONS + if (gModernMap && actor->hasX()) { // allow custom INI message instead "Picked up" + if (actor->xspr.txID != 3 && actor->xspr.lockMsg > 0) + customMsg = actor->xspr.lockMsg; + } +#endif - if (nType >= kItemBase && nType <= kItemMax) { - pickedUp = PickupItem(pPlayer, actor); - if (pickedUp && customMsg == -1) msg = GStrings(FStringf("TXTB_ITEM%02d", int(nType - kItemBase +1))); - - } else if (nType >= kItemAmmoBase && nType < kItemAmmoMax) { - pickedUp = PickupAmmo(pPlayer, actor); - if (pickedUp && customMsg == -1) msg = GStrings(FStringf("TXTB_AMMO%02d", int(nType - kItemAmmoBase +1))); - - } else if (nType >= kItemWeaponBase && nType < kItemWeaponMax) { - pickedUp = PickupWeapon(pPlayer, actor); - if (pickedUp && customMsg == -1) msg = GStrings(FStringf("TXTB_WPN%02d", int(nType - kItemWeaponBase +1))); - } + if (nType >= kItemBase && nType <= kItemMax) { + pickedUp = PickupItem(pPlayer, actor); + if (pickedUp && customMsg == -1) msg = GStrings(FStringf("TXTB_ITEM%02d", int(nType - kItemBase + 1))); - if (!pickedUp) return; - else if (actor->hasX()) - { - if (actor->xspr.Pickup) - trTriggerSprite(actor, kCmdSpritePickup); - } - - if (!actCheckRespawn(actor)) - actPostSprite(actor, kStatFree); + } + else if (nType >= kItemAmmoBase && nType < kItemAmmoMax) { + pickedUp = PickupAmmo(pPlayer, actor); + if (pickedUp && customMsg == -1) msg = GStrings(FStringf("TXTB_AMMO%02d", int(nType - kItemAmmoBase + 1))); - pPlayer->pickupEffect = 30; - if (pPlayer == gMe) { - if (customMsg > 0) trTextOver(customMsg - 1); - else if (msg) viewSetMessage(msg, 0, MESSAGE_PRIORITY_PICKUP); - } + } + else if (nType >= kItemWeaponBase && nType < kItemWeaponMax) { + pickedUp = PickupWeapon(pPlayer, actor); + if (pickedUp && customMsg == -1) msg = GStrings(FStringf("TXTB_WPN%02d", int(nType - kItemWeaponBase + 1))); + } + + if (!pickedUp) return; + else if (actor->hasX()) + { + if (actor->xspr.Pickup) + trTriggerSprite(actor, kCmdSpritePickup); + } + + if (!actCheckRespawn(actor)) + actPostSprite(actor, kStatFree); + + pPlayer->pickupEffect = 30; + if (pPlayer == gMe) { + if (customMsg > 0) trTextOver(customMsg - 1); + else if (msg) viewSetMessage(msg, 0, MESSAGE_PRIORITY_PICKUP); + } } -void CheckPickUp(PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void CheckPickUp(PLAYER* pPlayer) { - auto plActor = pPlayer->actor; - int x = plActor->spr.pos.X; - int y = plActor->spr.pos.Y; - int z = plActor->spr.pos.Z; - auto pSector = plActor->spr.sector(); - BloodStatIterator it(kStatItem); - while (auto itemactor = it.Next()) - { - if (itemactor->spr.flags&32) - continue; - int dx = abs(x-itemactor->spr.pos.X)>>4; - if (dx > 48) - continue; - int dy = abs(y-itemactor->spr.pos.Y)>>4; - if (dy > 48) - continue; - int top, bottom; - GetActorExtents(plActor, &top, &bottom); - int vb = 0; - if (itemactor->spr.pos.Z < top) - vb = (top-itemactor->spr.pos.Z)>>8; - else if (itemactor->spr.pos.Z > bottom) - vb = (itemactor->spr.pos.Z-bottom)>>8; - if (vb > 32) - continue; - if (approxDist(dx,dy) > 48) - continue; - GetActorExtents(itemactor, &top, &bottom); - if (cansee(x, y, z, pSector, itemactor->spr.pos.X, itemactor->spr.pos.Y, itemactor->spr.pos.Z, itemactor->spr.sector()) - || cansee(x, y, z, pSector, itemactor->spr.pos.X, itemactor->spr.pos.Y, top, itemactor->spr.sector()) - || cansee(x, y, z, pSector, itemactor->spr.pos.X, itemactor->spr.pos.Y, bottom, itemactor->spr.sector())) - PickUp(pPlayer, itemactor); - } + auto plActor = pPlayer->actor; + int x = plActor->spr.pos.X; + int y = plActor->spr.pos.Y; + int z = plActor->spr.pos.Z; + auto pSector = plActor->spr.sector(); + BloodStatIterator it(kStatItem); + while (auto itemactor = it.Next()) + { + if (itemactor->spr.flags & 32) + continue; + int dx = abs(x - itemactor->spr.pos.X) >> 4; + if (dx > 48) + continue; + int dy = abs(y - itemactor->spr.pos.Y) >> 4; + if (dy > 48) + continue; + int top, bottom; + GetActorExtents(plActor, &top, &bottom); + int vb = 0; + if (itemactor->spr.pos.Z < top) + vb = (top - itemactor->spr.pos.Z) >> 8; + else if (itemactor->spr.pos.Z > bottom) + vb = (itemactor->spr.pos.Z - bottom) >> 8; + if (vb > 32) + continue; + if (approxDist(dx, dy) > 48) + continue; + GetActorExtents(itemactor, &top, &bottom); + if (cansee(x, y, z, pSector, itemactor->spr.pos.X, itemactor->spr.pos.Y, itemactor->spr.pos.Z, itemactor->spr.sector()) + || cansee(x, y, z, pSector, itemactor->spr.pos.X, itemactor->spr.pos.Y, top, itemactor->spr.sector()) + || cansee(x, y, z, pSector, itemactor->spr.pos.X, itemactor->spr.pos.Y, bottom, itemactor->spr.sector())) + PickUp(pPlayer, itemactor); + } } -int ActionScan(PLAYER *pPlayer, HitInfo* out) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +int ActionScan(PLAYER* pPlayer, HitInfo* out) { - auto plActor = pPlayer->actor; - *out = {}; - int x = bcos(plActor->spr.ang); - int y = bsin(plActor->spr.ang); - int z = pPlayer->slope; - int hit = HitScan(pPlayer->actor, pPlayer->zView, x, y, z, 0x10000040, 128); - int hitDist = approxDist(plActor->spr.pos.X-gHitInfo.hitpos.X, plActor->spr.pos.Y-gHitInfo.hitpos.Y)>>4; - if (hitDist < 64) - { - switch (hit) - { - case 3: - { - auto hitactor = gHitInfo.actor(); - if (!hitactor || !hitactor->hasX()) return -1; - out->hitActor = hitactor; - if (hitactor->spr.statnum == kStatThing) - { - if (hitactor->spr.type == kThingDroppedLifeLeech) - { - if (gGameOptions.nGameType > 1 && findDroppedLeech(pPlayer, hitactor)) - return -1; - hitactor->xspr.data4 = pPlayer->nPlayer; - hitactor->xspr.isTriggered = 0; - } - } - if (hitactor->xspr.Push) - return 3; - if (hitactor->spr.statnum == kStatDude) - { - int nMass = getDudeInfo(hitactor->spr.type)->mass; - if (nMass) - { - int t2 = DivScale(0xccccc, nMass, 8); - hitactor->xvel += MulScale(x, t2, 16); - hitactor->yvel += MulScale(y, t2, 16); - hitactor->zvel += MulScale(z, t2, 16); - } - if (hitactor->xspr.Push && !hitactor->xspr.state && !hitactor->xspr.isTriggered) - trTriggerSprite(hitactor, kCmdSpritePush); - } - break; - } - case 0: - case 4: - { - auto pWall = gHitInfo.hitWall; - out->hitWall = gHitInfo.hitWall; - if (pWall->hasX() && pWall->xw().triggerPush) - return 0; - if (pWall->twoSided()) - { - auto sect = pWall->nextSector(); - out->hitWall = nullptr; - out->hitSector = sect; - if (sect->hasX() && sect->xs().Wallpush) - return 6; - } - break; - } - case 1: - case 2: - { - auto pSector = gHitInfo.hitSector; - out->hitSector = gHitInfo.hitSector; - if (pSector->hasX() && pSector->xs().Push) - return 6; - break; - } - } - } - out->hitSector = plActor->spr.sector(); - if (plActor->spr.sector()->hasX() && plActor->spr.sector()->xs().Push) - return 6; - return -1; + auto plActor = pPlayer->actor; + *out = {}; + int x = bcos(plActor->spr.ang); + int y = bsin(plActor->spr.ang); + int z = pPlayer->slope; + int hit = HitScan(pPlayer->actor, pPlayer->zView, x, y, z, 0x10000040, 128); + int hitDist = approxDist(plActor->spr.pos.X - gHitInfo.hitpos.X, plActor->spr.pos.Y - gHitInfo.hitpos.Y) >> 4; + if (hitDist < 64) + { + switch (hit) + { + case 3: + { + auto hitactor = gHitInfo.actor(); + if (!hitactor || !hitactor->hasX()) return -1; + out->hitActor = hitactor; + if (hitactor->spr.statnum == kStatThing) + { + if (hitactor->spr.type == kThingDroppedLifeLeech) + { + if (gGameOptions.nGameType > 1 && findDroppedLeech(pPlayer, hitactor)) + return -1; + hitactor->xspr.data4 = pPlayer->nPlayer; + hitactor->xspr.isTriggered = 0; + } + } + if (hitactor->xspr.Push) + return 3; + if (hitactor->spr.statnum == kStatDude) + { + int nMass = getDudeInfo(hitactor->spr.type)->mass; + if (nMass) + { + int t2 = DivScale(0xccccc, nMass, 8); + hitactor->xvel += MulScale(x, t2, 16); + hitactor->yvel += MulScale(y, t2, 16); + hitactor->zvel += MulScale(z, t2, 16); + } + if (hitactor->xspr.Push && !hitactor->xspr.state && !hitactor->xspr.isTriggered) + trTriggerSprite(hitactor, kCmdSpritePush); + } + break; + } + case 0: + case 4: + { + auto pWall = gHitInfo.hitWall; + out->hitWall = gHitInfo.hitWall; + if (pWall->hasX() && pWall->xw().triggerPush) + return 0; + if (pWall->twoSided()) + { + auto sect = pWall->nextSector(); + out->hitWall = nullptr; + out->hitSector = sect; + if (sect->hasX() && sect->xs().Wallpush) + return 6; + } + break; + } + case 1: + case 2: + { + auto pSector = gHitInfo.hitSector; + out->hitSector = gHitInfo.hitSector; + if (pSector->hasX() && pSector->xs().Push) + return 6; + break; + } + } + } + out->hitSector = plActor->spr.sector(); + if (plActor->spr.sector()->hasX() && plActor->spr.sector()->xs().Push) + return 6; + return -1; } //--------------------------------------------------------------------------- @@ -1329,9 +1493,9 @@ int ActionScan(PLAYER *pPlayer, HitInfo* out) // //--------------------------------------------------------------------------- -void UpdatePlayerSpriteAngle(PLAYER *pPlayer) +void UpdatePlayerSpriteAngle(PLAYER* pPlayer) { - pPlayer->actor->spr.ang = pPlayer->angle.ang.asbuild(); + pPlayer->actor->spr.ang = pPlayer->angle.ang.asbuild(); } //--------------------------------------------------------------------------- @@ -1342,847 +1506,919 @@ void UpdatePlayerSpriteAngle(PLAYER *pPlayer) void doslopetilting(PLAYER* pPlayer, double const scaleAdjust = 1) { - auto plActor = pPlayer->actor; - int const florhit = pPlayer->actor->hit.florhit.type; - bool const va = plActor->xspr.height < 16 && (florhit == kHitSector || florhit == 0) ? 1 : 0; - pPlayer->horizon.calcviewpitch(plActor->spr.pos.vec2, buildang(plActor->spr.ang), va, plActor->spr.sector()->floorstat & CSTAT_SECTOR_SLOPE, plActor->spr.sector(), scaleAdjust); + auto plActor = pPlayer->actor; + int const florhit = pPlayer->actor->hit.florhit.type; + bool const va = plActor->xspr.height < 16 && (florhit == kHitSector || florhit == 0) ? 1 : 0; + pPlayer->horizon.calcviewpitch(plActor->spr.pos.vec2, buildang(plActor->spr.ang), va, plActor->spr.sector()->floorstat & CSTAT_SECTOR_SLOPE, plActor->spr.sector(), scaleAdjust); } -void ProcessInput(PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void ProcessInput(PLAYER* pPlayer) { - enum - { - Item_MedKit = 0, - Item_CrystalBall = 1, - Item_BeastVision = 2, - Item_JumpBoots = 3 - }; + enum + { + Item_MedKit = 0, + Item_CrystalBall = 1, + Item_BeastVision = 2, + Item_JumpBoots = 3 + }; - pPlayer->horizon.resetadjustment(); - pPlayer->angle.resetadjustment(); + pPlayer->horizon.resetadjustment(); + pPlayer->angle.resetadjustment(); - DBloodActor* actor = pPlayer->actor; - POSTURE *pPosture = &pPlayer->pPosture[pPlayer->lifeMode][pPlayer->posture]; - InputPacket *pInput = &pPlayer->input; + DBloodActor* actor = pPlayer->actor; + POSTURE* pPosture = &pPlayer->pPosture[pPlayer->lifeMode][pPlayer->posture]; + InputPacket* pInput = &pPlayer->input; - // Originally, this was never able to be true due to sloppy input code in the original game. - // Allow it to become true behind a CVAR to offer an alternate playing experience if desired. - pPlayer->isRunning = !!(pInput->actions & SB_RUN) && !cl_bloodvanillarun; + // Originally, this was never able to be true due to sloppy input code in the original game. + // Allow it to become true behind a CVAR to offer an alternate playing experience if desired. + pPlayer->isRunning = !!(pInput->actions & SB_RUN) && !cl_bloodvanillarun; - if ((pInput->actions & SB_BUTTON_MASK) || pInput->fvel || pInput->svel || pInput->avel) - pPlayer->restTime = 0; - else if (pPlayer->restTime >= 0) - pPlayer->restTime += 4; - WeaponProcess(pPlayer); - if (actor->xspr.health == 0) - { - bool bSeqStat = playerSeqPlaying(pPlayer, 16); - DBloodActor* fragger = pPlayer->fragger; - if (fragger) - { - pPlayer->angle.addadjustment(getincanglebam(pPlayer->angle.ang, bvectangbam(fragger->spr.pos.X - actor->spr.pos.X, fragger->spr.pos.Y - actor->spr.pos.Y))); - } - pPlayer->deathTime += 4; - if (!bSeqStat) - pPlayer->horizon.addadjustment(q16horiz(MulScale(0x8000-(Cos(ClipHigh(pPlayer->deathTime<<3, 1024))>>15), gi->playerHorizMax(), 16) - pPlayer->horizon.horiz.asq16())); - if (pPlayer->curWeapon) - pInput->setNewWeapon(pPlayer->curWeapon); - if (pInput->actions & SB_OPEN) - { - if (bSeqStat) - { - if (pPlayer->deathTime > 360) - seqSpawn(pPlayer->pDudeInfo->seqStartID+14, pPlayer->actor, nPlayerSurviveClient); - } - else if (seqGetStatus(pPlayer->actor) < 0) - { - if (pPlayer->actor) - pPlayer->actor->spr.type = kThingBloodChunks; - actPostSprite(pPlayer->actor, kStatThing); - seqSpawn(pPlayer->pDudeInfo->seqStartID+15, pPlayer->actor, -1); - playerReset(pPlayer); - if (gGameOptions.nGameType == 0 && numplayers == 1) - { - gameaction = ga_autoloadgame; - } - else - playerStart(pPlayer->nPlayer); - } - pInput->actions &= ~SB_OPEN; - } - return; - } - if (pPlayer->posture == 1) - { - int x = Cos(actor->spr.ang); - int y = Sin(actor->spr.ang); - if (pInput->fvel) - { - int forward = pInput->fvel; - if (forward > 0) - forward = MulScale(pPosture->frontAccel, forward, 8); - else - forward = MulScale(pPosture->backAccel, forward, 8); - actor->xvel += MulScale(forward, x, 30); - actor->yvel += MulScale(forward, y, 30); - } - if (pInput->svel) - { - int strafe = pInput->svel; - strafe = MulScale(pPosture->sideAccel, strafe, 8); - actor->xvel += MulScale(strafe, y, 30); - actor->yvel -= MulScale(strafe, x, 30); - } - } - else if (actor->xspr.height < 256) - { - int speed = 0x10000; - if (actor->xspr.height > 0) - speed -= DivScale(actor->xspr.height, 256, 16); - int x = Cos(actor->spr.ang); - int y = Sin(actor->spr.ang); - if (pInput->fvel) - { - int forward = pInput->fvel; - if (forward > 0) - forward = MulScale(pPosture->frontAccel, forward, 8); - else - forward = MulScale(pPosture->backAccel, forward, 8); - if (actor->xspr.height) - forward = MulScale(forward, speed, 16); - actor->xvel += MulScale(forward, x, 30); - actor->yvel += MulScale(forward, y, 30); - } - if (pInput->svel) - { - int strafe = pInput->svel; - strafe = MulScale(pPosture->sideAccel, strafe, 8); - if (actor->xspr.height) - strafe = MulScale(strafe, speed, 16); - actor->xvel += MulScale(strafe, y, 30); - actor->yvel -= MulScale(strafe, x, 30); - } - } + if ((pInput->actions & SB_BUTTON_MASK) || pInput->fvel || pInput->svel || pInput->avel) + pPlayer->restTime = 0; + else if (pPlayer->restTime >= 0) + pPlayer->restTime += 4; + WeaponProcess(pPlayer); + if (actor->xspr.health == 0) + { + bool bSeqStat = playerSeqPlaying(pPlayer, 16); + DBloodActor* fragger = pPlayer->fragger; + if (fragger) + { + pPlayer->angle.addadjustment(getincanglebam(pPlayer->angle.ang, bvectangbam(fragger->spr.pos.X - actor->spr.pos.X, fragger->spr.pos.Y - actor->spr.pos.Y))); + } + pPlayer->deathTime += 4; + if (!bSeqStat) + pPlayer->horizon.addadjustment(q16horiz(MulScale(0x8000 - (Cos(ClipHigh(pPlayer->deathTime << 3, 1024)) >> 15), gi->playerHorizMax(), 16) - pPlayer->horizon.horiz.asq16())); + if (pPlayer->curWeapon) + pInput->setNewWeapon(pPlayer->curWeapon); + if (pInput->actions & SB_OPEN) + { + if (bSeqStat) + { + if (pPlayer->deathTime > 360) + seqSpawn(pPlayer->pDudeInfo->seqStartID + 14, pPlayer->actor, nPlayerSurviveClient); + } + else if (seqGetStatus(pPlayer->actor) < 0) + { + if (pPlayer->actor) + pPlayer->actor->spr.type = kThingBloodChunks; + actPostSprite(pPlayer->actor, kStatThing); + seqSpawn(pPlayer->pDudeInfo->seqStartID + 15, pPlayer->actor, -1); + playerReset(pPlayer); + if (gGameOptions.nGameType == 0 && numplayers == 1) + { + gameaction = ga_autoloadgame; + } + else + playerStart(pPlayer->nPlayer); + } + pInput->actions &= ~SB_OPEN; + } + return; + } + if (pPlayer->posture == 1) + { + int x = Cos(actor->spr.ang); + int y = Sin(actor->spr.ang); + if (pInput->fvel) + { + int forward = pInput->fvel; + if (forward > 0) + forward = MulScale(pPosture->frontAccel, forward, 8); + else + forward = MulScale(pPosture->backAccel, forward, 8); + actor->xvel += MulScale(forward, x, 30); + actor->yvel += MulScale(forward, y, 30); + } + if (pInput->svel) + { + int strafe = pInput->svel; + strafe = MulScale(pPosture->sideAccel, strafe, 8); + actor->xvel += MulScale(strafe, y, 30); + actor->yvel -= MulScale(strafe, x, 30); + } + } + else if (actor->xspr.height < 256) + { + int speed = 0x10000; + if (actor->xspr.height > 0) + speed -= DivScale(actor->xspr.height, 256, 16); + int x = Cos(actor->spr.ang); + int y = Sin(actor->spr.ang); + if (pInput->fvel) + { + int forward = pInput->fvel; + if (forward > 0) + forward = MulScale(pPosture->frontAccel, forward, 8); + else + forward = MulScale(pPosture->backAccel, forward, 8); + if (actor->xspr.height) + forward = MulScale(forward, speed, 16); + actor->xvel += MulScale(forward, x, 30); + actor->yvel += MulScale(forward, y, 30); + } + if (pInput->svel) + { + int strafe = pInput->svel; + strafe = MulScale(pPosture->sideAccel, strafe, 8); + if (actor->xspr.height) + strafe = MulScale(strafe, speed, 16); + actor->xvel += MulScale(strafe, y, 30); + actor->yvel -= MulScale(strafe, x, 30); + } + } - if (SyncInput()) - { - pPlayer->angle.applyinput(pInput->avel, &pInput->actions); - } + if (SyncInput()) + { + pPlayer->angle.applyinput(pInput->avel, &pInput->actions); + } - // unconditionally update the player's sprite angle - // in case game is forcing synchronised input. - UpdatePlayerSpriteAngle(pPlayer); + // unconditionally update the player's sprite angle + // in case game is forcing synchronised input. + UpdatePlayerSpriteAngle(pPlayer); - if (!(pInput->actions & SB_JUMP)) - pPlayer->cantJump = 0; + if (!(pInput->actions & SB_JUMP)) + pPlayer->cantJump = 0; - switch (pPlayer->posture) { - case 1: - if (pInput->actions & SB_JUMP) - actor->zvel -= pPosture->normalJumpZ;//0x5b05; - if (pInput->actions & SB_CROUCH) - actor->zvel += pPosture->normalJumpZ;//0x5b05; - break; - case 2: - if (!(pInput->actions & SB_CROUCH)) - pPlayer->posture = 0; - break; - default: - if (!pPlayer->cantJump && (pInput->actions & SB_JUMP) && actor->xspr.height == 0) { - #ifdef NOONE_EXTENSIONS - if ((packItemActive(pPlayer, 4) && pPosture->pwupJumpZ != 0) || pPosture->normalJumpZ != 0) - #endif - sfxPlay3DSound(actor, 700, 0, 0); - - if (packItemActive(pPlayer, 4)) actor->zvel = pPosture->pwupJumpZ; //-0x175555; - else actor->zvel = pPosture->normalJumpZ; //-0xbaaaa; - pPlayer->cantJump = 1; - } - - if (pInput->actions & SB_CROUCH) - pPlayer->posture = 2; - break; - } - if (pInput->actions & SB_OPEN) - { - HitInfo result; - - int hit = ActionScan(pPlayer, &result); - switch (hit) - { - case 6: - { - auto pSector = result.hitSector; - auto pXSector = &pSector->xs(); - int key = pXSector->Key; - if (pXSector->locked && pPlayer == gMe) - { - viewSetMessage(GStrings("TXTB_LOCKED")); - auto snd = 3062; - if (sndCheckPlaying(snd)) - sndStopSample(snd); - sndStartSample(snd, 255, 2, 0); - } - if (!key || pPlayer->hasKey[key]) - trTriggerSector(pSector, kCmdSpritePush); - else if (pPlayer == gMe) - { - viewSetMessage(GStrings("TXTB_KEY")); - auto snd = 3063; - if (sndCheckPlaying(snd)) - sndStopSample(snd); - sndStartSample(snd, 255, 2, 0); - } - break; - } - case 0: - { - auto pWall = result.hitWall; - auto pXWall = &pWall->xw(); - int key = pXWall->key; - if (pXWall->locked && pPlayer == gMe) - { - viewSetMessage(GStrings("TXTB_LOCKED")); - auto snd = 3062; - if (sndCheckPlaying(snd)) - sndStopSample(snd); - sndStartSample(snd, 255, 2, 0); - } - if (!key || pPlayer->hasKey[key]) - trTriggerWall(pWall, kCmdWallPush); - else if (pPlayer == gMe) - { - viewSetMessage(GStrings("TXTB_KEY")); - auto snd = 3063; - if (sndCheckPlaying(snd)) - sndStopSample(snd); - sndStartSample(snd, 255, 2, 0); - } - break; - } - case 3: - { - auto act = result.actor(); - int key = actor->xspr.key; - if (actor->xspr.locked && pPlayer == gMe && actor->xspr.lockMsg) - trTextOver(actor->xspr.lockMsg); - if (!key || pPlayer->hasKey[key]) - trTriggerSprite(act, kCmdSpritePush); - else if (pPlayer == gMe) - { - viewSetMessage(GStrings("TXTB_KEY")); - sndStartSample(3063, 255, 2, 0); - } - break; - } - } - if (pPlayer->handTime > 0) - pPlayer->handTime = ClipLow(pPlayer->handTime-4*(6-gGameOptions.nDifficulty), 0); - if (pPlayer->handTime <= 0 && pPlayer->hand) - { - DBloodActor* pactor = pPlayer->actor; - auto spawned = actSpawnDude(pactor, kDudeHand, pPlayer->actor->spr.clipdist<<1, 0); - if (spawned) - { - spawned->spr.ang = (pPlayer->actor->spr.ang + 1024) & 2047; - int x = bcos(pPlayer->actor->spr.ang); - int y = bsin(pPlayer->actor->spr.ang); - spawned->xvel = pPlayer->actor->xvel + MulScale(0x155555, x, 14); - spawned->yvel = pPlayer->actor->yvel + MulScale(0x155555, y, 14); - spawned->zvel = pPlayer->actor->zvel; - } - pPlayer->hand = 0; - } - pInput->actions &= ~SB_OPEN; - } - - if (SyncInput()) - { - pPlayer->horizon.applyinput(pInput->horz, &pInput->actions); - doslopetilting(pPlayer); - } - - // disable synchronised input and input locks if set by game. - resetForcedSyncInput(); - pPlayer->angle.unlockinput(); - pPlayer->horizon.unlockinput(); - - pPlayer->slope = -pPlayer->horizon.horiz.asq16() >> 9; - if (pInput->actions & SB_INVPREV) - { - pInput->actions&= ~SB_INVPREV; - packPrevItem(pPlayer); - } - if (pInput->actions & SB_INVNEXT) - { - pInput->actions &= ~SB_INVNEXT; - packNextItem(pPlayer); - } - if (pInput->actions & SB_INVUSE) - { - pInput->actions &= ~SB_INVUSE; - if (pPlayer->packSlots[pPlayer->packItemId].curAmount > 0) - packUseItem(pPlayer, pPlayer->packItemId); - } - if (pInput->isItemUsed(Item_BeastVision)) - { - pInput->clearItemUsed(Item_BeastVision); - if (pPlayer->packSlots[3].curAmount > 0) - packUseItem(pPlayer, 3); - } - if (pInput->isItemUsed(Item_CrystalBall)) - { - pInput->clearItemUsed(Item_CrystalBall); - if (pPlayer->packSlots[2].curAmount > 0) - packUseItem(pPlayer, 2); - } - if (pInput->isItemUsed(Item_JumpBoots)) - { - pInput->clearItemUsed(Item_JumpBoots); - if (pPlayer->packSlots[4].curAmount > 0) - packUseItem(pPlayer, 4); - } - if (pInput->isItemUsed(Item_MedKit)) - { - pInput->clearItemUsed(Item_MedKit); - if (pPlayer->packSlots[0].curAmount > 0) - packUseItem(pPlayer, 0); - } - if (pInput->actions & SB_HOLSTER) - { - pInput->actions &= ~SB_HOLSTER; - if (pPlayer->curWeapon) - { - WeaponLower(pPlayer); - viewSetMessage("Holstering weapon"); - } - } - CheckPickUp(pPlayer); -} - -void playerProcess(PLAYER *pPlayer) -{ - DBloodActor* actor = pPlayer->actor; - POSTURE* pPosture = &pPlayer->pPosture[pPlayer->lifeMode][pPlayer->posture]; - powerupProcess(pPlayer); - int top, bottom; - GetActorExtents(actor, &top, &bottom); - int dzb = (bottom-actor->spr.pos.Z)/4; - int dzt = (actor->spr.pos.Z-top)/4; - int dw = actor->spr.clipdist<<2; - if (!gNoClip) - { - auto pSector = actor->spr.sector(); - if (pushmove(&actor->spr.pos, &pSector, dw, dzt, dzb, CLIPMASK0) == -1) - actDamageSprite(actor, actor, kDamageFall, 500<<4); - if (actor->spr.sector() != pSector) - { - if (pSector == nullptr) - { - pSector = actor->spr.sector(); - actDamageSprite(actor, actor, kDamageFall, 500<<4); - } - else - ChangeActorSect(actor, pSector); - } - } - ProcessInput(pPlayer); - int nSpeed = approxDist(actor->xvel, actor->yvel); - pPlayer->zViewVel = interpolatedvalue(pPlayer->zViewVel, actor->zvel, 0x7000); - int dz = pPlayer->actor->spr.pos.Z-pPosture->eyeAboveZ-pPlayer->zView; - if (dz > 0) - pPlayer->zViewVel += MulScale(dz<<8, 0xa000, 16); - else - pPlayer->zViewVel += MulScale(dz<<8, 0x1800, 16); - pPlayer->zView += pPlayer->zViewVel>>8; - pPlayer->zWeaponVel = interpolatedvalue(pPlayer->zWeaponVel, actor->zvel, 0x5000); - dz = pPlayer->actor->spr.pos.Z-pPosture->weaponAboveZ-pPlayer->zWeapon; - if (dz > 0) - pPlayer->zWeaponVel += MulScale(dz<<8, 0x8000, 16); - else - pPlayer->zWeaponVel += MulScale(dz<<8, 0xc00, 16); - pPlayer->zWeapon += pPlayer->zWeaponVel>>8; - pPlayer->bobPhase = ClipLow(pPlayer->bobPhase-4, 0); - nSpeed >>= FRACBITS; - if (pPlayer->posture == 1) - { - pPlayer->bobAmp = (pPlayer->bobAmp+17)&2047; - pPlayer->swayAmp = (pPlayer->swayAmp+17)&2047; - pPlayer->bobHeight = MulScale(pPosture->bobV*10, Sin(pPlayer->bobAmp*2), 30); - pPlayer->bobWidth = MulScale(pPosture->bobH*pPlayer->bobPhase, Sin(pPlayer->bobAmp-256), 30); - pPlayer->swayHeight = MulScale(pPosture->swayV*pPlayer->bobPhase, Sin(pPlayer->swayAmp*2), 30); - pPlayer->swayWidth = MulScale(pPosture->swayH*pPlayer->bobPhase, Sin(pPlayer->swayAmp-0x155), 30); - } - else - { - if (actor->xspr.height < 256) - { - bool running = pPlayer->isRunning && !cl_bloodvanillabobbing; - pPlayer->bobAmp = (pPlayer->bobAmp+pPosture->pace[running]*4) & 2047; - pPlayer->swayAmp = (pPlayer->swayAmp+(pPosture->pace[running]*4)/2) & 2047; - if (running) - { - if (pPlayer->bobPhase < 60) - pPlayer->bobPhase = ClipHigh(pPlayer->bobPhase+nSpeed, 60); - } - else - { - if (pPlayer->bobPhase < 30) - pPlayer->bobPhase = ClipHigh(pPlayer->bobPhase+nSpeed, 30); - } - } - pPlayer->bobHeight = MulScale(pPosture->bobV*pPlayer->bobPhase, Sin(pPlayer->bobAmp*2), 30); - pPlayer->bobWidth = MulScale(pPosture->bobH*pPlayer->bobPhase, Sin(pPlayer->bobAmp-256), 30); - pPlayer->swayHeight = MulScale(pPosture->swayV*pPlayer->bobPhase, Sin(pPlayer->swayAmp*2), 30); - pPlayer->swayWidth = MulScale(pPosture->swayH*pPlayer->bobPhase, Sin(pPlayer->swayAmp-0x155), 30); - } - pPlayer->flickerEffect = 0; - pPlayer->quakeEffect = ClipLow(pPlayer->quakeEffect-4, 0); - pPlayer->tiltEffect = ClipLow(pPlayer->tiltEffect-4, 0); - pPlayer->visibility = ClipLow(pPlayer->visibility-4, 0); - pPlayer->painEffect = ClipLow(pPlayer->painEffect-4, 0); - pPlayer->blindEffect = ClipLow(pPlayer->blindEffect-4, 0); - pPlayer->pickupEffect = ClipLow(pPlayer->pickupEffect-4, 0); - if (pPlayer == gMe && gMe->actor->xspr.health == 0) - pPlayer->hand = 0; - if (!actor->xspr.health) - return; - pPlayer->isUnderwater = 0; - if (pPlayer->posture == 1) - { - pPlayer->isUnderwater = 1; - auto link = actor->spr.sector()->lowerLink; - if (link && (link->spr.type == kMarkerLowGoo || link->spr.type == kMarkerLowWater)) - { - if (getceilzofslopeptr(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y) > pPlayer->zView) - pPlayer->isUnderwater = 0; - } - } - if (!pPlayer->isUnderwater) - { - pPlayer->underwaterTime = 1200; - pPlayer->chokeEffect = 0; - if (packItemActive(pPlayer, 1)) - packUseItem(pPlayer, 1); - } - int nType = kDudePlayer1-kDudeBase; - switch (pPlayer->posture) - { - case 1: - seqSpawn(dudeInfo[nType].seqStartID+9, actor, -1); - break; - case 2: - seqSpawn(dudeInfo[nType].seqStartID+10, actor, -1); - break; - default: - if (!nSpeed) - seqSpawn(dudeInfo[nType].seqStartID, actor, -1); - else - seqSpawn(dudeInfo[nType].seqStartID+8, actor, -1); - break; - } -} - -DBloodActor* playerFireMissile(PLAYER *pPlayer, int a2, int a3, int a4, int a5, int a6) -{ - return actFireMissile(pPlayer->actor, a2, pPlayer->zWeapon-pPlayer->actor->spr.pos.Z, a3, a4, a5, a6); -} - -DBloodActor* playerFireThing(PLAYER *pPlayer, int a2, int a3, int thingType, int a5) -{ - assert(thingType >= kThingBase && thingType < kThingMax); - return actFireThing(pPlayer->actor, a2, pPlayer->zWeapon-pPlayer->actor->spr.pos.Z, pPlayer->slope+a3, thingType, a5); -} - -void playerFrag(PLAYER *pKiller, PLAYER *pVictim) -{ - assert(pKiller != NULL); - assert(pVictim != NULL); - - char buffer[128] = ""; - int nKiller = pKiller->actor->spr.type-kDudePlayer1; - assert(nKiller >= 0 && nKiller < kMaxPlayers); - int nVictim = pVictim->actor->spr.type-kDudePlayer1; - assert(nVictim >= 0 && nVictim < kMaxPlayers); - if (nKiller == nVictim) - { - pVictim->fragger = nullptr; - if (VanillaMode() || gGameOptions.nGameType != 1) - { - pVictim->fragCount--; - pVictim->fragInfo[nVictim]--; - } - if (gGameOptions.nGameType == 3) - team_score[pVictim->teamId]--; - int nMessage = Random(5); - int nSound = gSuicide[nMessage].Kills; - if (pVictim == gMe && gMe->handTime <= 0) - { - strcpy(buffer, GStrings("TXTB_KILLSELF")); - if (gGameOptions.nGameType > 0 && nSound >= 0) - sndStartSample(nSound, 255, 2, 0); - } - else - { - sprintf(buffer, gSuicide[nMessage].message, PlayerName(nVictim)); - } - } - else - { - if (VanillaMode() || gGameOptions.nGameType != 1) - { - pKiller->fragCount++; - pKiller->fragInfo[nKiller]++; - } - if (gGameOptions.nGameType == 3) - { - if (pKiller->teamId == pVictim->teamId) - team_score[pKiller->teamId]--; - else - { - team_score[pKiller->teamId]++; - team_ticker[pKiller->teamId]+=120; - } - } - int nMessage = Random(25); - int nSound = gVictory[nMessage].Kills; - const char* pzMessage = gVictory[nMessage].message; - sprintf(buffer, pzMessage, PlayerName(nKiller), PlayerName(nVictim)); - if (gGameOptions.nGameType > 0 && nSound >= 0 && pKiller == gMe) - sndStartSample(nSound, 255, 2, 0); - } - viewSetMessage(buffer); -} - -void FragPlayer(PLAYER *pPlayer, DBloodActor* killer) -{ - if (killer && killer->IsPlayerActor()) - { - PLAYER *pKiller = &gPlayer[killer->spr.type - kDudePlayer1]; - playerFrag(pKiller, pPlayer); - int nTeam1 = pKiller->teamId&1; - int nTeam2 = pPlayer->teamId&1; - if (nTeam1 == 0) - { - if (nTeam1 != nTeam2) - evSendGame(15, kCmdToggle); - else - evSendGame(16, kCmdToggle); - } - else - { - if (nTeam1 == nTeam2) - evSendGame(16, kCmdToggle); - else - evSendGame(15, kCmdToggle); - } - } -} - -int playerDamageArmor(PLAYER *pPlayer, DAMAGE_TYPE nType, int nDamage) -{ - DAMAGEINFO *pDamageInfo = &damageInfo[nType]; - int nArmorType = pDamageInfo->armorType; - if (nArmorType >= 0 && pPlayer->armor[nArmorType]) - { -#if 0 - int vbp = (nDamage*7)/8-nDamage/4; - int v8 = pPlayer->at33e[nArmorType]; - int t = nDamage/4 + vbp * v8 / 3200; - v8 -= t; + switch (pPlayer->posture) { + case 1: + if (pInput->actions & SB_JUMP) + actor->zvel -= pPosture->normalJumpZ;//0x5b05; + if (pInput->actions & SB_CROUCH) + actor->zvel += pPosture->normalJumpZ;//0x5b05; + break; + case 2: + if (!(pInput->actions & SB_CROUCH)) + pPlayer->posture = 0; + break; + default: + if (!pPlayer->cantJump && (pInput->actions & SB_JUMP) && actor->xspr.height == 0) { +#ifdef NOONE_EXTENSIONS + if ((packItemActive(pPlayer, 4) && pPosture->pwupJumpZ != 0) || pPosture->normalJumpZ != 0) #endif - int v8 = pPlayer->armor[nArmorType]; - int t = scale(v8, 0, 3200, nDamage/4, (nDamage*7)/8); - v8 -= t; - nDamage -= t; - pPlayer->armor[nArmorType] = ClipLow(v8, 0); - } - return nDamage; + sfxPlay3DSound(actor, 700, 0, 0); + + if (packItemActive(pPlayer, 4)) actor->zvel = pPosture->pwupJumpZ; //-0x175555; + else actor->zvel = pPosture->normalJumpZ; //-0xbaaaa; + pPlayer->cantJump = 1; + } + + if (pInput->actions & SB_CROUCH) + pPlayer->posture = 2; + break; + } + if (pInput->actions & SB_OPEN) + { + HitInfo result; + + int hit = ActionScan(pPlayer, &result); + switch (hit) + { + case 6: + { + auto pSector = result.hitSector; + auto pXSector = &pSector->xs(); + int key = pXSector->Key; + if (pXSector->locked && pPlayer == gMe) + { + viewSetMessage(GStrings("TXTB_LOCKED")); + auto snd = 3062; + if (sndCheckPlaying(snd)) + sndStopSample(snd); + sndStartSample(snd, 255, 2, 0); + } + if (!key || pPlayer->hasKey[key]) + trTriggerSector(pSector, kCmdSpritePush); + else if (pPlayer == gMe) + { + viewSetMessage(GStrings("TXTB_KEY")); + auto snd = 3063; + if (sndCheckPlaying(snd)) + sndStopSample(snd); + sndStartSample(snd, 255, 2, 0); + } + break; + } + case 0: + { + auto pWall = result.hitWall; + auto pXWall = &pWall->xw(); + int key = pXWall->key; + if (pXWall->locked && pPlayer == gMe) + { + viewSetMessage(GStrings("TXTB_LOCKED")); + auto snd = 3062; + if (sndCheckPlaying(snd)) + sndStopSample(snd); + sndStartSample(snd, 255, 2, 0); + } + if (!key || pPlayer->hasKey[key]) + trTriggerWall(pWall, kCmdWallPush); + else if (pPlayer == gMe) + { + viewSetMessage(GStrings("TXTB_KEY")); + auto snd = 3063; + if (sndCheckPlaying(snd)) + sndStopSample(snd); + sndStartSample(snd, 255, 2, 0); + } + break; + } + case 3: + { + auto act = result.actor(); + int key = actor->xspr.key; + if (actor->xspr.locked && pPlayer == gMe && actor->xspr.lockMsg) + trTextOver(actor->xspr.lockMsg); + if (!key || pPlayer->hasKey[key]) + trTriggerSprite(act, kCmdSpritePush); + else if (pPlayer == gMe) + { + viewSetMessage(GStrings("TXTB_KEY")); + sndStartSample(3063, 255, 2, 0); + } + break; + } + } + if (pPlayer->handTime > 0) + pPlayer->handTime = ClipLow(pPlayer->handTime - 4 * (6 - gGameOptions.nDifficulty), 0); + if (pPlayer->handTime <= 0 && pPlayer->hand) + { + DBloodActor* pactor = pPlayer->actor; + auto spawned = actSpawnDude(pactor, kDudeHand, pPlayer->actor->spr.clipdist << 1, 0); + if (spawned) + { + spawned->spr.ang = (pPlayer->actor->spr.ang + 1024) & 2047; + int x = bcos(pPlayer->actor->spr.ang); + int y = bsin(pPlayer->actor->spr.ang); + spawned->xvel = pPlayer->actor->xvel + MulScale(0x155555, x, 14); + spawned->yvel = pPlayer->actor->yvel + MulScale(0x155555, y, 14); + spawned->zvel = pPlayer->actor->zvel; + } + pPlayer->hand = 0; + } + pInput->actions &= ~SB_OPEN; + } + + if (SyncInput()) + { + pPlayer->horizon.applyinput(pInput->horz, &pInput->actions); + doslopetilting(pPlayer); + } + + // disable synchronised input and input locks if set by game. + resetForcedSyncInput(); + pPlayer->angle.unlockinput(); + pPlayer->horizon.unlockinput(); + + pPlayer->slope = -pPlayer->horizon.horiz.asq16() >> 9; + if (pInput->actions & SB_INVPREV) + { + pInput->actions &= ~SB_INVPREV; + packPrevItem(pPlayer); + } + if (pInput->actions & SB_INVNEXT) + { + pInput->actions &= ~SB_INVNEXT; + packNextItem(pPlayer); + } + if (pInput->actions & SB_INVUSE) + { + pInput->actions &= ~SB_INVUSE; + if (pPlayer->packSlots[pPlayer->packItemId].curAmount > 0) + packUseItem(pPlayer, pPlayer->packItemId); + } + if (pInput->isItemUsed(Item_BeastVision)) + { + pInput->clearItemUsed(Item_BeastVision); + if (pPlayer->packSlots[3].curAmount > 0) + packUseItem(pPlayer, 3); + } + if (pInput->isItemUsed(Item_CrystalBall)) + { + pInput->clearItemUsed(Item_CrystalBall); + if (pPlayer->packSlots[2].curAmount > 0) + packUseItem(pPlayer, 2); + } + if (pInput->isItemUsed(Item_JumpBoots)) + { + pInput->clearItemUsed(Item_JumpBoots); + if (pPlayer->packSlots[4].curAmount > 0) + packUseItem(pPlayer, 4); + } + if (pInput->isItemUsed(Item_MedKit)) + { + pInput->clearItemUsed(Item_MedKit); + if (pPlayer->packSlots[0].curAmount > 0) + packUseItem(pPlayer, 0); + } + if (pInput->actions & SB_HOLSTER) + { + pInput->actions &= ~SB_HOLSTER; + if (pPlayer->curWeapon) + { + WeaponLower(pPlayer); + viewSetMessage("Holstering weapon"); + } + } + CheckPickUp(pPlayer); } -void flagDropped(PLAYER *pPlayer, int a2) +void playerProcess(PLAYER* pPlayer) { - DBloodActor* playeractor = pPlayer->actor; - DBloodActor* actor; - char buffer[80]; - switch (a2) - { - case kItemFlagA: - pPlayer->hasFlag &= ~1; - actor = actDropObject(playeractor, kItemFlagA); - if (actor) actor->SetOwner(pPlayer->ctfFlagState[0]); - gBlueFlagDropped = true; - sprintf(buffer, "%s dropped Blue Flag", PlayerName(pPlayer->nPlayer)); - sndStartSample(8005, 255, 2, 0); - viewSetMessage(buffer); - break; - case kItemFlagB: - pPlayer->hasFlag &= ~2; - actor = actDropObject(playeractor, kItemFlagB); - if (actor) actor->SetOwner(pPlayer->ctfFlagState[1]); - gRedFlagDropped = true; - sprintf(buffer, "%s dropped Red Flag", PlayerName(pPlayer->nPlayer)); - sndStartSample(8004, 255, 2, 0); - viewSetMessage(buffer); - break; - } + DBloodActor* actor = pPlayer->actor; + POSTURE* pPosture = &pPlayer->pPosture[pPlayer->lifeMode][pPlayer->posture]; + powerupProcess(pPlayer); + int top, bottom; + GetActorExtents(actor, &top, &bottom); + int dzb = (bottom - actor->spr.pos.Z) / 4; + int dzt = (actor->spr.pos.Z - top) / 4; + int dw = actor->spr.clipdist << 2; + if (!gNoClip) + { + auto pSector = actor->spr.sector(); + if (pushmove(&actor->spr.pos, &pSector, dw, dzt, dzb, CLIPMASK0) == -1) + actDamageSprite(actor, actor, kDamageFall, 500 << 4); + if (actor->spr.sector() != pSector) + { + if (pSector == nullptr) + { + pSector = actor->spr.sector(); + actDamageSprite(actor, actor, kDamageFall, 500 << 4); + } + else + ChangeActorSect(actor, pSector); + } + } + ProcessInput(pPlayer); + int nSpeed = approxDist(actor->xvel, actor->yvel); + pPlayer->zViewVel = interpolatedvalue(pPlayer->zViewVel, actor->zvel, 0x7000); + int dz = pPlayer->actor->spr.pos.Z - pPosture->eyeAboveZ - pPlayer->zView; + if (dz > 0) + pPlayer->zViewVel += MulScale(dz << 8, 0xa000, 16); + else + pPlayer->zViewVel += MulScale(dz << 8, 0x1800, 16); + pPlayer->zView += pPlayer->zViewVel >> 8; + pPlayer->zWeaponVel = interpolatedvalue(pPlayer->zWeaponVel, actor->zvel, 0x5000); + dz = pPlayer->actor->spr.pos.Z - pPosture->weaponAboveZ - pPlayer->zWeapon; + if (dz > 0) + pPlayer->zWeaponVel += MulScale(dz << 8, 0x8000, 16); + else + pPlayer->zWeaponVel += MulScale(dz << 8, 0xc00, 16); + pPlayer->zWeapon += pPlayer->zWeaponVel >> 8; + pPlayer->bobPhase = ClipLow(pPlayer->bobPhase - 4, 0); + nSpeed >>= FRACBITS; + if (pPlayer->posture == 1) + { + pPlayer->bobAmp = (pPlayer->bobAmp + 17) & 2047; + pPlayer->swayAmp = (pPlayer->swayAmp + 17) & 2047; + pPlayer->bobHeight = MulScale(pPosture->bobV * 10, Sin(pPlayer->bobAmp * 2), 30); + pPlayer->bobWidth = MulScale(pPosture->bobH * pPlayer->bobPhase, Sin(pPlayer->bobAmp - 256), 30); + pPlayer->swayHeight = MulScale(pPosture->swayV * pPlayer->bobPhase, Sin(pPlayer->swayAmp * 2), 30); + pPlayer->swayWidth = MulScale(pPosture->swayH * pPlayer->bobPhase, Sin(pPlayer->swayAmp - 0x155), 30); + } + else + { + if (actor->xspr.height < 256) + { + bool running = pPlayer->isRunning && !cl_bloodvanillabobbing; + pPlayer->bobAmp = (pPlayer->bobAmp + pPosture->pace[running] * 4) & 2047; + pPlayer->swayAmp = (pPlayer->swayAmp + (pPosture->pace[running] * 4) / 2) & 2047; + if (running) + { + if (pPlayer->bobPhase < 60) + pPlayer->bobPhase = ClipHigh(pPlayer->bobPhase + nSpeed, 60); + } + else + { + if (pPlayer->bobPhase < 30) + pPlayer->bobPhase = ClipHigh(pPlayer->bobPhase + nSpeed, 30); + } + } + pPlayer->bobHeight = MulScale(pPosture->bobV * pPlayer->bobPhase, Sin(pPlayer->bobAmp * 2), 30); + pPlayer->bobWidth = MulScale(pPosture->bobH * pPlayer->bobPhase, Sin(pPlayer->bobAmp - 256), 30); + pPlayer->swayHeight = MulScale(pPosture->swayV * pPlayer->bobPhase, Sin(pPlayer->swayAmp * 2), 30); + pPlayer->swayWidth = MulScale(pPosture->swayH * pPlayer->bobPhase, Sin(pPlayer->swayAmp - 0x155), 30); + } + pPlayer->flickerEffect = 0; + pPlayer->quakeEffect = ClipLow(pPlayer->quakeEffect - 4, 0); + pPlayer->tiltEffect = ClipLow(pPlayer->tiltEffect - 4, 0); + pPlayer->visibility = ClipLow(pPlayer->visibility - 4, 0); + pPlayer->painEffect = ClipLow(pPlayer->painEffect - 4, 0); + pPlayer->blindEffect = ClipLow(pPlayer->blindEffect - 4, 0); + pPlayer->pickupEffect = ClipLow(pPlayer->pickupEffect - 4, 0); + if (pPlayer == gMe && gMe->actor->xspr.health == 0) + pPlayer->hand = 0; + if (!actor->xspr.health) + return; + pPlayer->isUnderwater = 0; + if (pPlayer->posture == 1) + { + pPlayer->isUnderwater = 1; + auto link = actor->spr.sector()->lowerLink; + if (link && (link->spr.type == kMarkerLowGoo || link->spr.type == kMarkerLowWater)) + { + if (getceilzofslopeptr(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y) > pPlayer->zView) + pPlayer->isUnderwater = 0; + } + } + if (!pPlayer->isUnderwater) + { + pPlayer->underwaterTime = 1200; + pPlayer->chokeEffect = 0; + if (packItemActive(pPlayer, 1)) + packUseItem(pPlayer, 1); + } + int nType = kDudePlayer1 - kDudeBase; + switch (pPlayer->posture) + { + case 1: + seqSpawn(dudeInfo[nType].seqStartID + 9, actor, -1); + break; + case 2: + seqSpawn(dudeInfo[nType].seqStartID + 10, actor, -1); + break; + default: + if (!nSpeed) + seqSpawn(dudeInfo[nType].seqStartID, actor, -1); + else + seqSpawn(dudeInfo[nType].seqStartID + 8, actor, -1); + break; + } } -int playerDamageSprite(DBloodActor* source, PLAYER *pPlayer, DAMAGE_TYPE nDamageType, int nDamage) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +DBloodActor* playerFireMissile(PLAYER* pPlayer, int a2, int a3, int a4, int a5, int a6) { - assert(pPlayer != NULL); - if (pPlayer->damageControl[nDamageType] || pPlayer->godMode) - return 0; - nDamage = playerDamageArmor(pPlayer, nDamageType, nDamage); - pPlayer->painEffect = ClipHigh(pPlayer->painEffect+(nDamage>>3), 600); - - DBloodActor* pActor = pPlayer->actor; - DUDEINFO *pDudeInfo = getDudeInfo(pActor->spr.type); - int nDeathSeqID = -1; - int nKneelingPlayer = -1; - bool va = playerSeqPlaying(pPlayer, 16); - if (!pActor->xspr.health) - { - if (va) - { - switch (nDamageType) - { - case kDamageSpirit: - nDeathSeqID = 18; - sfxPlay3DSound(pPlayer->actor, 716, 0, 0); - break; - case kDamageExplode: - GibSprite(pActor, GIBTYPE_7, NULL, NULL); - GibSprite(pActor, GIBTYPE_15, NULL, NULL); - pPlayer->actor->spr.cstat |= CSTAT_SPRITE_INVISIBLE; - nDeathSeqID = 17; - break; - default: - { - int top, bottom; - GetActorExtents(pActor, &top, &bottom); - CGibPosition gibPos(pActor->spr.pos.X, pActor->spr.pos.Y, top); - CGibVelocity gibVel(pActor->xvel >> 1, pActor->yvel >> 1, -0xccccc); - GibSprite(pActor, GIBTYPE_27, &gibPos, &gibVel); - GibSprite(pActor, GIBTYPE_7, NULL, NULL); - fxSpawnBlood(pActor, nDamage<<4); - fxSpawnBlood(pActor, nDamage<<4); - nDeathSeqID = 17; - break; - } - } - } - } - else - { - int nHealth = pActor->xspr.health-nDamage; - pActor->xspr.health = ClipLow(nHealth, 0); - if (pActor->xspr.health > 0 && pActor->xspr.health < 16) - { - nDamageType = kDamageBullet; - pActor->xspr.health = 0; - nHealth = -25; - } - if (pActor->xspr.health > 0) - { - DAMAGEINFO *pDamageInfo = &damageInfo[nDamageType]; - int nSound; - if (nDamage >= (10<<4)) - nSound = pDamageInfo->Kills[0]; - else - nSound = pDamageInfo->Kills[Random(3)]; - if (nDamageType == kDamageDrown && pActor->xspr.medium == kMediumWater && !pPlayer->hand) - nSound = 714; - sfxPlay3DSound(pPlayer->actor, nSound, 0, 6); - return nDamage; - } - sfxKill3DSound(pPlayer->actor, -1, 441); - if (gGameOptions.nGameType == 3 && pPlayer->hasFlag) { - if (pPlayer->hasFlag&1) flagDropped(pPlayer, kItemFlagA); - if (pPlayer->hasFlag&2) flagDropped(pPlayer, kItemFlagB); - } - pPlayer->deathTime = 0; - pPlayer->qavLoop = 0; - pPlayer->curWeapon = kWeapNone; - pPlayer->fragger = source; - pPlayer->voodooTargets = 0; - if (nDamageType == kDamageExplode && nDamage < (9<<4)) - nDamageType = kDamageFall; - switch (nDamageType) - { - case kDamageExplode: - sfxPlay3DSound(pPlayer->actor, 717, 0, 0); - GibSprite(pActor, GIBTYPE_7, NULL, NULL); - GibSprite(pActor, GIBTYPE_15, NULL, NULL); - pPlayer->actor->spr.cstat |= CSTAT_SPRITE_INVISIBLE; - nDeathSeqID = 2; - break; - case kDamageBurn: - sfxPlay3DSound(pPlayer->actor, 718, 0, 0); - nDeathSeqID = 3; - break; - case kDamageDrown: - nDeathSeqID = 1; - break; - default: - if (nHealth < -20 && gGameOptions.nGameType >= 2 && Chance(0x4000)) - { - DAMAGEINFO *pDamageInfo = &damageInfo[nDamageType]; - sfxPlay3DSound(pPlayer->actor, pDamageInfo->at10[0], 0, 2); - nDeathSeqID = 16; - nKneelingPlayer = nPlayerKneelClient; - powerupActivate(pPlayer, kPwUpDeliriumShroom); - pActor->SetTarget(source); - evPostActor(pPlayer->actor, 15, kCallbackFinishHim); - } - else - { - sfxPlay3DSound(pPlayer->actor, 716, 0, 0); - nDeathSeqID = 1; - } - break; - } - } - if (nDeathSeqID < 0) - return nDamage; - if (nDeathSeqID != 16) - { - powerupClear(pPlayer); - if (pActor->spr.sector()->hasX() && pActor->spr.sector()->xs().Exit) - trTriggerSector(pActor->spr.sector(), kCmdSectorExit); - pActor->spr.flags |= 7; - for (int p = connecthead; p >= 0; p = connectpoint2[p]) - { - if (gPlayer[p].fragger == pPlayer->actor && gPlayer[p].deathTime > 0) - gPlayer[p].fragger = nullptr; - } - FragPlayer(pPlayer, source); - trTriggerSprite(pActor, kCmdOff); - - #ifdef NOONE_EXTENSIONS - // allow drop items and keys in multiplayer - if (gModernMap && gGameOptions.nGameType != 0 && pPlayer->actor->xspr.health <= 0) { - - DBloodActor* pItem = nullptr; - if (pPlayer->actor->xspr.dropMsg && (pItem = actDropItem(pActor, pPlayer->actor->xspr.dropMsg)) != NULL) - evPostActor(pItem, 500, kCallbackRemove); - - if (pPlayer->actor->xspr.key) { - - int i; // if all players have this key, don't drop it - for (i = connecthead; i >= 0; i = connectpoint2[i]) { - if (!gPlayer[i].hasKey[pPlayer->actor->xspr.key]) - break; - } - - if (i == 0 && (pItem = actDropKey(pActor, (pPlayer->actor->xspr.key + kItemKeyBase) - 1)) != NULL) - evPostActor(pItem, 500, kCallbackRemove); - - } - - - } - #endif - - } - assert(getSequence(pDudeInfo->seqStartID + nDeathSeqID) != NULL); - seqSpawn(pDudeInfo->seqStartID+nDeathSeqID, pPlayer->actor, nKneelingPlayer); - return nDamage; + return actFireMissile(pPlayer->actor, a2, pPlayer->zWeapon - pPlayer->actor->spr.pos.Z, a3, a4, a5, a6); } -int UseAmmo(PLAYER *pPlayer, int nAmmoType, int nDec) +DBloodActor* playerFireThing(PLAYER* pPlayer, int a2, int a3, int thingType, int a5) { - if (gInfiniteAmmo) - return 9999; - if (nAmmoType == -1) - return 9999; - pPlayer->ammoCount[nAmmoType] = ClipLow(pPlayer->ammoCount[nAmmoType]-nDec, 0); - return pPlayer->ammoCount[nAmmoType]; + assert(thingType >= kThingBase && thingType < kThingMax); + return actFireThing(pPlayer->actor, a2, pPlayer->zWeapon - pPlayer->actor->spr.pos.Z, pPlayer->slope + a3, thingType, a5); } -void voodooTarget(PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void playerFrag(PLAYER* pKiller, PLAYER* pVictim) { - DBloodActor* actor = pPlayer->actor; - int v4 = pPlayer->aim.dz; - int dz = pPlayer->zWeapon-pPlayer->actor->spr.pos.Z; - if (UseAmmo(pPlayer, 9, 0) < 8) - { - pPlayer->voodooTargets = 0; - return; - } - for (int i = 0; i < 4; i++) - { - int ang1 = (pPlayer->voodooVar1+pPlayer->vodooVar2)&2047; - actFireVector(actor, 0, dz, bcos(ang1), bsin(ang1), v4, kVectorVoodoo10); - int ang2 = (pPlayer->voodooVar1+2048-pPlayer->vodooVar2)&2047; - actFireVector(actor, 0, dz, bcos(ang2), bsin(ang2), v4, kVectorVoodoo10); - } - pPlayer->voodooTargets = ClipLow(pPlayer->voodooTargets-1, 0); + assert(pKiller != NULL); + assert(pVictim != NULL); + + char buffer[128] = ""; + int nKiller = pKiller->actor->spr.type - kDudePlayer1; + assert(nKiller >= 0 && nKiller < kMaxPlayers); + int nVictim = pVictim->actor->spr.type - kDudePlayer1; + assert(nVictim >= 0 && nVictim < kMaxPlayers); + if (nKiller == nVictim) + { + pVictim->fragger = nullptr; + if (VanillaMode() || gGameOptions.nGameType != 1) + { + pVictim->fragCount--; + pVictim->fragInfo[nVictim]--; + } + if (gGameOptions.nGameType == 3) + team_score[pVictim->teamId]--; + int nMessage = Random(5); + int nSound = gSuicide[nMessage].Kills; + if (pVictim == gMe && gMe->handTime <= 0) + { + strcpy(buffer, GStrings("TXTB_KILLSELF")); + if (gGameOptions.nGameType > 0 && nSound >= 0) + sndStartSample(nSound, 255, 2, 0); + } + else + { + sprintf(buffer, gSuicide[nMessage].message, PlayerName(nVictim)); + } + } + else + { + if (VanillaMode() || gGameOptions.nGameType != 1) + { + pKiller->fragCount++; + pKiller->fragInfo[nKiller]++; + } + if (gGameOptions.nGameType == 3) + { + if (pKiller->teamId == pVictim->teamId) + team_score[pKiller->teamId]--; + else + { + team_score[pKiller->teamId]++; + team_ticker[pKiller->teamId] += 120; + } + } + int nMessage = Random(25); + int nSound = gVictory[nMessage].Kills; + const char* pzMessage = gVictory[nMessage].message; + sprintf(buffer, pzMessage, PlayerName(nKiller), PlayerName(nVictim)); + if (gGameOptions.nGameType > 0 && nSound >= 0 && pKiller == gMe) + sndStartSample(nSound, 255, 2, 0); + } + viewSetMessage(buffer); } -void playerLandingSound(PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void FragPlayer(PLAYER* pPlayer, DBloodActor* killer) { - static int surfaceSound[] = { - -1, - 600, - 601, - 602, - 603, - 604, - 605, - 605, - 605, - 600, - 605, - 605, - 605, - 604, - 603 - }; - SPRITEHIT* pHit = &pPlayer->actor->hit; - if (pHit->florhit.type != kHitNone) - { - if (!gGameOptions.bFriendlyFire && pHit->florhit.type == kHitSprite && IsTargetTeammate(pPlayer, pHit->florhit.actor())) - return; - int nSurf = tileGetSurfType(pHit->florhit); - if (nSurf) - sfxPlay3DSound(pPlayer->actor, surfaceSound[nSurf], -1, 0); - } + if (killer && killer->IsPlayerActor()) + { + PLAYER* pKiller = &gPlayer[killer->spr.type - kDudePlayer1]; + playerFrag(pKiller, pPlayer); + int nTeam1 = pKiller->teamId & 1; + int nTeam2 = pPlayer->teamId & 1; + if (nTeam1 == 0) + { + if (nTeam1 != nTeam2) + evSendGame(15, kCmdToggle); + else + evSendGame(16, kCmdToggle); + } + else + { + if (nTeam1 == nTeam2) + evSendGame(16, kCmdToggle); + else + evSendGame(15, kCmdToggle); + } + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +int playerDamageArmor(PLAYER* pPlayer, DAMAGE_TYPE nType, int nDamage) +{ + DAMAGEINFO* pDamageInfo = &damageInfo[nType]; + int nArmorType = pDamageInfo->armorType; + if (nArmorType >= 0 && pPlayer->armor[nArmorType]) + { +#if 0 + int vbp = (nDamage * 7) / 8 - nDamage / 4; + int v8 = pPlayer->at33e[nArmorType]; + int t = nDamage / 4 + vbp * v8 / 3200; + v8 -= t; +#endif + int v8 = pPlayer->armor[nArmorType]; + int t = scale(v8, 0, 3200, nDamage / 4, (nDamage * 7) / 8); + v8 -= t; + nDamage -= t; + pPlayer->armor[nArmorType] = ClipLow(v8, 0); + } + return nDamage; +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void flagDropped(PLAYER* pPlayer, int a2) +{ + DBloodActor* playeractor = pPlayer->actor; + DBloodActor* actor; + char buffer[80]; + switch (a2) + { + case kItemFlagA: + pPlayer->hasFlag &= ~1; + actor = actDropObject(playeractor, kItemFlagA); + if (actor) actor->SetOwner(pPlayer->ctfFlagState[0]); + gBlueFlagDropped = true; + sprintf(buffer, "%s dropped Blue Flag", PlayerName(pPlayer->nPlayer)); + sndStartSample(8005, 255, 2, 0); + viewSetMessage(buffer); + break; + case kItemFlagB: + pPlayer->hasFlag &= ~2; + actor = actDropObject(playeractor, kItemFlagB); + if (actor) actor->SetOwner(pPlayer->ctfFlagState[1]); + gRedFlagDropped = true; + sprintf(buffer, "%s dropped Red Flag", PlayerName(pPlayer->nPlayer)); + sndStartSample(8004, 255, 2, 0); + viewSetMessage(buffer); + break; + } +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +int playerDamageSprite(DBloodActor* source, PLAYER* pPlayer, DAMAGE_TYPE nDamageType, int nDamage) +{ + assert(pPlayer != NULL); + if (pPlayer->damageControl[nDamageType] || pPlayer->godMode) + return 0; + nDamage = playerDamageArmor(pPlayer, nDamageType, nDamage); + pPlayer->painEffect = ClipHigh(pPlayer->painEffect + (nDamage >> 3), 600); + + DBloodActor* pActor = pPlayer->actor; + DUDEINFO* pDudeInfo = getDudeInfo(pActor->spr.type); + int nDeathSeqID = -1; + int nKneelingPlayer = -1; + bool va = playerSeqPlaying(pPlayer, 16); + if (!pActor->xspr.health) + { + if (va) + { + switch (nDamageType) + { + case kDamageSpirit: + nDeathSeqID = 18; + sfxPlay3DSound(pPlayer->actor, 716, 0, 0); + break; + case kDamageExplode: + GibSprite(pActor, GIBTYPE_7, NULL, NULL); + GibSprite(pActor, GIBTYPE_15, NULL, NULL); + pPlayer->actor->spr.cstat |= CSTAT_SPRITE_INVISIBLE; + nDeathSeqID = 17; + break; + default: + { + int top, bottom; + GetActorExtents(pActor, &top, &bottom); + CGibPosition gibPos(pActor->spr.pos.X, pActor->spr.pos.Y, top); + CGibVelocity gibVel(pActor->xvel >> 1, pActor->yvel >> 1, -0xccccc); + GibSprite(pActor, GIBTYPE_27, &gibPos, &gibVel); + GibSprite(pActor, GIBTYPE_7, NULL, NULL); + fxSpawnBlood(pActor, nDamage << 4); + fxSpawnBlood(pActor, nDamage << 4); + nDeathSeqID = 17; + break; + } + } + } + } + else + { + int nHealth = pActor->xspr.health - nDamage; + pActor->xspr.health = ClipLow(nHealth, 0); + if (pActor->xspr.health > 0 && pActor->xspr.health < 16) + { + nDamageType = kDamageBullet; + pActor->xspr.health = 0; + nHealth = -25; + } + if (pActor->xspr.health > 0) + { + DAMAGEINFO* pDamageInfo = &damageInfo[nDamageType]; + int nSound; + if (nDamage >= (10 << 4)) + nSound = pDamageInfo->Kills[0]; + else + nSound = pDamageInfo->Kills[Random(3)]; + if (nDamageType == kDamageDrown && pActor->xspr.medium == kMediumWater && !pPlayer->hand) + nSound = 714; + sfxPlay3DSound(pPlayer->actor, nSound, 0, 6); + return nDamage; + } + sfxKill3DSound(pPlayer->actor, -1, 441); + if (gGameOptions.nGameType == 3 && pPlayer->hasFlag) { + if (pPlayer->hasFlag & 1) flagDropped(pPlayer, kItemFlagA); + if (pPlayer->hasFlag & 2) flagDropped(pPlayer, kItemFlagB); + } + pPlayer->deathTime = 0; + pPlayer->qavLoop = 0; + pPlayer->curWeapon = kWeapNone; + pPlayer->fragger = source; + pPlayer->voodooTargets = 0; + if (nDamageType == kDamageExplode && nDamage < (9 << 4)) + nDamageType = kDamageFall; + switch (nDamageType) + { + case kDamageExplode: + sfxPlay3DSound(pPlayer->actor, 717, 0, 0); + GibSprite(pActor, GIBTYPE_7, NULL, NULL); + GibSprite(pActor, GIBTYPE_15, NULL, NULL); + pPlayer->actor->spr.cstat |= CSTAT_SPRITE_INVISIBLE; + nDeathSeqID = 2; + break; + case kDamageBurn: + sfxPlay3DSound(pPlayer->actor, 718, 0, 0); + nDeathSeqID = 3; + break; + case kDamageDrown: + nDeathSeqID = 1; + break; + default: + if (nHealth < -20 && gGameOptions.nGameType >= 2 && Chance(0x4000)) + { + DAMAGEINFO* pDamageInfo = &damageInfo[nDamageType]; + sfxPlay3DSound(pPlayer->actor, pDamageInfo->at10[0], 0, 2); + nDeathSeqID = 16; + nKneelingPlayer = nPlayerKneelClient; + powerupActivate(pPlayer, kPwUpDeliriumShroom); + pActor->SetTarget(source); + evPostActor(pPlayer->actor, 15, kCallbackFinishHim); + } + else + { + sfxPlay3DSound(pPlayer->actor, 716, 0, 0); + nDeathSeqID = 1; + } + break; + } + } + if (nDeathSeqID < 0) + return nDamage; + if (nDeathSeqID != 16) + { + powerupClear(pPlayer); + if (pActor->spr.sector()->hasX() && pActor->spr.sector()->xs().Exit) + trTriggerSector(pActor->spr.sector(), kCmdSectorExit); + pActor->spr.flags |= 7; + for (int p = connecthead; p >= 0; p = connectpoint2[p]) + { + if (gPlayer[p].fragger == pPlayer->actor && gPlayer[p].deathTime > 0) + gPlayer[p].fragger = nullptr; + } + FragPlayer(pPlayer, source); + trTriggerSprite(pActor, kCmdOff); + +#ifdef NOONE_EXTENSIONS + // allow drop items and keys in multiplayer + if (gModernMap && gGameOptions.nGameType != 0 && pPlayer->actor->xspr.health <= 0) { + + DBloodActor* pItem = nullptr; + if (pPlayer->actor->xspr.dropMsg && (pItem = actDropItem(pActor, pPlayer->actor->xspr.dropMsg)) != NULL) + evPostActor(pItem, 500, kCallbackRemove); + + if (pPlayer->actor->xspr.key) { + + int i; // if all players have this key, don't drop it + for (i = connecthead; i >= 0; i = connectpoint2[i]) { + if (!gPlayer[i].hasKey[pPlayer->actor->xspr.key]) + break; + } + + if (i == 0 && (pItem = actDropKey(pActor, (pPlayer->actor->xspr.key + kItemKeyBase) - 1)) != NULL) + evPostActor(pItem, 500, kCallbackRemove); + + } + + + } +#endif + + } + assert(getSequence(pDudeInfo->seqStartID + nDeathSeqID) != NULL); + seqSpawn(pDudeInfo->seqStartID + nDeathSeqID, pPlayer->actor, nKneelingPlayer); + return nDamage; +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +int UseAmmo(PLAYER* pPlayer, int nAmmoType, int nDec) +{ + if (gInfiniteAmmo) + return 9999; + if (nAmmoType == -1) + return 9999; + pPlayer->ammoCount[nAmmoType] = ClipLow(pPlayer->ammoCount[nAmmoType] - nDec, 0); + return pPlayer->ammoCount[nAmmoType]; +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void voodooTarget(PLAYER* pPlayer) +{ + DBloodActor* actor = pPlayer->actor; + int v4 = pPlayer->aim.dz; + int dz = pPlayer->zWeapon - pPlayer->actor->spr.pos.Z; + if (UseAmmo(pPlayer, 9, 0) < 8) + { + pPlayer->voodooTargets = 0; + return; + } + for (int i = 0; i < 4; i++) + { + int ang1 = (pPlayer->voodooVar1 + pPlayer->vodooVar2) & 2047; + actFireVector(actor, 0, dz, bcos(ang1), bsin(ang1), v4, kVectorVoodoo10); + int ang2 = (pPlayer->voodooVar1 + 2048 - pPlayer->vodooVar2) & 2047; + actFireVector(actor, 0, dz, bcos(ang2), bsin(ang2), v4, kVectorVoodoo10); + } + pPlayer->voodooTargets = ClipLow(pPlayer->voodooTargets - 1, 0); +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void playerLandingSound(PLAYER* pPlayer) +{ + static int surfaceSound[] = { + -1, + 600, + 601, + 602, + 603, + 604, + 605, + 605, + 605, + 600, + 605, + 605, + 605, + 604, + 603 + }; + SPRITEHIT* pHit = &pPlayer->actor->hit; + if (pHit->florhit.type != kHitNone) + { + if (!gGameOptions.bFriendlyFire && pHit->florhit.type == kHitSprite && IsTargetTeammate(pPlayer, pHit->florhit.actor())) + return; + int nSurf = tileGetSurfType(pHit->florhit); + if (nSurf) + sfxPlay3DSound(pPlayer->actor, surfaceSound[nSurf], -1, 0); + } +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void PlayerSurvive(int, DBloodActor* actor) { - char buffer[80]; - actHealDude(actor, 1, 2); - if (gGameOptions.nGameType > 0 && numplayers > 1) - { - sfxPlay3DSound(actor, 3009, 0, 6); - if (actor->IsPlayerActor()) - { - PLAYER *pPlayer = &gPlayer[actor->spr.type-kDudePlayer1]; - if (pPlayer == gMe) - viewSetMessage(GStrings("TXT_LIVEAGAIM")); - else - { - sprintf(buffer, "%s lives again!", PlayerName(pPlayer->nPlayer)); - viewSetMessage(buffer); - } - pPlayer->newWeapon = kWeapPitchFork; - } - } + char buffer[80]; + actHealDude(actor, 1, 2); + if (gGameOptions.nGameType > 0 && numplayers > 1) + { + sfxPlay3DSound(actor, 3009, 0, 6); + if (actor->IsPlayerActor()) + { + PLAYER* pPlayer = &gPlayer[actor->spr.type - kDudePlayer1]; + if (pPlayer == gMe) + viewSetMessage(GStrings("TXT_LIVEAGAIM")); + else + { + sprintf(buffer, "%s lives again!", PlayerName(pPlayer->nPlayer)); + viewSetMessage(buffer); + } + pPlayer->newWeapon = kWeapPitchFork; + } + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void PlayerKneelsOver(int, DBloodActor* actor) { - for (int p = connecthead; p >= 0; p = connectpoint2[p]) - { - if (gPlayer[p].actor == actor) - { - PLAYER *pPlayer = &gPlayer[p]; - playerDamageSprite(pPlayer->fragger, pPlayer, kDamageSpirit, 500<<4); - return; - } - } + for (int p = connecthead; p >= 0; p = connectpoint2[p]) + { + if (gPlayer[p].actor == actor) + { + PLAYER* pPlayer = &gPlayer[p]; + playerDamageSprite(pPlayer->fragger, pPlayer, kDamageSpirit, 500 << 4); + return; + } + } } @@ -2194,200 +2430,212 @@ void PlayerKneelsOver(int, DBloodActor* actor) FSerializer& Serialize(FSerializer& arc, const char* keyname, Aim& w, Aim* def) { - if (arc.BeginObject(keyname)) - { - arc("x", w.dx) - ("y", w.dx) - ("z", w.dx) - .EndObject(); - } - return arc; + if (arc.BeginObject(keyname)) + { + arc("x", w.dx) + ("y", w.dx) + ("z", w.dx) + .EndObject(); + } + return arc; } FSerializer& Serialize(FSerializer& arc, const char* keyname, PACKINFO& w, PACKINFO* def) { - if (arc.BeginObject(keyname)) - { - arc("isactive", w.isActive) - ("curamount", w.curAmount) - .EndObject(); - } - return arc; + if (arc.BeginObject(keyname)) + { + arc("isactive", w.isActive) + ("curamount", w.curAmount) + .EndObject(); + } + return arc; } FSerializer& Serialize(FSerializer& arc, const char* keyname, POSTURE& w, POSTURE* def) { - if (arc.BeginObject(keyname)) - { - arc("frontaccel", w.frontAccel, def->frontAccel) - ("sideaccel", w.sideAccel, def->sideAccel) - ("backaccel", w.backAccel, def->backAccel) - ("pace0", w.pace[0], def->pace[0]) - ("pace1", w.pace[1], def->pace[1]) - ("bobv", w.bobV, def->bobV) - ("bobh", w.bobH, def->bobH) - ("swayv", w.swayV, def->swayV) - ("swayh", w.swayH, def->swayH) - ("eyeabovez", w.eyeAboveZ, def->eyeAboveZ) - ("weaponabovez", w.weaponAboveZ, def->weaponAboveZ) - ("xoffset", w.xOffset, def->xOffset) - ("zoffset", w.zOffset, def->zOffset) - ("normaljumpz", w.normalJumpZ, def->normalJumpZ) - ("pwupjumpz", w.pwupJumpZ, def->pwupJumpZ) - .EndObject(); - } - return arc; + if (arc.BeginObject(keyname)) + { + arc("frontaccel", w.frontAccel, def->frontAccel) + ("sideaccel", w.sideAccel, def->sideAccel) + ("backaccel", w.backAccel, def->backAccel) + ("pace0", w.pace[0], def->pace[0]) + ("pace1", w.pace[1], def->pace[1]) + ("bobv", w.bobV, def->bobV) + ("bobh", w.bobH, def->bobH) + ("swayv", w.swayV, def->swayV) + ("swayh", w.swayH, def->swayH) + ("eyeabovez", w.eyeAboveZ, def->eyeAboveZ) + ("weaponabovez", w.weaponAboveZ, def->weaponAboveZ) + ("xoffset", w.xOffset, def->xOffset) + ("zoffset", w.zOffset, def->zOffset) + ("normaljumpz", w.normalJumpZ, def->normalJumpZ) + ("pwupjumpz", w.pwupJumpZ, def->pwupJumpZ) + .EndObject(); + } + return arc; } FSerializer& Serialize(FSerializer& arc, const char* keyname, PLAYER& w, PLAYER* def) { - if (arc.isReading()) playerResetPosture(&w); - if (arc.BeginObject(keyname)) - { - arc("spritenum", w.actor) - ("horizon", w.horizon) - ("angle", w.angle) - ("newweapon", w.newWeapon) - ("used1", w.used1) - ("weaponqav", w.weaponQav) - ("qavcallback", w.qavCallback) - ("isrunning", w.isRunning) - ("posture", w.posture) - ("sceneqav", w.sceneQav) - ("bobphase", w.bobPhase) - ("bobamp", w.bobAmp) - ("bobheight", w.bobHeight) - ("bobwidth", w.bobWidth) - ("swayphase", w.swayPhase) - ("swayamp", w.swayAmp) - ("swayheight", w.swayHeight) - ("swaywidth", w.swayWidth) - ("nplayer", w.nPlayer) - ("lifemode", w.lifeMode) - ("bloodlust", w.bloodlust) - ("zview", w.zView) - ("zviewvel", w.zViewVel) - ("zweapon", w.zWeapon) - ("zweaponvel", w.zWeaponVel) - ("slope", w.slope) - ("underwater", w.isUnderwater) - .Array("haskey", w.hasKey, 8) - ("hasflag", w.hasFlag) - .Array("ctfflagstate", w.ctfFlagState, 2) - .Array("dmgcontrol", w.damageControl, 7) - ("curweapon", w.curWeapon) - ("nextweapon", w.nextWeapon) - ("weapontimer", w.weaponTimer) - ("weaponstate", w.weaponState) - ("weaponammo", w.weaponAmmo) - .Array("hasweapon", w.hasWeapon, countof(w.hasWeapon)) - .Array("weaponmode", w.weaponMode, countof(w.weaponMode)) - .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) - ("aim", w.aim) - ("relaim", w.relAim) - ("aimtarget", w.aimTarget) - ("aimtargetscount", w.aimTargetsCount) - .Array("aimtargets", w.aimTargets, countof(w.aimTargets)) - ("deathtime", w.deathTime) - .Array("pwuptime", w.pwUpTime, countof(w.pwUpTime)) - ("fragcount", w.fragCount) - .Array("fraginfo", w.fragInfo, countof(w.fragInfo)) - ("teamid", w.teamId) - ("fraggerid", w.fragger) - ("undserwatertime", w.underwaterTime) - ("bubbletime", w.bubbleTime) - ("resttime", w.restTime) - ("kickpower", w.kickPower) - ("laughcount", w.laughCount) - ("godmode", w.godMode) - ("fallscream", w.fallScream) - ("cantjump", w.cantJump) - ("packitemtime", w.packItemTime) - ("packitemid", w.packItemId) - .Array("packslots", w.packSlots, countof(w.packSlots)) - .Array("armor", w.armor, countof(w.armor)) - ("voodootarget", w.voodooTarget) - ("voodootargets", w.voodooTargets) - ("voodoovar1", w.voodooVar1) - ("voodoovar2", w.vodooVar2) - ("flickereffect", w.flickerEffect) - ("tilteffect", w.tiltEffect) - ("visibility", w.visibility) - ("paineffect", w.painEffect) - ("blindeffect", w.blindEffect) - ("chokeeffect", w.chokeEffect) - ("handtime", w.handTime) - ("hand", w.hand) - ("pickupeffect", w.pickupEffect) - ("flasheffect", w.flashEffect) - ("quakeeffect", w.quakeEffect) - ("player_par", w.player_par) - ("waterpal", w.nWaterPal) - .Array("posturedata", &w.pPosture[0][0], &gPostureDefaults[0][0], kModeMax * kPostureMax) // only save actual changes in this. - .EndObject(); - } - return arc; + if (arc.isReading()) playerResetPosture(&w); + if (arc.BeginObject(keyname)) + { + arc("spritenum", w.actor) + ("horizon", w.horizon) + ("angle", w.angle) + ("newweapon", w.newWeapon) + ("used1", w.used1) + ("weaponqav", w.weaponQav) + ("qavcallback", w.qavCallback) + ("isrunning", w.isRunning) + ("posture", w.posture) + ("sceneqav", w.sceneQav) + ("bobphase", w.bobPhase) + ("bobamp", w.bobAmp) + ("bobheight", w.bobHeight) + ("bobwidth", w.bobWidth) + ("swayphase", w.swayPhase) + ("swayamp", w.swayAmp) + ("swayheight", w.swayHeight) + ("swaywidth", w.swayWidth) + ("nplayer", w.nPlayer) + ("lifemode", w.lifeMode) + ("bloodlust", w.bloodlust) + ("zview", w.zView) + ("zviewvel", w.zViewVel) + ("zweapon", w.zWeapon) + ("zweaponvel", w.zWeaponVel) + ("slope", w.slope) + ("underwater", w.isUnderwater) + .Array("haskey", w.hasKey, 8) + ("hasflag", w.hasFlag) + .Array("ctfflagstate", w.ctfFlagState, 2) + .Array("dmgcontrol", w.damageControl, 7) + ("curweapon", w.curWeapon) + ("nextweapon", w.nextWeapon) + ("weapontimer", w.weaponTimer) + ("weaponstate", w.weaponState) + ("weaponammo", w.weaponAmmo) + .Array("hasweapon", w.hasWeapon, countof(w.hasWeapon)) + .Array("weaponmode", w.weaponMode, countof(w.weaponMode)) + .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) + ("aim", w.aim) + ("relaim", w.relAim) + ("aimtarget", w.aimTarget) + ("aimtargetscount", w.aimTargetsCount) + .Array("aimtargets", w.aimTargets, countof(w.aimTargets)) + ("deathtime", w.deathTime) + .Array("pwuptime", w.pwUpTime, countof(w.pwUpTime)) + ("fragcount", w.fragCount) + .Array("fraginfo", w.fragInfo, countof(w.fragInfo)) + ("teamid", w.teamId) + ("fraggerid", w.fragger) + ("undserwatertime", w.underwaterTime) + ("bubbletime", w.bubbleTime) + ("resttime", w.restTime) + ("kickpower", w.kickPower) + ("laughcount", w.laughCount) + ("godmode", w.godMode) + ("fallscream", w.fallScream) + ("cantjump", w.cantJump) + ("packitemtime", w.packItemTime) + ("packitemid", w.packItemId) + .Array("packslots", w.packSlots, countof(w.packSlots)) + .Array("armor", w.armor, countof(w.armor)) + ("voodootarget", w.voodooTarget) + ("voodootargets", w.voodooTargets) + ("voodoovar1", w.voodooVar1) + ("voodoovar2", w.vodooVar2) + ("flickereffect", w.flickerEffect) + ("tilteffect", w.tiltEffect) + ("visibility", w.visibility) + ("paineffect", w.painEffect) + ("blindeffect", w.blindEffect) + ("chokeeffect", w.chokeEffect) + ("handtime", w.handTime) + ("hand", w.hand) + ("pickupeffect", w.pickupEffect) + ("flasheffect", w.flashEffect) + ("quakeeffect", w.quakeEffect) + ("player_par", w.player_par) + ("waterpal", w.nWaterPal) + .Array("posturedata", &w.pPosture[0][0], &gPostureDefaults[0][0], kModeMax * kPostureMax) // only save actual changes in this. + .EndObject(); + } + return arc; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + #ifdef NOONE_EXTENSIONS FSerializer& Serialize(FSerializer& arc, const char* keyname, TRPLAYERCTRL& w, TRPLAYERCTRL* def) { - if (arc.BeginObject(keyname)) - { - arc("index", w.qavScene.initiator) - ("dummy", w.qavScene.dummy) - .EndObject(); - } - if (arc.isReading()) w.qavScene.qavResrc = nullptr; - return arc; + if (arc.BeginObject(keyname)) + { + arc("index", w.qavScene.initiator) + ("dummy", w.qavScene.dummy) + .EndObject(); + } + if (arc.isReading()) w.qavScene.qavResrc = nullptr; + return arc; } #endif +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void SerializePlayers(FSerializer& arc) { - if (arc.BeginObject("players")) - { - arc("numplayers", gNetPlayers) - .Array("teamscore", team_score, gNetPlayers) - .Array("players", gPlayer, gNetPlayers) + if (arc.BeginObject("players")) + { + arc("numplayers", gNetPlayers) + .Array("teamscore", team_score, gNetPlayers) + .Array("players", gPlayer, gNetPlayers) #ifdef NOONE_EXTENSIONS - .Array("playerctrl", gPlayerCtrl, gNetPlayers) + .Array("playerctrl", gPlayerCtrl, gNetPlayers) #endif - .EndObject(); - } + .EndObject(); + } - if (arc.isReading()) - { - for (int i = 0; i < gNetPlayers; i++) - { - gPlayer[i].pDudeInfo = &dudeInfo[gPlayer[i].actor->spr.type - kDudeBase]; + if (arc.isReading()) + { + for (int i = 0; i < gNetPlayers; i++) + { + gPlayer[i].pDudeInfo = &dudeInfo[gPlayer[i].actor->spr.type - kDudeBase]; #ifdef NOONE_EXTENSIONS - // load qav scene - if (gPlayer[i].sceneQav != -1) - { - QAV* pQav = playerQavSceneLoad(gPlayer[i].sceneQav); - if (pQav) - { - gPlayerCtrl[i].qavScene.qavResrc = pQav; - //gPlayerCtrl[i].qavScene.qavResrc->Preload(); - } - else - { - gPlayer[i].sceneQav = -1; - } - } + // load qav scene + if (gPlayer[i].sceneQav != -1) + { + QAV* pQav = playerQavSceneLoad(gPlayer[i].sceneQav); + if (pQav) + { + gPlayerCtrl[i].qavScene.qavResrc = pQav; + //gPlayerCtrl[i].qavScene.qavResrc->Preload(); + } + else + { + gPlayer[i].sceneQav = -1; + } + } #endif - } - } + } + } } diff --git a/source/games/blood/src/player.h b/source/games/blood/src/player.h index 1745c5596..47eeeb550 100644 --- a/source/games/blood/src/player.h +++ b/source/games/blood/src/player.h @@ -36,166 +36,166 @@ BEGIN_BLD_NS // life modes of the player enum { - kModeHuman = 0, - kModeBeast = 1, - kModeHumanShrink = 2, - kModeHumanGrown = 3, - kModeMax = 4, + kModeHuman = 0, + kModeBeast = 1, + kModeHumanShrink = 2, + kModeHumanGrown = 3, + kModeMax = 4, }; // postures enum { - kPostureStand = 0, - kPostureSwim = 1, - kPostureCrouch = 2, - kPostureMax = 3, + kPostureStand = 0, + kPostureSwim = 1, + kPostureCrouch = 2, + kPostureMax = 3, }; struct PACKINFO { - bool isActive; // is active (0/1) - int curAmount = 0; // remaining percent + bool isActive; // is active (0/1) + int curAmount = 0; // remaining percent }; struct POSTURE { - int frontAccel; - int sideAccel; - int backAccel; - int pace[2]; - int bobV; - int bobH; - int swayV; - int swayH; - int eyeAboveZ; - int weaponAboveZ; - int xOffset; - int zOffset; - int normalJumpZ; - int pwupJumpZ; + int frontAccel; + int sideAccel; + int backAccel; + int pace[2]; + int bobV; + int bobH; + int swayV; + int swayH; + int eyeAboveZ; + int weaponAboveZ; + int xOffset; + int zOffset; + int normalJumpZ; + int pwupJumpZ; }; extern POSTURE gPostureDefaults[kModeMax][kPostureMax]; struct PLAYER { - DBloodActor* actor; - DUDEINFO* pDudeInfo; - InputPacket input; - PlayerHorizon horizon; - PlayerAngle angle; - uint8_t newWeapon; - int used1; // something related to game checksum - int weaponQav; - int qavCallback; - bool isRunning; - int posture; // stand, crouch, swim - int sceneQav; // by NoOne: used to keep qav id - int bobPhase; - int bobAmp; - int bobHeight; - int bobWidth; - int swayPhase; - int swayAmp; - int swayHeight; - int swayWidth; - int nPlayer; // Connect id - int lifeMode; - int bloodlust; // ---> useless - int zView; - int zViewVel; - int zWeapon; - int zWeaponVel; - int slope; - bool isUnderwater; - bool hasKey[8]; - int8_t hasFlag; - TObjPtr ctfFlagState[2]; - int damageControl[7]; - int8_t curWeapon; - int8_t nextWeapon; - int weaponTimer; - int weaponState; - int weaponAmmo; //rename - bool hasWeapon[14]; - int weaponMode[14]; - int weaponOrder[2][14]; - //int at149[14]; - int ammoCount[12]; - bool qavLoop; - int qavLastTick; - int qavTimer; - int fuseTime; - int throwTime; - int throwPower; - Aim aim; // world - //int at1c6; - Aim relAim; // relative - //int relAim; - //int at1ce; - //int at1d2; - TObjPtr aimTarget; // aim target sprite - int aimTargetsCount; - TObjPtr aimTargets[16]; - int deathTime; - int pwUpTime[kMaxPowerUps]; - int fragCount; - int fragInfo[8]; - int teamId; - TObjPtr fragger; - int underwaterTime; - int bubbleTime; - int restTime; - int kickPower; - int laughCount; - bool godMode; - bool fallScream; - bool cantJump; - int packItemTime; // pack timer - int packItemId; // pack id 1: diving suit, 2: crystal ball, 3: beast vision 4: jump boots - PACKINFO packSlots[5]; // at325 [1]: diving suit, [2]: crystal ball, [3]: beast vision [4]: jump boots - int armor[3]; // armor - //int at342; - //int at346; - TObjPtr voodooTarget; - int voodooTargets; // --> useless - int voodooVar1; // --> useless - int vodooVar2; // --> useless - int flickerEffect; - int tiltEffect; - int visibility; - int painEffect; - int blindEffect; - int chokeEffect; - int handTime; - bool hand; // if true, there is hand start choking the player - int pickupEffect; - bool flashEffect; // if true, reduce pPlayer->visibility counter - int quakeEffect; - int player_par; - int nWaterPal; - POSTURE pPosture[kModeMax][kPostureMax]; + DBloodActor* actor; + DUDEINFO* pDudeInfo; + InputPacket input; + PlayerHorizon horizon; + PlayerAngle angle; + uint8_t newWeapon; + int used1; // something related to game checksum + int weaponQav; + int qavCallback; + bool isRunning; + int posture; // stand, crouch, swim + int sceneQav; // by NoOne: used to keep qav id + int bobPhase; + int bobAmp; + int bobHeight; + int bobWidth; + int swayPhase; + int swayAmp; + int swayHeight; + int swayWidth; + int nPlayer; // Connect id + int lifeMode; + int bloodlust; // ---> useless + int zView; + int zViewVel; + int zWeapon; + int zWeaponVel; + int slope; + bool isUnderwater; + bool hasKey[8]; + int8_t hasFlag; + TObjPtr ctfFlagState[2]; + int damageControl[7]; + int8_t curWeapon; + int8_t nextWeapon; + int weaponTimer; + int weaponState; + int weaponAmmo; //rename + bool hasWeapon[14]; + int weaponMode[14]; + int weaponOrder[2][14]; + //int at149[14]; + int ammoCount[12]; + bool qavLoop; + int qavLastTick; + int qavTimer; + int fuseTime; + int throwTime; + int throwPower; + Aim aim; // world + //int at1c6; + Aim relAim; // relative + //int relAim; + //int at1ce; + //int at1d2; + TObjPtr aimTarget; // aim target sprite + int aimTargetsCount; + TObjPtr aimTargets[16]; + int deathTime; + int pwUpTime[kMaxPowerUps]; + int fragCount; + int fragInfo[8]; + int teamId; + TObjPtr fragger; + int underwaterTime; + int bubbleTime; + int restTime; + int kickPower; + int laughCount; + bool godMode; + bool fallScream; + bool cantJump; + int packItemTime; // pack timer + int packItemId; // pack id 1: diving suit, 2: crystal ball, 3: beast vision 4: jump boots + PACKINFO packSlots[5]; // at325 [1]: diving suit, [2]: crystal ball, [3]: beast vision [4]: jump boots + int armor[3]; // armor + //int at342; + //int at346; + TObjPtr voodooTarget; + int voodooTargets; // --> useless + int voodooVar1; // --> useless + int vodooVar2; // --> useless + int flickerEffect; + int tiltEffect; + int visibility; + int painEffect; + int blindEffect; + int chokeEffect; + int handTime; + bool hand; // if true, there is hand start choking the player + int pickupEffect; + bool flashEffect; // if true, reduce pPlayer->visibility counter + int quakeEffect; + int player_par; + int nWaterPal; + POSTURE pPosture[kModeMax][kPostureMax]; }; struct AMMOINFO { - int max; - int8_t vectorType; + int max; + int8_t vectorType; }; struct POWERUPINFO { - int16_t picnum; - bool pickupOnce; - int bonusTime; - int maxTime; + int16_t picnum; + bool pickupOnce; + int bonusTime; + int maxTime; }; void playerResetPosture(PLAYER* pPlayer); extern PLAYER gPlayer[kMaxPlayers]; -extern PLAYER *gMe, *gView; +extern PLAYER* gMe, * gView; extern bool gBlueFlagDropped; extern bool gRedFlagDropped; @@ -206,39 +206,39 @@ extern AMMOINFO gAmmoInfo[]; extern POWERUPINFO gPowerUpInfo[kMaxPowerUps]; bool IsTargetTeammate(PLAYER* pSourcePlayer, DBloodActor* target); -int powerupCheck(PLAYER *pPlayer, int nPowerUp); -bool powerupActivate(PLAYER *pPlayer, int nPowerUp); -void powerupDeactivate(PLAYER *pPlayer, int nPowerUp); -void powerupSetState(PLAYER *pPlayer, int nPowerUp, bool bState); -void powerupProcess(PLAYER *pPlayer); -void powerupClear(PLAYER *pPlayer); +int powerupCheck(PLAYER* pPlayer, int nPowerUp); +bool powerupActivate(PLAYER* pPlayer, int nPowerUp); +void powerupDeactivate(PLAYER* pPlayer, int nPowerUp); +void powerupSetState(PLAYER* pPlayer, int nPowerUp, bool bState); +void powerupProcess(PLAYER* pPlayer); +void powerupClear(PLAYER* pPlayer); int packItemToPowerup(int nPack); int powerupToPackItem(int nPowerUp); -bool packAddItem(PLAYER *pPlayer, unsigned int nPack); -int packCheckItem(PLAYER *pPlayer, int nPack); -bool packItemActive(PLAYER *pPlayer, int nPack); -void packUseItem(PLAYER *pPlayer, int nPack); -void packPrevItem(PLAYER *pPlayer); -void packNextItem(PLAYER *pPlayer); -bool playerSeqPlaying(PLAYER *pPlayer, int nSeq); -void playerSetRace(PLAYER *pPlayer, int nLifeMode); -void playerSetGodMode(PLAYER *pPlayer, bool bGodMode); -void playerResetInertia(PLAYER *pPlayer); -void playerCorrectInertia(PLAYER *pPlayer, vec3_t const *oldpos); +bool packAddItem(PLAYER* pPlayer, unsigned int nPack); +int packCheckItem(PLAYER* pPlayer, int nPack); +bool packItemActive(PLAYER* pPlayer, int nPack); +void packUseItem(PLAYER* pPlayer, int nPack); +void packPrevItem(PLAYER* pPlayer); +void packNextItem(PLAYER* pPlayer); +bool playerSeqPlaying(PLAYER* pPlayer, int nSeq); +void playerSetRace(PLAYER* pPlayer, int nLifeMode); +void playerSetGodMode(PLAYER* pPlayer, bool bGodMode); +void playerResetInertia(PLAYER* pPlayer); +void playerCorrectInertia(PLAYER* pPlayer, vec3_t const* oldpos); void playerStart(int nPlayer, int bNewLevel = 0); -void playerReset(PLAYER *pPlayer); +void playerReset(PLAYER* pPlayer); void playerInit(int nPlayer, unsigned int a2); -void CheckPickUp(PLAYER *pPlayer); -void ProcessInput(PLAYER *pPlayer); -void playerProcess(PLAYER *pPlayer); -DBloodActor *playerFireMissile(PLAYER *pPlayer, int a2, int a3, int a4, int a5, int a6); -DBloodActor *playerFireThing(PLAYER *pPlayer, int a2, int a3, int thingType, int a5); -void playerFrag(PLAYER *pKiller, PLAYER *pVictim); -int playerDamageArmor(PLAYER *pPlayer, DAMAGE_TYPE nType, int nDamage); -int playerDamageSprite(DBloodActor* nSource, PLAYER *pPlayer, DAMAGE_TYPE nDamageType, int nDamage); -int UseAmmo(PLAYER *pPlayer, int nAmmoType, int nDec); -void voodooTarget(PLAYER *pPlayer); -void playerLandingSound(PLAYER *pPlayer); +void CheckPickUp(PLAYER* pPlayer); +void ProcessInput(PLAYER* pPlayer); +void playerProcess(PLAYER* pPlayer); +DBloodActor* playerFireMissile(PLAYER* pPlayer, int a2, int a3, int a4, int a5, int a6); +DBloodActor* playerFireThing(PLAYER* pPlayer, int a2, int a3, int thingType, int a5); +void playerFrag(PLAYER* pKiller, PLAYER* pVictim); +int playerDamageArmor(PLAYER* pPlayer, DAMAGE_TYPE nType, int nDamage); +int playerDamageSprite(DBloodActor* nSource, PLAYER* pPlayer, DAMAGE_TYPE nDamageType, int nDamage); +int UseAmmo(PLAYER* pPlayer, int nAmmoType, int nDec); +void voodooTarget(PLAYER* pPlayer); +void playerLandingSound(PLAYER* pPlayer); void PlayerSurvive(int, DBloodActor*); END_BLD_NS diff --git a/source/games/blood/src/prediction.cpp b/source/games/blood/src/prediction.cpp index 6953e719d..8d67925cf 100644 --- a/source/games/blood/src/prediction.cpp +++ b/source/games/blood/src/prediction.cpp @@ -56,7 +56,7 @@ void viewInitializePrediction(void) predict.at6f = gMe->cantJump; predict.at70 = gMe->isRunning; predict.at72 = gMe->isUnderwater; - predict.at71 = !!(gMe->input.actions & SB_JUMP); + predict.at71 = !!(gMe->input.actions & SB_JUMP); predict.x = gMe->actor->spr.x; predict.y = gMe->actor->spr.y; predict.z = gMe->actor->spr.z; @@ -78,275 +78,275 @@ void viewInitializePrediction(void) predict.at14 = gMe->swayAmp; predict.shakeBobY = gMe->swayHeight; predict.shakeBobX = gMe->swayWidth; - predict.weaponZ = gMe->zWeapon-gMe->zView-(12<<8); + predict.weaponZ = gMe->zWeapon - gMe->zView - (12 << 8); predict.viewz = gMe->zView; predict.at3c = gMe->zViewVel; predict.at40 = gMe->zWeapon; predict.at44 = gMe->zWeaponVel; - predictOld = predict; + predictOld = predict; #endif } -void viewUpdatePrediction(InputPacket *pInput) +void viewUpdatePrediction(InputPacket* pInput) { - predictOld = predict; + predictOld = predict; auto bakCstat = gMe->actor->spr.cstat; - gMe->actor->spr.cstat = 0; - fakePlayerProcess(gMe, pInput); - fakeActProcessSprites(); - gMe->actor->spr.cstat = bakCstat; - //predictFifo[gPredictTail&255] = predict; - //gPredictTail++; + gMe->actor->spr.cstat = 0; + fakePlayerProcess(gMe, pInput); + fakeActProcessSprites(); + gMe->actor->spr.cstat = bakCstat; + //predictFifo[gPredictTail&255] = predict; + //gPredictTail++; } -static void sub_158B4(PLAYER *pPlayer) +static void sub_158B4(PLAYER* pPlayer) { - predict.viewz = predict.z - pPlayer->pPosture[pPlayer->lifeMode][predict.at48].eyeAboveZ; - predict.at40 = predict.z - pPlayer->pPosture[pPlayer->lifeMode][predict.at48].weaponAboveZ; + predict.viewz = predict.z - pPlayer->pPosture[pPlayer->lifeMode][predict.at48].eyeAboveZ; + predict.at40 = predict.z - pPlayer->pPosture[pPlayer->lifeMode][predict.at48].weaponAboveZ; } -static void fakeProcessInput(PLAYER *pPlayer, InputPacket *pInput) +static void fakeProcessInput(PLAYER* pPlayer, InputPacket* pInput) { #if 0 - POSTURE *pPosture = &pPlayer->pPosture[pPlayer->lifeMode][predict.at48]; + POSTURE* pPosture = &pPlayer->pPosture[pPlayer->lifeMode][predict.at48]; - predict.at70 = !!(gMe->input.actions & SB_RUN); - predict.at71 = !!(gMe->input.actions & SB_JUMP); - if (predict.at48 == 1) - { - int x = Cos(predict.angle.asbuild()); - int y = Sin(predict.angle.asbuild()); - if (pInput->fvel) - { - int forward = pInput->fvel; - if (forward > 0) - forward = MulScale(pPosture->frontAccel, forward, 8); - else - forward = MulScale(pPosture->backAccel, forward, 8); - predict.xvel += MulScale(forward, x, 30); - predict.yvel += MulScale(forward, y, 30); - } - if (pInput->svel) - { - int strafe = pInput->svel; - strafe = MulScale(pPosture->sideAccel, strafe, 8); - predict.xvel += MulScale(strafe, y, 30); - predict.yvel -= MulScale(strafe, x, 30); - } - } - else if (predict.floordist < 0x100) - { - int speed = 0x10000; - if (predict.floordist > 0) - speed -= DivScale(predict.floordist, 0x100, 16); - int x = Cos(predict.angle.asbuild()); - int y = Sin(predict.angle.asbuild()); - if (pInput->fvel) - { - int forward = pInput->fvel; - if (forward > 0) - forward = MulScale(pPosture->frontAccel, forward, 8); - else - forward = MulScale(pPosture->backAccel, forward, 8); - if (predict.floordist) - forward = MulScale(forward, speed, 16); - predict.xvel += MulScale(forward, x, 30); - predict.yvel += MulScale(forward, y, 30); - } - if (pInput->svel) - { - int strafe = pInput->svel; - strafe = MulScale(pPosture->sideAccel, strafe, 8); - if (predict.floordist) - strafe = MulScale(strafe, speed, 16); - predict.xvel += MulScale(strafe, y, 30); - predict.yvel -= MulScale(strafe, x, 30); - } - } - if (pInput->avel) - predict.angle = degang(pInput->avel); - if (pInput->actions & SB_TURNAROUND) - if (!predict.spin) - predict.spin = -1024; - if (predict.spin < 0) - { - int speed; - if (predict.at48 == 1) - speed = 64; - else - speed = 128; - - predict.spin = min(int(predict.spin) + speed, 0); - predict.angle += buildang(speed); - } - - if (!predict.at71) - predict.at6f = 0; - - switch (predict.at48) - { - case 1: - if (predict.at71) - predict.zvel -= pPosture->normalJumpZ;//0x5b05; - if (pInput->actions & SB_CROUCH) - predict.zvel += pPosture->normalJumpZ;//0x5b05; - break; - case 2: - if (!(pInput->actions & SB_CROUCH)) - predict.at48 = 0; - break; - default: - if (!predict.at6f && predict.at71 && predict.floordist == 0) { - if (packItemActive(pPlayer, 4)) predict.zvel = pPosture->pwupJumpZ;//-0x175555; - else predict.zvel = pPosture->normalJumpZ;//-0xbaaaa; - predict.at6f = 1; - } - if (pInput->actions & SB_CROUCH) - predict.at48 = 2; - break; - } - -#if 0 - if (predict.at6e && !(pInput->actions & (SB_LOOK_UP | SB_LOOK_DOWN))) - { - if (predict.at20 < 0) - predict.at20 = min(predict.at20+IntToFixed(4), 0); - if (predict.at20 > 0) - predict.at20 = max(predict.at20-IntToFixed(4), 0); - if (predict.at20 == 0) - predict.at6e = 0; - } - else - { - if (pInput->actions & SB_LOOK_UP) - predict.at20 = min(predict.at20+IntToFixed(4), IntToFixed(60)); - if (pInput->actions & SB_LOOK_DOWN) - predict.at20 = max(predict.at20-IntToFixed(4), IntToFixed(-60)); - } - predict.at20 = clamp(predict.at20+pInput->horz, IntToFixed(-60), IntToFixed(60)); - - if (predict.at20 > 0) - predict.at24 = FloatToFixed(MulScaleF(120., bsinf(FixedToFloat(predict.at20) * 8., 16)), 30); - else if (predict.at20 < 0) - predict.at24 = FloatToFixed(MulScaleF(180., bsinf(FixedToFloat(predict.at20) * 8., 16)), 30); - else - predict.at24 = 0; -#endif - - int nSector = predict.sector; - int florhit = predict.at75.florhit.type; - bool va = (predict.floordist < 16 && (florhit == kHitSector || florhit == 0)); - - if (va && (sector[nSector].floorstat&2) != 0) - { - int z1 = getflorzofslope(nSector, predict.x, predict.y); - int x2 = predict.x+MulScale(64, Cos(predict.angle.asbuild()), 30); - int y2 = predict.y+MulScale(64, Sin(predict.angle.asbuild()), 30); - int nSector2 = nSector; - updatesector(x2, y2, &nSector2); - if (nSector2 == nSector) - { - int z2 = getflorzofslope(nSector2, x2, y2); - predict.horizoff = interpolatedhorizon(predict.horizoff, q16horiz((z1 - z2) << 13), 0x4000); - } - } - else - { - predict.horizoff = interpolatedhorizon(predict.horizoff, q16horiz(0), 0x4000); - if (abs(predict.horizoff.asq16()) < 4) - predict.horizoff = q16horiz(0); - } - predict.at2c = -predict.horiz.asq16() >> 9; -#endif -} - -void fakePlayerProcess(PLAYER *pPlayer, InputPacket *pInput) -{ -#if 0 - auto pSprite = pPlayer->actor; - POSTURE* pPosture = &pPlayer->pPosture[pPlayer->lifeMode][predict.at48]; - - int top, bottom; - GetSpriteExtents(pSprite, &top, &bottom); - - top += predict.z-pSprite->z; - bottom += predict.z-pSprite->z; - - int dzb = (bottom-predict.z)/4; - int dzt = (predict.z-top)/4; - - int dw = pSprite->clipdist<<2; - int nSector = predict.sector; - if (!gNoClip) - { - pushmove(&predict.pos, &predict.sector, dw, dzt, dzb, CLIPMASK0); - if (predict.sector == -1) - predict.sector = nSector; - } - fakeProcessInput(pPlayer, pInput); - - int nSpeed = approxDist(predict.xvel, predict.yvel); - - predict.at3c = interpolatedvalue(predict.at3c, predict.zvel, 0x7000); - int dz = predict.z-pPosture->eyeAboveZ-predict.viewz; - if (dz > 0) - predict.at3c += MulScale(dz<<8, 0xa000, 16); - else - predict.at3c += MulScale(dz<<8, 0x1800, 16); - predict.viewz += predict.at3c>>8; - - predict.at44 = interpolatedvalue(predict.at44, predict.zvel, 0x5000); - dz = predict.z-pPosture->weaponAboveZ-predict.at40; - if (dz > 0) - predict.at44 += MulScale(dz<<8, 0x8000, 16); - else - predict.at44 += MulScale(dz<<8, 0xc00, 16); - predict.at40 += predict.at44>>8; - - predict.weaponZ = predict.at40 - predict.viewz - (12<<8); - - predict.bobPhase = ClipLow(predict.bobPhase-4, 0); - - nSpeed >>= FRACBITS; + predict.at70 = !!(gMe->input.actions & SB_RUN); + predict.at71 = !!(gMe->input.actions & SB_JUMP); if (predict.at48 == 1) { - predict.Kills = (predict.Kills+17)&2047; - predict.at14 = (predict.at14+17)&2047; - predict.bobHeight = MulScale(10*pPosture->bobV,Sin(predict.Kills*2), 30); - predict.bobWidth = MulScale(predict.bobPhase*pPosture->bobH,Sin(predict.Kills-256), 30); - predict.shakeBobY = MulScale(predict.bobPhase*pPosture->swayV,Sin(predict.at14*2), 30); - predict.shakeBobX = MulScale(predict.bobPhase*pPosture->swayH,Sin(predict.at14-0x155), 30); + int x = Cos(predict.angle.asbuild()); + int y = Sin(predict.angle.asbuild()); + if (pInput->fvel) + { + int forward = pInput->fvel; + if (forward > 0) + forward = MulScale(pPosture->frontAccel, forward, 8); + else + forward = MulScale(pPosture->backAccel, forward, 8); + predict.xvel += MulScale(forward, x, 30); + predict.yvel += MulScale(forward, y, 30); + } + if (pInput->svel) + { + int strafe = pInput->svel; + strafe = MulScale(pPosture->sideAccel, strafe, 8); + predict.xvel += MulScale(strafe, y, 30); + predict.yvel -= MulScale(strafe, x, 30); + } + } + else if (predict.floordist < 0x100) + { + int speed = 0x10000; + if (predict.floordist > 0) + speed -= DivScale(predict.floordist, 0x100, 16); + int x = Cos(predict.angle.asbuild()); + int y = Sin(predict.angle.asbuild()); + if (pInput->fvel) + { + int forward = pInput->fvel; + if (forward > 0) + forward = MulScale(pPosture->frontAccel, forward, 8); + else + forward = MulScale(pPosture->backAccel, forward, 8); + if (predict.floordist) + forward = MulScale(forward, speed, 16); + predict.xvel += MulScale(forward, x, 30); + predict.yvel += MulScale(forward, y, 30); + } + if (pInput->svel) + { + int strafe = pInput->svel; + strafe = MulScale(pPosture->sideAccel, strafe, 8); + if (predict.floordist) + strafe = MulScale(strafe, speed, 16); + predict.xvel += MulScale(strafe, y, 30); + predict.yvel -= MulScale(strafe, x, 30); + } + } + if (pInput->avel) + predict.angle = degang(pInput->avel); + if (pInput->actions & SB_TURNAROUND) + if (!predict.spin) + predict.spin = -1024; + if (predict.spin < 0) + { + int speed; + if (predict.at48 == 1) + speed = 64; + else + speed = 128; + + predict.spin = min(int(predict.spin) + speed, 0); + predict.angle += buildang(speed); + } + + if (!predict.at71) + predict.at6f = 0; + + switch (predict.at48) + { + case 1: + if (predict.at71) + predict.zvel -= pPosture->normalJumpZ;//0x5b05; + if (pInput->actions & SB_CROUCH) + predict.zvel += pPosture->normalJumpZ;//0x5b05; + break; + case 2: + if (!(pInput->actions & SB_CROUCH)) + predict.at48 = 0; + break; + default: + if (!predict.at6f && predict.at71 && predict.floordist == 0) { + if (packItemActive(pPlayer, 4)) predict.zvel = pPosture->pwupJumpZ;//-0x175555; + else predict.zvel = pPosture->normalJumpZ;//-0xbaaaa; + predict.at6f = 1; + } + if (pInput->actions & SB_CROUCH) + predict.at48 = 2; + break; + } + +#if 0 + if (predict.at6e && !(pInput->actions & (SB_LOOK_UP | SB_LOOK_DOWN))) + { + if (predict.at20 < 0) + predict.at20 = min(predict.at20 + IntToFixed(4), 0); + if (predict.at20 > 0) + predict.at20 = max(predict.at20 - IntToFixed(4), 0); + if (predict.at20 == 0) + predict.at6e = 0; + } + else + { + if (pInput->actions & SB_LOOK_UP) + predict.at20 = min(predict.at20 + IntToFixed(4), IntToFixed(60)); + if (pInput->actions & SB_LOOK_DOWN) + predict.at20 = max(predict.at20 - IntToFixed(4), IntToFixed(-60)); + } + predict.at20 = clamp(predict.at20 + pInput->horz, IntToFixed(-60), IntToFixed(60)); + + if (predict.at20 > 0) + predict.at24 = FloatToFixed(MulScaleF(120., bsinf(FixedToFloat(predict.at20) * 8., 16)), 30); + else if (predict.at20 < 0) + predict.at24 = FloatToFixed(MulScaleF(180., bsinf(FixedToFloat(predict.at20) * 8., 16)), 30); + else + predict.at24 = 0; +#endif + + int nSector = predict.sector; + int florhit = predict.at75.florhit.type; + bool va = (predict.floordist < 16 && (florhit == kHitSector || florhit == 0)); + + if (va && (sector[nSector].floorstat & 2) != 0) + { + int z1 = getflorzofslope(nSector, predict.x, predict.y); + int x2 = predict.x + MulScale(64, Cos(predict.angle.asbuild()), 30); + int y2 = predict.y + MulScale(64, Sin(predict.angle.asbuild()), 30); + int nSector2 = nSector; + updatesector(x2, y2, &nSector2); + if (nSector2 == nSector) + { + int z2 = getflorzofslope(nSector2, x2, y2); + predict.horizoff = interpolatedhorizon(predict.horizoff, q16horiz((z1 - z2) << 13), 0x4000); + } + } + else + { + predict.horizoff = interpolatedhorizon(predict.horizoff, q16horiz(0), 0x4000); + if (abs(predict.horizoff.asq16()) < 4) + predict.horizoff = q16horiz(0); + } + predict.at2c = -predict.horiz.asq16() >> 9; +#endif +} + +void fakePlayerProcess(PLAYER* pPlayer, InputPacket* pInput) +{ +#if 0 + auto pSprite = pPlayer->actor; + POSTURE* pPosture = &pPlayer->pPosture[pPlayer->lifeMode][predict.at48]; + + int top, bottom; + GetSpriteExtents(pSprite, &top, &bottom); + + top += predict.z - pSprite->z; + bottom += predict.z - pSprite->z; + + int dzb = (bottom - predict.z) / 4; + int dzt = (predict.z - top) / 4; + + int dw = pSprite->clipdist << 2; + int nSector = predict.sector; + if (!gNoClip) + { + pushmove(&predict.pos, &predict.sector, dw, dzt, dzb, CLIPMASK0); + if (predict.sector == -1) + predict.sector = nSector; + } + fakeProcessInput(pPlayer, pInput); + + int nSpeed = approxDist(predict.xvel, predict.yvel); + + predict.at3c = interpolatedvalue(predict.at3c, predict.zvel, 0x7000); + int dz = predict.z - pPosture->eyeAboveZ - predict.viewz; + if (dz > 0) + predict.at3c += MulScale(dz << 8, 0xa000, 16); + else + predict.at3c += MulScale(dz << 8, 0x1800, 16); + predict.viewz += predict.at3c >> 8; + + predict.at44 = interpolatedvalue(predict.at44, predict.zvel, 0x5000); + dz = predict.z - pPosture->weaponAboveZ - predict.at40; + if (dz > 0) + predict.at44 += MulScale(dz << 8, 0x8000, 16); + else + predict.at44 += MulScale(dz << 8, 0xc00, 16); + predict.at40 += predict.at44 >> 8; + + predict.weaponZ = predict.at40 - predict.viewz - (12 << 8); + + predict.bobPhase = ClipLow(predict.bobPhase - 4, 0); + + nSpeed >>= FRACBITS; + if (predict.at48 == 1) + { + predict.Kills = (predict.Kills + 17) & 2047; + predict.at14 = (predict.at14 + 17) & 2047; + predict.bobHeight = MulScale(10 * pPosture->bobV, Sin(predict.Kills * 2), 30); + predict.bobWidth = MulScale(predict.bobPhase * pPosture->bobH, Sin(predict.Kills - 256), 30); + predict.shakeBobY = MulScale(predict.bobPhase * pPosture->swayV, Sin(predict.at14 * 2), 30); + predict.shakeBobX = MulScale(predict.bobPhase * pPosture->swayH, Sin(predict.at14 - 0x155), 30); } else { if (pXSprite->height < 256) { - predict.Kills = (predict.Kills+(pPosture->pace[predict.at70]*4))&2047; - predict.at14 = (predict.at14+(pPosture->pace[predict.at70]*4)/2)&2047; + predict.Kills = (predict.Kills + (pPosture->pace[predict.at70] * 4)) & 2047; + predict.at14 = (predict.at14 + (pPosture->pace[predict.at70] * 4) / 2) & 2047; if (predict.at70) { if (predict.bobPhase < 60) - predict.bobPhase = ClipHigh(predict.bobPhase + nSpeed, 60); + predict.bobPhase = ClipHigh(predict.bobPhase + nSpeed, 60); } else { if (predict.bobPhase < 30) - predict.bobPhase = ClipHigh(predict.bobPhase + nSpeed, 30); + predict.bobPhase = ClipHigh(predict.bobPhase + nSpeed, 30); } } - predict.bobHeight = MulScale(predict.bobPhase*pPosture->bobV,Sin(predict.Kills*2), 30); - predict.bobWidth = MulScale(predict.bobPhase*pPosture->bobH,Sin(predict.Kills-256), 30); - predict.shakeBobY = MulScale(predict.bobPhase*pPosture->swayV,Sin(predict.at14*2), 30); - predict.shakeBobX = MulScale(predict.bobPhase*pPosture->swayH,Sin(predict.at14-0x155), 30); + predict.bobHeight = MulScale(predict.bobPhase * pPosture->bobV, Sin(predict.Kills * 2), 30); + predict.bobWidth = MulScale(predict.bobPhase * pPosture->bobH, Sin(predict.Kills - 256), 30); + predict.shakeBobY = MulScale(predict.bobPhase * pPosture->swayV, Sin(predict.at14 * 2), 30); + predict.shakeBobX = MulScale(predict.bobPhase * pPosture->swayH, Sin(predict.at14 - 0x155), 30); } if (!pXSprite->health) - return; + return; predict.at72 = 0; if (predict.at48 == 1) { predict.at72 = 1; - int nSector = predict.sector; - auto nLink = getLowerLink(nSector); + int nSector = predict.sector; + auto nLink = getLowerLink(nSector); if (nLink && (nLink->spr.type == kMarkerLowGoo || nLink->spr.type == kMarkerLowWater)) { if (getceilzofslope(nSector, predict.x, predict.y) > predict.viewz) @@ -356,240 +356,240 @@ void fakePlayerProcess(PLAYER *pPlayer, InputPacket *pInput) #endif } -static void fakeMoveDude(DBloodActor *actor) +static void fakeMoveDude(DBloodActor* actor) { #if 0 // not needed for single player, temporarily disabled due to icompatibilities with the refactored API. - PLAYER *pPlayer = NULL; - int bottom, top; - if (IsPlayerSprite(pSprite)) - pPlayer = &gPlayer[pSprite->type-kDudePlayer1]; - assert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax); - GetSpriteExtents(pSprite, &top, &bottom); + PLAYER* pPlayer = NULL; + int bottom, top; + if (IsPlayerSprite(pSprite)) + pPlayer = &gPlayer[pSprite->type - kDudePlayer1]; + assert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax); + GetSpriteExtents(pSprite, &top, &bottom); top += predict.z - pSprite->z; bottom += predict.z - pSprite->z; - int bz = (bottom-predict.z)/4; - int tz = (predict.z-top)/4; - int wd = pSprite->clipdist*4; - int nSector = predict.sector; - assert(validSectorIndex(nSector)); - if (predict.xvel || predict.yvel) - { - if (pPlayer && gNoClip) - { - predict.x += predict.xvel>>12; - predict.y += predict.yvel>>12; - if (!FindSector(predict.x, predict.y, &nSector)) - nSector = predict.sector; - } - else - { - auto bakCstat = pSprite->cstat; - pSprite->cstat &= ~CSTAT_SPRITE_BLOCK_ALL; - ClipMove(&predict.pos, &nSector, predict.xvel >> 12, predict.yvel >> 12, wd, tz, bz, CLIPMASK0, predict.at75.hit); - if (nSector == -1) - nSector = predict.sector; - - if (sector[nSector].type >= kSectorPath && sector[nSector].type <= kSectorRotate) - { - int nSector2 = nSector; - pushmove(&predict.pos, &nSector2, wd, tz, bz, CLIPMASK0); - if (nSector2 != -1) - nSector = nSector2; - } + int bz = (bottom - predict.z) / 4; + int tz = (predict.z - top) / 4; + int wd = pSprite->clipdist * 4; + int nSector = predict.sector; + assert(validSectorIndex(nSector)); + if (predict.xvel || predict.yvel) + { + if (pPlayer && gNoClip) + { + predict.x += predict.xvel >> 12; + predict.y += predict.yvel >> 12; + if (!FindSector(predict.x, predict.y, &nSector)) + nSector = predict.sector; + } + else + { + auto bakCstat = pSprite->cstat; + pSprite->cstat &= ~CSTAT_SPRITE_BLOCK_ALL; + ClipMove(&predict.pos, &nSector, predict.xvel >> 12, predict.yvel >> 12, wd, tz, bz, CLIPMASK0, predict.at75.hit); + if (nSector == -1) + nSector = predict.sector; - assert(nSector >= 0); + if (sector[nSector].type >= kSectorPath && sector[nSector].type <= kSectorRotate) + { + int nSector2 = nSector; + pushmove(&predict.pos, &nSector2, wd, tz, bz, CLIPMASK0); + if (nSector2 != -1) + nSector = nSector2; + } - pSprite->cstat = bakCstat; - } - switch (predict.at75.hit.type) - { - case kHitSprite: - { - int nHitWall = predict.at75.hit.index; - walltype *pHitWall = &wall [nHitWall]; - if (pHitWall->twoSided()) - { - sectortype *pHitSector = &pHitWall->nextSector(); - if (top < pHitSector->ceilingz || bottom > pHitSector->floorz) - { - // ??? - } - } - actWallBounceVector(&predict.xvel, &predict.yvel, pHitWall, 0); - break; - } - } - } - if (predict.sector != nSector) - { - assert(validSectorIndex(nSector)); - predict.sector = nSector; - } - bool bUnderwater = 0; - bool bDepth = 0; - if (sector[sector].hasX()) - { - XSECTOR *pXSector = §or[sector].xs(); - if (pXSector->Underwater) - bUnderwater = 1; - if (pXSector->Depth) - bDepth = 1; - } - auto nUpperLink = getUpperLink(nSector); - auto nLowerLink = getLowerLink(nSector); - if (nUpperLink >= 0 && (nUpperLink->spr.type == kMarkerUpWater || nUpperLink->spr.type == kMarkerUpGoo)) - bDepth = 1; - if (nLowerLink >= 0 && (nLowerLink->spr.type == kMarkerLowWater || nLowerLink->spr.type == kMarkerLowGoo)) - bDepth = 1; - if (pPlayer) - wd += 16; + assert(nSector >= 0); - if (predict.zvel) - predict.z += predict.zvel >> 8; + pSprite->cstat = bakCstat; + } + switch (predict.at75.hit.type) + { + case kHitSprite: + { + int nHitWall = predict.at75.hit.index; + walltype* pHitWall = &wall[nHitWall]; + if (pHitWall->twoSided()) + { + sectortype* pHitSector = &pHitWall->nextSector(); + if (top < pHitSector->ceilingz || bottom > pHitSector->floorz) + { + // ??? + } + } + actWallBounceVector(&predict.xvel, &predict.yvel, pHitWall, 0); + break; + } + } + } + if (predict.sector != nSector) + { + assert(validSectorIndex(nSector)); + predict.sector = nSector; + } + bool bUnderwater = 0; + bool bDepth = 0; + if (sector[sector].hasX()) + { + XSECTOR* pXSector = §or[sector].xs(); + if (pXSector->Underwater) + bUnderwater = 1; + if (pXSector->Depth) + bDepth = 1; + } + auto nUpperLink = getUpperLink(nSector); + auto nLowerLink = getLowerLink(nSector); + if (nUpperLink >= 0 && (nUpperLink->spr.type == kMarkerUpWater || nUpperLink->spr.type == kMarkerUpGoo)) + bDepth = 1; + if (nLowerLink >= 0 && (nLowerLink->spr.type == kMarkerLowWater || nLowerLink->spr.type == kMarkerLowGoo)) + bDepth = 1; + if (pPlayer) + wd += 16; - spritetype pSpriteBak; memcpy(&pSpriteBak, pSprite, sizeof(pSpriteBak)); - auto pTempSprite = pSprite; - pTempSprite->x = predict.x; - pTempSprite->y = predict.y; - pTempSprite->z = predict.z; - pTempSprite-> sector = predict. sector; - int ceilZ, floorZ; - Collision ceilColl, floorColl; - GetZRange(pTempSprite, &ceilZ, &ceilColl, &floorZ, &floorColl, wd, CLIPMASK0); - GetSpriteExtents(pTempSprite, &top, &bottom); - if (predict.at73 & 2) - { - int vc = 58254; - if (bDepth) - { - if (bUnderwater) - { - int cz = getceilzofslope(nSector, predict.x, predict.y); - if (cz > top) - vc += ((bottom-cz)*-80099) / (bottom-top); - else - vc = 0; - } - else - { - int fz = getflorzofslope(nSector, predict.x, predict.y); - if (fz < bottom) - vc += ((bottom-fz)*-80099) / (bottom-top); - } - } - else - { - if (bUnderwater) - vc = 0; - else if (bottom >= floorZ) - vc = 0; - } - if (vc) - { - predict.z += ((vc*4)/2)>>8; - predict.zvel += vc; - } - } - GetSpriteExtents(pTempSprite, &top, &bottom); - if (bottom >= floorZ) - { - int floorZ2 = floorZ; - auto floorHit2 = floorColl; - GetZRange(pTempSprite, &ceilZ, &ceilColl, &floorZ, &floorColl, pSprite->clipdist<<2, CLIPMASK0, PARALLAXCLIP_CEILING|PARALLAXCLIP_FLOOR); - if (bottom <= floorZ && predict.z-floorZ2 < bz) - { - floorZ = floorZ2; - floorColl = floorHit2; - } - } - if (floorZ <= bottom) - { - predict.at75.florhit = floorColl; - predict.z += floorZ-bottom; - int var44 = predict.zvel-predict.sector()->velFloor; - if (var44 > 0) - { - actFloorBounceVector(&predict.xvel, &predict.yvel, &var44, predict.sector, 0); - predict.zvel = var44; - if (abs(predict.zvel) < 0x10000) - { - predict.zvel = predict.sector()->velFloor; - predict.at73 &= ~4; - } - else - predict.at73 |= 4; - } - else if (predict.zvel == 0) - predict.at73 &= ~4; - } - else - { - predict.at75.florhit.setNone(); - if (predict.at73 & 2) - predict.at73 |= 4; - } - if (top <= ceilZ) - { - predict.at75.ceilhit = ceilColl; - predict.z += ClipLow(ceilZ-top, 0); - if (predict.zvel <= 0 && (predict.at73&4)) - predict.zvel = MulScale(-predict.zvel, 0x2000, 16); - } - else - predict.at75.ceilhit = 0; + if (predict.zvel) + predict.z += predict.zvel >> 8; - GetSpriteExtents(pTempSprite, &top, &bottom); - memcpy(pSprite, &pSpriteBak, sizeof(pSpriteBak)); - predict.floordist = ClipLow(floorZ-bottom, 0)>>8; - if (predict.xvel || predict.yvel) - { - if (floorColl.type == kHitSprite) - { - auto hitactor = floorColl.actor; - if ((hitactor->spr.cstat & 0x30) == 0) - { - predict.xvel += MulScale(4, predict.x - hitactor->spr.x, 2); - predict.yvel += MulScale(4, predict.y - hitactor->spr.y, 2); - return; - } - } - if (pSprite->sector()->hasX() && pSprite->sector()->xs().Underwater) - return; - if (predict.floordist >= 0x100) - return; - int nDrag = gDudeDrag; - if (predict.floordist > 0) - nDrag -= scale(gDudeDrag, predict.floordist, 0x100); - predict.xvel -= mulscale16r(predict.xvel, nDrag); - predict.yvel -= mulscale16r(predict.yvel, nDrag); - if (approxDist(predict.xvel, predict.yvel) < 0x1000) - predict.xvel = predict.yvel = 0; - } + spritetype pSpriteBak; memcpy(&pSpriteBak, pSprite, sizeof(pSpriteBak)); + auto pTempSprite = pSprite; + pTempSprite->x = predict.x; + pTempSprite->y = predict.y; + pTempSprite->z = predict.z; + pTempSprite->sector = predict.sector; + int ceilZ, floorZ; + Collision ceilColl, floorColl; + GetZRange(pTempSprite, &ceilZ, &ceilColl, &floorZ, &floorColl, wd, CLIPMASK0); + GetSpriteExtents(pTempSprite, &top, &bottom); + if (predict.at73 & 2) + { + int vc = 58254; + if (bDepth) + { + if (bUnderwater) + { + int cz = getceilzofslope(nSector, predict.x, predict.y); + if (cz > top) + vc += ((bottom - cz) * -80099) / (bottom - top); + else + vc = 0; + } + else + { + int fz = getflorzofslope(nSector, predict.x, predict.y); + if (fz < bottom) + vc += ((bottom - fz) * -80099) / (bottom - top); + } + } + else + { + if (bUnderwater) + vc = 0; + else if (bottom >= floorZ) + vc = 0; + } + if (vc) + { + predict.z += ((vc * 4) / 2) >> 8; + predict.zvel += vc; + } + } + GetSpriteExtents(pTempSprite, &top, &bottom); + if (bottom >= floorZ) + { + int floorZ2 = floorZ; + auto floorHit2 = floorColl; + GetZRange(pTempSprite, &ceilZ, &ceilColl, &floorZ, &floorColl, pSprite->clipdist << 2, CLIPMASK0, PARALLAXCLIP_CEILING | PARALLAXCLIP_FLOOR); + if (bottom <= floorZ && predict.z - floorZ2 < bz) + { + floorZ = floorZ2; + floorColl = floorHit2; + } + } + if (floorZ <= bottom) + { + predict.at75.florhit = floorColl; + predict.z += floorZ - bottom; + int var44 = predict.zvel - predict.sector()->velFloor; + if (var44 > 0) + { + actFloorBounceVector(&predict.xvel, &predict.yvel, &var44, predict.sector, 0); + predict.zvel = var44; + if (abs(predict.zvel) < 0x10000) + { + predict.zvel = predict.sector()->velFloor; + predict.at73 &= ~4; + } + else + predict.at73 |= 4; + } + else if (predict.zvel == 0) + predict.at73 &= ~4; + } + else + { + predict.at75.florhit.setNone(); + if (predict.at73 & 2) + predict.at73 |= 4; + } + if (top <= ceilZ) + { + predict.at75.ceilhit = ceilColl; + predict.z += ClipLow(ceilZ - top, 0); + if (predict.zvel <= 0 && (predict.at73 & 4)) + predict.zvel = MulScale(-predict.zvel, 0x2000, 16); + } + else + predict.at75.ceilhit = 0; + + GetSpriteExtents(pTempSprite, &top, &bottom); + memcpy(pSprite, &pSpriteBak, sizeof(pSpriteBak)); + predict.floordist = ClipLow(floorZ - bottom, 0) >> 8; + if (predict.xvel || predict.yvel) + { + if (floorColl.type == kHitSprite) + { + auto hitactor = floorColl.actor; + if ((hitactor->spr.cstat & 0x30) == 0) + { + predict.xvel += MulScale(4, predict.x - hitactor->spr.x, 2); + predict.yvel += MulScale(4, predict.y - hitactor->spr.y, 2); + return; + } + } + if (pSprite->sector()->hasX() && pSprite->sector()->xs().Underwater) + return; + if (predict.floordist >= 0x100) + return; + int nDrag = gDudeDrag; + if (predict.floordist > 0) + nDrag -= scale(gDudeDrag, predict.floordist, 0x100); + predict.xvel -= mulscale16r(predict.xvel, nDrag); + predict.yvel -= mulscale16r(predict.yvel, nDrag); + if (approxDist(predict.xvel, predict.yvel) < 0x1000) + predict.xvel = predict.yvel = 0; + } #endif } -static void fakeActAirDrag(DBloodActor *, int num) +static void fakeActAirDrag(DBloodActor*, int num) { #if 0 - int xvec = 0; - int yvec = 0; - assert(validSectorIndex(predict.sector)); - sectortype *pSector = §or[predict.sector]; - if (pSector->hasX()) - { - XSECTOR *pXSector = &pSector->xs(); - if (pXSector->windVel && (pXSector->windAlways || pXSector->busy)) - { - int vel = pXSector->windVel<<12; - if (!pXSector->windAlways && pXSector->busy) - vel = MulScale(vel, pXSector->busy, 16); - xvec = MulScale(vel, Cos(pXSector->windAng), 30); - yvec = MulScale(vel, Sin(pXSector->windAng), 30); - } - } - predict.xvel += MulScale(xvec-predict.xvel, num, 16); - predict.yvel += MulScale(yvec-predict.yvel, num, 16); - predict.zvel -= MulScale(predict.zvel, num, 16); + int xvec = 0; + int yvec = 0; + assert(validSectorIndex(predict.sector)); + sectortype* pSector = §or[predict.sector]; + if (pSector->hasX()) + { + XSECTOR* pXSector = &pSector->xs(); + if (pXSector->windVel && (pXSector->windAlways || pXSector->busy)) + { + int vel = pXSector->windVel << 12; + if (!pXSector->windAlways && pXSector->busy) + vel = MulScale(vel, pXSector->busy, 16); + xvec = MulScale(vel, Cos(pXSector->windAng), 30); + yvec = MulScale(vel, Sin(pXSector->windAng), 30); + } + } + predict.xvel += MulScale(xvec - predict.xvel, num, 16); + predict.yvel += MulScale(yvec - predict.yvel, num, 16); + predict.zvel -= MulScale(predict.zvel, num, 16); #endif } @@ -600,39 +600,39 @@ void fakeActProcessSprites(void) if (pSprite->statnum == kStatDude) { int nSector = predict.sector; - auto pSector = §or[predict.sector]; - auto pXSector = pSector->hasX()? &pSector->xs() : nullptr; + auto pSector = §or[predict.sector]; + auto pXSector = pSector->hasX() ? &pSector->xs() : nullptr; if (pXSector) { - int top, bottom; - GetSpriteExtents(pSprite, &top, &bottom); + int top, bottom; + GetSpriteExtents(pSprite, &top, &bottom); top += predict.z - pSprite->z; bottom += predict.z - pSprite->z; if (getflorzofslope(nSector, predict.x, predict.y) < bottom) { int angle = pXSector->panAngle; - int speed = 0; + int speed = 0; if (pXSector->panAlways || pXSector->state || pXSector->busy) { speed = pXSector->panVel << 9; if (!pXSector->panAlways && pXSector->busy) speed = MulScale(speed, pXSector->busy, 16); } - if (pSector->floorstat&64) - angle = (GetWallAngle(pSector->firstWall())+512)&2047; - predict.xvel += MulScale(speed,Cos(angle), 30); - predict.yvel += MulScale(speed,Sin(angle), 30); + if (pSector->floorstat & 64) + angle = (GetWallAngle(pSector->firstWall()) + 512) & 2047; + predict.xvel += MulScale(speed, Cos(angle), 30); + predict.yvel += MulScale(speed, Sin(angle), 30); } } - if (pXSector && pXSector->Underwater) - fakeActAirDrag(pSprite, 5376); - else - fakeActAirDrag(pSprite, 128); + if (pXSector && pXSector->Underwater) + fakeActAirDrag(pSprite, 5376); + else + fakeActAirDrag(pSprite, 128); - if ((predict.at73 & 4) != 0 || predict.xvel != 0 || predict.yvel != 0 || predict.zvel != 0 || predict.sector()->velFloor != 0 || predict.sector()->velCeil != 0) - { - fakeMoveDude(pSprite); - } + if ((predict.at73 & 4) != 0 || predict.xvel != 0 || predict.yvel != 0 || predict.zvel != 0 || predict.sector()->velFloor != 0 || predict.sector()->velCeil != 0) + { + fakeMoveDude(pSprite); + } } #endif } @@ -640,18 +640,18 @@ void fakeActProcessSprites(void) void viewCorrectPrediction(void) { #if 0 - auto pSprite = gMe->actor; - VIEW *pView = &predictFifo[(gNetFifoTail-1)&255]; - if (gMe->angle.ang != pView->at30 || pView->at24 != gMe->horizon.horiz || pView->at50 != pSprite->x || pView->at54 != pSprite->y || pView->at58 != pSprite->z) - { - viewInitializePrediction(); - predictOld = gPrevView[myconnectindex]; - gPredictTail = gNetFifoTail; - while (gPredictTail < gNetFifoHead[myconnectindex]) - { - viewUpdatePrediction(&gFifoInput[gPredictTail&255][myconnectindex]); - } - } + auto pSprite = gMe->actor; + VIEW* pView = &predictFifo[(gNetFifoTail - 1) & 255]; + if (gMe->angle.ang != pView->at30 || pView->at24 != gMe->horizon.horiz || pView->at50 != pSprite->x || pView->at54 != pSprite->y || pView->at58 != pSprite->z) + { + viewInitializePrediction(); + predictOld = gPrevView[myconnectindex]; + gPredictTail = gNetFifoTail; + while (gPredictTail < gNetFifoHead[myconnectindex]) + { + viewUpdatePrediction(&gFifoInput[gPredictTail & 255][myconnectindex]); + } + } #endif } diff --git a/source/games/blood/src/preload.cpp b/source/games/blood/src/preload.cpp index b6a330a5c..6b68e9064 100644 --- a/source/games/blood/src/preload.cpp +++ b/source/games/blood/src/preload.cpp @@ -36,281 +36,309 @@ void fxPrecache(); void gibPrecache(); +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void tilePrecacheTile(int nTile, int nType, int palette) { - int n = 1; - switch (picanm[nTile].extra & 7) - { - case 0: - n = 1; - break; - case 1: - n = 5; - break; - case 2: - n = 8; - break; - case 3: - n = 2; - break; - } - while (n--) - { - if (picanm[nTile].sf & PICANM_ANIMTYPE_MASK) - { - for (int frame = picanm[nTile].num; frame >= 0; frame--) - { - int tile; - if ((picanm[nTile].sf & PICANM_ANIMTYPE_MASK) == PICANM_ANIMTYPE_BACK) - tile = nTile - frame; - else - tile = nTile + frame; + int n = 1; + switch (picanm[nTile].extra & 7) + { + case 0: + n = 1; + break; + case 1: + n = 5; + break; + case 2: + n = 8; + break; + case 3: + n = 2; + break; + } + while (n--) + { + if (picanm[nTile].sf & PICANM_ANIMTYPE_MASK) + { + for (int frame = picanm[nTile].num; frame >= 0; frame--) + { + int tile; + if ((picanm[nTile].sf & PICANM_ANIMTYPE_MASK) == PICANM_ANIMTYPE_BACK) + tile = nTile - frame; + else + tile = nTile + frame; - markTileForPrecache(tile, palette); - } - } - else - { - markTileForPrecache(nTile, palette); - } - nTile += 1 + picanm[nTile].num; - } + markTileForPrecache(tile, palette); + } + } + else + { + markTileForPrecache(nTile, palette); + } + nTile += 1 + picanm[nTile].num; + } } // To do: This needs to handle the sprite palettes as well to properly precache the needed content. +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void viewPrecacheTiles() { - tilePrecacheTile(2173, 0, 0); - tilePrecacheTile(2200, 0, 0); - tilePrecacheTile(2201, 0, 0); - tilePrecacheTile(2202, 0, 0); - tilePrecacheTile(2207, 0, 0); - tilePrecacheTile(2208, 0, 0); - tilePrecacheTile(2209, 0, 0); - tilePrecacheTile(2229, 0, 0); - tilePrecacheTile(2260, 0, 0); - tilePrecacheTile(2559, 0, 0); - tilePrecacheTile(2169, 0, 0); - tilePrecacheTile(2578, 0, 0); - tilePrecacheTile(2586, 0, 0); - tilePrecacheTile(2602, 0, 0); - for (int i = 0; i < 10; i++) - { - tilePrecacheTile(2190 + i, 0, 0); - tilePrecacheTile(2230 + i, 0, 0); - tilePrecacheTile(2240 + i, 0, 0); - tilePrecacheTile(2250 + i, 0, 0); - tilePrecacheTile(kSBarNumberHealth + i, 0, 0); - tilePrecacheTile(kSBarNumberAmmo + i, 0, 0); - tilePrecacheTile(kSBarNumberInv + i, 0, 0); - tilePrecacheTile(kSBarNumberArmor1 + i, 0, 0); - tilePrecacheTile(kSBarNumberArmor2 + i, 0, 0); - tilePrecacheTile(kSBarNumberArmor3 + i, 0, 0); - } - /* - for (int i = 0; i < 5; i++) - { - tilePrecacheTile(gPackIcons[i], 0); - tilePrecacheTile(gPackIcons2[i].nTile, 0); - } - */ - for (int i = 0; i < 6; i++) - { - tilePrecacheTile(2220 + i, 0, 0); - tilePrecacheTile(2552 + i, 0, 0); - } + tilePrecacheTile(2173, 0, 0); + tilePrecacheTile(2200, 0, 0); + tilePrecacheTile(2201, 0, 0); + tilePrecacheTile(2202, 0, 0); + tilePrecacheTile(2207, 0, 0); + tilePrecacheTile(2208, 0, 0); + tilePrecacheTile(2209, 0, 0); + tilePrecacheTile(2229, 0, 0); + tilePrecacheTile(2260, 0, 0); + tilePrecacheTile(2559, 0, 0); + tilePrecacheTile(2169, 0, 0); + tilePrecacheTile(2578, 0, 0); + tilePrecacheTile(2586, 0, 0); + tilePrecacheTile(2602, 0, 0); + for (int i = 0; i < 10; i++) + { + tilePrecacheTile(2190 + i, 0, 0); + tilePrecacheTile(2230 + i, 0, 0); + tilePrecacheTile(2240 + i, 0, 0); + tilePrecacheTile(2250 + i, 0, 0); + tilePrecacheTile(kSBarNumberHealth + i, 0, 0); + tilePrecacheTile(kSBarNumberAmmo + i, 0, 0); + tilePrecacheTile(kSBarNumberInv + i, 0, 0); + tilePrecacheTile(kSBarNumberArmor1 + i, 0, 0); + tilePrecacheTile(kSBarNumberArmor2 + i, 0, 0); + tilePrecacheTile(kSBarNumberArmor3 + i, 0, 0); + } + /* + for (int i = 0; i < 5; i++) + { + tilePrecacheTile(gPackIcons[i], 0); + tilePrecacheTile(gPackIcons2[i].nTile, 0); + } + */ + for (int i = 0; i < 6; i++) + { + tilePrecacheTile(2220 + i, 0, 0); + tilePrecacheTile(2552 + i, 0, 0); + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- - -void PrecacheDude(DBloodActor *actor) +void PrecacheDude(DBloodActor* actor) { - int palette = actor->spr.pal; - DUDEINFO *pDudeInfo = getDudeInfo(actor->spr.type); - seqPrecacheId(pDudeInfo->seqStartID , palette); - seqPrecacheId(pDudeInfo->seqStartID+5, palette); - seqPrecacheId(pDudeInfo->seqStartID+1, palette); - seqPrecacheId(pDudeInfo->seqStartID+2, palette); - switch (actor->spr.type) - { - case kDudeCultistTommy: - case kDudeCultistShotgun: - case kDudeCultistTesla: - case kDudeCultistTNT: - seqPrecacheId(pDudeInfo->seqStartID+6 , palette); - seqPrecacheId(pDudeInfo->seqStartID+7 , palette); - seqPrecacheId(pDudeInfo->seqStartID+8 , palette); - seqPrecacheId(pDudeInfo->seqStartID+9 , palette); - seqPrecacheId(pDudeInfo->seqStartID+13, palette); - seqPrecacheId(pDudeInfo->seqStartID+14, palette); - seqPrecacheId(pDudeInfo->seqStartID+15, palette); - break; - case kDudeZombieButcher: - case kDudeGillBeast: - seqPrecacheId(pDudeInfo->seqStartID+6, palette); - seqPrecacheId(pDudeInfo->seqStartID+7, palette); - seqPrecacheId(pDudeInfo->seqStartID+8, palette); - seqPrecacheId(pDudeInfo->seqStartID+9, palette); - seqPrecacheId(pDudeInfo->seqStartID+10, palette); - seqPrecacheId(pDudeInfo->seqStartID+11, palette); - break; - case kDudeGargoyleStatueFlesh: - case kDudeGargoyleStatueStone: - seqPrecacheId(pDudeInfo->seqStartID+6, palette); - seqPrecacheId(pDudeInfo->seqStartID+6, palette); //??? - [[fallthrough]]; - case kDudeGargoyleFlesh: - case kDudeGargoyleStone: - seqPrecacheId(pDudeInfo->seqStartID+6, palette); - seqPrecacheId(pDudeInfo->seqStartID+7, palette); - seqPrecacheId(pDudeInfo->seqStartID+8, palette); - seqPrecacheId(pDudeInfo->seqStartID+9, palette); - break; - case kDudePhantasm: - case kDudeHellHound: - case kDudeSpiderBrown: - case kDudeSpiderRed: - case kDudeSpiderBlack: - case kDudeSpiderMother: - case kDudeTchernobog: - seqPrecacheId(pDudeInfo->seqStartID+6, palette); - seqPrecacheId(pDudeInfo->seqStartID+7, palette); - seqPrecacheId(pDudeInfo->seqStartID+8, palette); - break; - case kDudeCerberusTwoHead: - seqPrecacheId(pDudeInfo->seqStartID+6, palette); - seqPrecacheId(pDudeInfo->seqStartID+7, palette); - [[fallthrough]]; - case kDudeHand: - case kDudeBoneEel: - case kDudeBat: - case kDudeRat: - seqPrecacheId(pDudeInfo->seqStartID+6, palette); - seqPrecacheId(pDudeInfo->seqStartID+7, palette); - break; - case kDudeCultistBeast: - seqPrecacheId(pDudeInfo->seqStartID+6, palette); - break; - case kDudeZombieAxeBuried: - seqPrecacheId(pDudeInfo->seqStartID+12, palette); - seqPrecacheId(pDudeInfo->seqStartID+9, palette); - [[fallthrough]]; - case kDudeZombieAxeLaying: - seqPrecacheId(pDudeInfo->seqStartID+10, palette); - [[fallthrough]]; - case kDudeZombieAxeNormal: - seqPrecacheId(pDudeInfo->seqStartID+6, palette); - seqPrecacheId(pDudeInfo->seqStartID+7, palette); - seqPrecacheId(pDudeInfo->seqStartID+8, palette); - seqPrecacheId(pDudeInfo->seqStartID+11, palette); - seqPrecacheId(pDudeInfo->seqStartID+13, palette); - seqPrecacheId(pDudeInfo->seqStartID+14, palette); - break; - } + int palette = actor->spr.pal; + DUDEINFO* pDudeInfo = getDudeInfo(actor->spr.type); + seqPrecacheId(pDudeInfo->seqStartID, palette); + seqPrecacheId(pDudeInfo->seqStartID + 5, palette); + seqPrecacheId(pDudeInfo->seqStartID + 1, palette); + seqPrecacheId(pDudeInfo->seqStartID + 2, palette); + switch (actor->spr.type) + { + case kDudeCultistTommy: + case kDudeCultistShotgun: + case kDudeCultistTesla: + case kDudeCultistTNT: + seqPrecacheId(pDudeInfo->seqStartID + 6, palette); + seqPrecacheId(pDudeInfo->seqStartID + 7, palette); + seqPrecacheId(pDudeInfo->seqStartID + 8, palette); + seqPrecacheId(pDudeInfo->seqStartID + 9, palette); + seqPrecacheId(pDudeInfo->seqStartID + 13, palette); + seqPrecacheId(pDudeInfo->seqStartID + 14, palette); + seqPrecacheId(pDudeInfo->seqStartID + 15, palette); + break; + case kDudeZombieButcher: + case kDudeGillBeast: + seqPrecacheId(pDudeInfo->seqStartID + 6, palette); + seqPrecacheId(pDudeInfo->seqStartID + 7, palette); + seqPrecacheId(pDudeInfo->seqStartID + 8, palette); + seqPrecacheId(pDudeInfo->seqStartID + 9, palette); + seqPrecacheId(pDudeInfo->seqStartID + 10, palette); + seqPrecacheId(pDudeInfo->seqStartID + 11, palette); + break; + case kDudeGargoyleStatueFlesh: + case kDudeGargoyleStatueStone: + seqPrecacheId(pDudeInfo->seqStartID + 6, palette); + seqPrecacheId(pDudeInfo->seqStartID + 6, palette); //??? + [[fallthrough]]; + case kDudeGargoyleFlesh: + case kDudeGargoyleStone: + seqPrecacheId(pDudeInfo->seqStartID + 6, palette); + seqPrecacheId(pDudeInfo->seqStartID + 7, palette); + seqPrecacheId(pDudeInfo->seqStartID + 8, palette); + seqPrecacheId(pDudeInfo->seqStartID + 9, palette); + break; + case kDudePhantasm: + case kDudeHellHound: + case kDudeSpiderBrown: + case kDudeSpiderRed: + case kDudeSpiderBlack: + case kDudeSpiderMother: + case kDudeTchernobog: + seqPrecacheId(pDudeInfo->seqStartID + 6, palette); + seqPrecacheId(pDudeInfo->seqStartID + 7, palette); + seqPrecacheId(pDudeInfo->seqStartID + 8, palette); + break; + case kDudeCerberusTwoHead: + seqPrecacheId(pDudeInfo->seqStartID + 6, palette); + seqPrecacheId(pDudeInfo->seqStartID + 7, palette); + [[fallthrough]]; + case kDudeHand: + case kDudeBoneEel: + case kDudeBat: + case kDudeRat: + seqPrecacheId(pDudeInfo->seqStartID + 6, palette); + seqPrecacheId(pDudeInfo->seqStartID + 7, palette); + break; + case kDudeCultistBeast: + seqPrecacheId(pDudeInfo->seqStartID + 6, palette); + break; + case kDudeZombieAxeBuried: + seqPrecacheId(pDudeInfo->seqStartID + 12, palette); + seqPrecacheId(pDudeInfo->seqStartID + 9, palette); + [[fallthrough]]; + case kDudeZombieAxeLaying: + seqPrecacheId(pDudeInfo->seqStartID + 10, palette); + [[fallthrough]]; + case kDudeZombieAxeNormal: + seqPrecacheId(pDudeInfo->seqStartID + 6, palette); + seqPrecacheId(pDudeInfo->seqStartID + 7, palette); + seqPrecacheId(pDudeInfo->seqStartID + 8, palette); + seqPrecacheId(pDudeInfo->seqStartID + 11, palette); + seqPrecacheId(pDudeInfo->seqStartID + 13, palette); + seqPrecacheId(pDudeInfo->seqStartID + 14, palette); + break; + } } -void PrecacheThing(DBloodActor* actor) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void PrecacheThing(DBloodActor* actor) { - int palette = actor->spr.pal; - switch (actor->spr.type) { - case kThingGlassWindow: // worthless... - case kThingFluorescent: - seqPrecacheId(12, palette); - break; - case kThingSpiderWeb: - seqPrecacheId(15, palette); - break; - case kThingMetalGrate: - seqPrecacheId(21, palette); - break; - case kThingFlammableTree: - seqPrecacheId(25, palette); - seqPrecacheId(26, palette); - break; - case kTrapMachinegun: - seqPrecacheId(38, palette); - seqPrecacheId(40, palette); - seqPrecacheId(28, palette); - break; - case kThingObjectGib: - //case kThingObjectExplode: weird that only gib object is precached and this one is not - break; - } - tilePrecacheTile(actor->spr.picnum, -1, palette); + int palette = actor->spr.pal; + switch (actor->spr.type) { + case kThingGlassWindow: // worthless... + case kThingFluorescent: + seqPrecacheId(12, palette); + break; + case kThingSpiderWeb: + seqPrecacheId(15, palette); + break; + case kThingMetalGrate: + seqPrecacheId(21, palette); + break; + case kThingFlammableTree: + seqPrecacheId(25, palette); + seqPrecacheId(26, palette); + break; + case kTrapMachinegun: + seqPrecacheId(38, palette); + seqPrecacheId(40, palette); + seqPrecacheId(28, palette); + break; + case kThingObjectGib: + //case kThingObjectExplode: weird that only gib object is precached and this one is not + break; + } + tilePrecacheTile(actor->spr.picnum, -1, palette); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void PreloadCache() { - if (!r_precache) return; - int skyTile = -1; - // Fonts - for(auto& sect: sector) - { - tilePrecacheTile(sect.floorpicnum, 0, sect.floorpal); - tilePrecacheTile(sect.ceilingpicnum, 0, sect.ceilingpal); - if ((sect.ceilingstat & CSTAT_SECTOR_SKY) != 0 && skyTile == -1) - skyTile = sect.ceilingpicnum; - } - for(auto& wal : wall) - { - tilePrecacheTile(wal.picnum, 0, wal.pal); - if (wal.overpicnum >= 0) - tilePrecacheTile(wal.overpicnum, 0, wal.pal); - } - BloodSpriteIterator it; - while (auto actor = it.Next()) - { - switch (actor->spr.statnum) - { - case kStatDude: - PrecacheDude(actor); - break; - case kStatThing: - PrecacheThing(actor); - break; - default: - tilePrecacheTile(actor->spr.picnum, -1, actor->spr.pal); - break; - } - } + if (!r_precache) return; + int skyTile = -1; + // Fonts + for (auto& sect : sector) + { + tilePrecacheTile(sect.floorpicnum, 0, sect.floorpal); + tilePrecacheTile(sect.ceilingpicnum, 0, sect.ceilingpal); + if ((sect.ceilingstat & CSTAT_SECTOR_SKY) != 0 && skyTile == -1) + skyTile = sect.ceilingpicnum; + } + for (auto& wal : wall) + { + tilePrecacheTile(wal.picnum, 0, wal.pal); + if (wal.overpicnum >= 0) + tilePrecacheTile(wal.overpicnum, 0, wal.pal); + } + BloodSpriteIterator it; + while (auto actor = it.Next()) + { + switch (actor->spr.statnum) + { + case kStatDude: + PrecacheDude(actor); + break; + case kStatThing: + PrecacheThing(actor); + break; + default: + tilePrecacheTile(actor->spr.picnum, -1, actor->spr.pal); + break; + } + } - // Precache common SEQs - for (int i = 0; i < 100; i++) - { - seqPrecacheId(i, 0); - } + // Precache common SEQs + for (int i = 0; i < 100; i++) + { + seqPrecacheId(i, 0); + } - tilePrecacheTile(1147, -1, 0); // water drip - tilePrecacheTile(1160, -1, 0); // blood drip + tilePrecacheTile(1147, -1, 0); // water drip + tilePrecacheTile(1160, -1, 0); // blood drip - // Player SEQs - seqPrecacheId(dudeInfo[31].seqStartID+6, 0); - seqPrecacheId(dudeInfo[31].seqStartID+7, 0); - seqPrecacheId(dudeInfo[31].seqStartID+8, 0); - seqPrecacheId(dudeInfo[31].seqStartID+9, 0); - seqPrecacheId(dudeInfo[31].seqStartID+10, 0); - seqPrecacheId(dudeInfo[31].seqStartID+14, 0); - seqPrecacheId(dudeInfo[31].seqStartID+15, 0); - seqPrecacheId(dudeInfo[31].seqStartID+12, 0); - seqPrecacheId(dudeInfo[31].seqStartID+16, 0); - seqPrecacheId(dudeInfo[31].seqStartID+17, 0); - seqPrecacheId(dudeInfo[31].seqStartID+18, 0); + // Player SEQs + seqPrecacheId(dudeInfo[31].seqStartID + 6, 0); + seqPrecacheId(dudeInfo[31].seqStartID + 7, 0); + seqPrecacheId(dudeInfo[31].seqStartID + 8, 0); + seqPrecacheId(dudeInfo[31].seqStartID + 9, 0); + seqPrecacheId(dudeInfo[31].seqStartID + 10, 0); + seqPrecacheId(dudeInfo[31].seqStartID + 14, 0); + seqPrecacheId(dudeInfo[31].seqStartID + 15, 0); + seqPrecacheId(dudeInfo[31].seqStartID + 12, 0); + seqPrecacheId(dudeInfo[31].seqStartID + 16, 0); + seqPrecacheId(dudeInfo[31].seqStartID + 17, 0); + seqPrecacheId(dudeInfo[31].seqStartID + 18, 0); - if (skyTile > -1 && skyTile < kMaxTiles) - { - for (int i = 1; i < gSkyCount; i++) - tilePrecacheTile(skyTile+i, 0, 0); - } + if (skyTile > -1 && skyTile < kMaxTiles) + { + for (int i = 1; i < gSkyCount; i++) + tilePrecacheTile(skyTile + i, 0, 0); + } - WeaponPrecache(); - viewPrecacheTiles(); - fxPrecache(); - gibPrecache(); + WeaponPrecache(); + viewPrecacheTiles(); + fxPrecache(); + gibPrecache(); - I_GetEvent(); - precacheMarkedTiles(); + I_GetEvent(); + precacheMarkedTiles(); } END_BLD_NS diff --git a/source/games/blood/src/qav.cpp b/source/games/blood/src/qav.cpp index 158c4c105..6e174b0dd 100644 --- a/source/games/blood/src/qav.cpp +++ b/source/games/blood/src/qav.cpp @@ -30,7 +30,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. BEGIN_BLD_NS -extern void (*qavClientCallback[])(int, void *); +extern void (*qavClientCallback[])(int, void*); //========================================================================== @@ -39,20 +39,20 @@ extern void (*qavClientCallback[])(int, void *); // //========================================================================== -using QAVPrevTileFinder = TILE_FRAME* (*)(FRAMEINFO* const thisFrame, FRAMEINFO* const prevFrame, const int i); +using QAVPrevTileFinder = TILE_FRAME * (*)(FRAMEINFO* const thisFrame, FRAMEINFO* const prevFrame, const int i); struct QAVInterpProps { - QAVPrevTileFinder PrevTileFinder; - bool loopable; - TMap> IgnoreData; + QAVPrevTileFinder PrevTileFinder; + bool loopable; + TMap> 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; - } + 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 qavPrevTileFinders; @@ -60,66 +60,78 @@ static TMap 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 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; - }); + // 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 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; - }); + // 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; + }); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + static QAVPrevTileFinder qavGetInterpType(const FString& type) { - if (!qavPrevTileFinders.CountUsed()) qavInitTileFinderMap(); - return *qavPrevTileFinders.CheckKey(type); + if (!qavPrevTileFinders.CountUsed()) qavInitTileFinderMap(); + return *qavPrevTileFinders.CheckKey(type); } bool GameInterface::IsQAVInterpTypeValid(const FString& type) { - return qavGetInterpType(type) != nullptr; + return qavGetInterpType(type) != nullptr; } void GameInterface::AddQAVInterpProps(const int res_id, const FString& interptype, const bool loopable, const TMap>&& ignoredata) { - qavInterpProps.Insert(res_id, { qavGetInterpType(interptype), loopable, std::move(ignoredata) }); + qavInterpProps.Insert(res_id, { qavGetInterpType(interptype), loopable, std::move(ignoredata) }); } void GameInterface::RemoveQAVInterpProps(const int res_id) { - qavInterpProps.Remove(res_id); + qavInterpProps.Remove(res_id); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void DrawFrame(double x, double y, double z, double a, double alpha, int picnum, int stat, int shade, int palnum, bool to3dview) { - if (!to3dview) - { + if (!to3dview) + { auto tex = tileGetTexture(picnum); double scale = z * (1. / 65536.); double angle = a * BAngToDegree; - int renderstyle = (stat & RS_NOMASK)? STYLE_Normal : STYLE_Translucent; - int pin = (stat & kQavOrientationLeft)? -1 : (stat & RS_ALIGN_R)? 1:0; + int renderstyle = (stat & RS_NOMASK) ? STYLE_Normal : STYLE_Translucent; + int pin = (stat & kQavOrientationLeft) ? -1 : (stat & RS_ALIGN_R) ? 1 : 0; auto translation = TRANSLATION(Translation_Remap, palnum); bool topleft = !!(stat & RS_TOPLEFT); @@ -128,258 +140,294 @@ void DrawFrame(double x, double y, double z, double a, double alpha, int picnum, 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? 0:2, DTA_FullscreenScale, FSMode_Fit320x200, DTA_FlipOffsets, true, DTA_Color, color, - DTA_FlipX, xflip, DTA_FlipY, yflip, TAG_DONE); - } - else - { - // there's some disagreements about flag values between QAV and the drawer. Shuffle these around. + DTA_TopLeft, topleft, DTA_CenterOffsetRel, topleft ? 0 : 2, DTA_FullscreenScale, FSMode_Fit320x200, DTA_FlipOffsets, true, DTA_Color, color, + DTA_FlipX, xflip, DTA_FlipY, yflip, TAG_DONE); + } + else + { + // there's some disagreements about flag values between QAV and the drawer. Shuffle these around. if (stat & RS_YFLIP) stat |= RS_YFLIPHUD; stat &= ~RS_YFLIP; if (stat & 0x100) stat |= RS_XFLIPHUD; - stat &= ~0x100; + stat &= ~0x100; if ((stat & kQavOrientationLeft)) stat |= RS_ALIGN_L; - stat &= ~kQavOrientationLeft; + stat &= ~kQavOrientationLeft; hud_drawsprite(x, y, z, a, picnum, shade, palnum, stat, alpha); - } + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void QAV::Draw(double x, double y, int ticks, int stat, int shade, int palnum, bool to3dview, double const smoothratio) { - assert(ticksPerFrame > 0); + assert(ticksPerFrame > 0); - auto const interpdata = qavInterpProps.CheckKey(res_id); + auto const interpdata = qavInterpProps.CheckKey(res_id); - auto const nFrame = clamp(ticks / ticksPerFrame, 0, nFrames - 1); - FRAMEINFO* const thisFrame = &frames[nFrame]; + auto const nFrame = clamp(ticks / ticksPerFrame, 0, nFrames - 1); + FRAMEINFO* const thisFrame = &frames[nFrame]; - auto const oFrame = clamp((nFrame == 0 && interpdata && interpdata->loopable ? nFrames : nFrame) - 1, 0, nFrames - 1); - FRAMEINFO* const prevFrame = &frames[oFrame]; + 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); + bool const interpolate = interpdata && cl_hudinterpolation && cl_bloodqavinterp && (nFrames > 1) && (nFrame != oFrame) && (smoothratio != MaxSmoothRatio); - for (int i = 0; i < 8; i++) - { - if (thisFrame->tiles[i].picnum > 0) - { - TILE_FRAME* const thisTile = &thisFrame->tiles[i]; - TILE_FRAME* const prevTile = interpolate && interpdata->CanInterpFrameTile(nFrame, i) ? interpdata->PrevTileFinder(thisFrame, prevFrame, i) : nullptr; + for (int i = 0; i < 8; i++) + { + if (thisFrame->tiles[i].picnum > 0) + { + TILE_FRAME* const thisTile = &thisFrame->tiles[i]; + TILE_FRAME* const prevTile = interpolate && interpdata->CanInterpFrameTile(nFrame, i) ? interpdata->PrevTileFinder(thisFrame, prevFrame, i) : nullptr; - double tileX = x; - double tileY = y; - double tileZ; - double tileA; - double tileAlpha; - int tileShade; - auto const tileStat = stat | thisTile->stat; + double tileX = x; + double tileY = y; + double tileZ; + double tileA; + double tileAlpha; + int tileShade; + auto const tileStat = stat | thisTile->stat; - 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(); - 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 - { - tileX += thisTile->x; - 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.; - } + 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(); + 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 + { + tileX += thisTile->x; + 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, tileAlpha, thisTile->picnum, tileStat, tileShade, (palnum <= 0 ? thisTile->palnum : palnum), to3dview); - } - } + DrawFrame(tileX, tileY, tileZ, tileA, tileAlpha, thisTile->picnum, tileStat, tileShade, (palnum <= 0 ? thisTile->palnum : palnum), to3dview); + } + } } -void QAV::Play(int start, int end, int nCallback, PLAYER *pData) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void QAV::Play(int start, int end, int nCallback, PLAYER* pData) { - auto pActor = pData ? pData->actor : nullptr; - assert(ticksPerFrame > 0); - int frame; - int ticks; - if (start < 0) - frame = (start + 1) / ticksPerFrame; - else - frame = start / ticksPerFrame + 1; - - for (ticks = ticksPerFrame * frame; ticks <= end; frame++, ticks += ticksPerFrame) - { - if (frame >= 0 && frame < nFrames) - { - FRAMEINFO *pFrame = &frames[frame]; - SOUNDINFO *pSound = &pFrame->sound; - - // by NoOne: handle Sound kill flags - if (!VanillaMode() && pSound->sndFlags > 0 && pSound->sndFlags <= kFlagSoundKillAll) { - for (int i = 0; i < nFrames; i++) { - FRAMEINFO* pFrame2 = &frames[i]; - SOUNDINFO* pSound2 = &pFrame2->sound; - if (pSound2->sound != 0) { - if (pSound->sndFlags != kFlagSoundKillAll && pSound2->priority != pSound->priority) continue; - else if (pActor) { - // We need stop all sounds in a range - for (int a = 0; a <= pSound2->sndRange; a++) - sfxKill3DSound(pActor, -1, pSound2->sound + a); - } else { - sndKillAllSounds(); - } - } - } - } + auto pActor = pData ? pData->actor : nullptr; + assert(ticksPerFrame > 0); + int frame; + int ticks; + if (start < 0) + frame = (start + 1) / ticksPerFrame; + else + frame = start / ticksPerFrame + 1; - if (pSound->sound > 0) { - int sound = pSound->sound; - - // by NoOne: add random rage sound feature - if (pSound->sndRange > 0 && !VanillaMode()) - sound += Random((pSound->sndRange == 1) ? 2 : pSound->sndRange); - - if (pActor == nullptr) sndStartSample(sound, -1, -1, 0); - else sfxPlay3DSound(pActor, sound, 16+pSound->priority, 6); - } - - if (pFrame->nCallbackId > 0 && nCallback != -1) { - qavClientCallback[nCallback](pFrame->nCallbackId, pData); - } - } - } + for (ticks = ticksPerFrame * frame; ticks <= end; frame++, ticks += ticksPerFrame) + { + if (frame >= 0 && frame < nFrames) + { + FRAMEINFO* pFrame = &frames[frame]; + SOUNDINFO* pSound = &pFrame->sound; + + // by NoOne: handle Sound kill flags + if (!VanillaMode() && pSound->sndFlags > 0 && pSound->sndFlags <= kFlagSoundKillAll) { + for (int i = 0; i < nFrames; i++) { + FRAMEINFO* pFrame2 = &frames[i]; + SOUNDINFO* pSound2 = &pFrame2->sound; + if (pSound2->sound != 0) { + if (pSound->sndFlags != kFlagSoundKillAll && pSound2->priority != pSound->priority) continue; + else if (pActor) { + // We need stop all sounds in a range + for (int a = 0; a <= pSound2->sndRange; a++) + sfxKill3DSound(pActor, -1, pSound2->sound + a); + } + else { + sndKillAllSounds(); + } + } + } + } + + if (pSound->sound > 0) { + int sound = pSound->sound; + + // by NoOne: add random rage sound feature + if (pSound->sndRange > 0 && !VanillaMode()) + sound += Random((pSound->sndRange == 1) ? 2 : pSound->sndRange); + + if (pActor == nullptr) sndStartSample(sound, -1, -1, 0); + else sfxPlay3DSound(pActor, sound, 16 + pSound->priority, 6); + } + + if (pFrame->nCallbackId > 0 && nCallback != -1) { + qavClientCallback[nCallback](pFrame->nCallbackId, pData); + } + } + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void QAV::Precache(int palette) { - for (int i = 0; i < nFrames; i++) - { - for (int j = 0; j < 8; j++) - { - if (frames[i].tiles[j].picnum >= 0) - tilePrecacheTile(frames[i].tiles[j].picnum, 0, palette); - } - } + for (int i = 0; i < nFrames; i++) + { + for (int j = 0; j < 8; j++) + { + if (frames[i].tiles[j].picnum >= 0) + tilePrecacheTile(frames[i].tiles[j].picnum, 0, palette); + } + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void qavProcessTicker(QAV* const pQAV, int* duration, int* lastTick) { - if (*duration > 0) - { - auto thisTick = I_GetTime(pQAV->ticrate); - auto numTicks = thisTick - (*lastTick); - if (numTicks) - { - *lastTick = thisTick; - *duration -= pQAV->ticksPerFrame * numTicks; - } - } - *duration = ClipLow(*duration, 0); + if (*duration > 0) + { + auto thisTick = I_GetTime(pQAV->ticrate); + auto numTicks = thisTick - (*lastTick); + if (numTicks) + { + *lastTick = thisTick; + *duration -= pQAV->ticksPerFrame * numTicks; + } + } + *duration = ClipLow(*duration, 0); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void qavProcessTimer(PLAYER* const pPlayer, QAV* const pQAV, int* duration, double* smoothratio, bool const fixedduration, bool const ignoreWeaponTimer) { - // Process if not paused. - if (!paused) - { - // Process clock based on QAV's ticrate and last tick value. - qavProcessTicker(pQAV, &pPlayer->qavTimer, &pPlayer->qavLastTick); + // Process if not paused. + if (!paused) + { + // Process clock based on QAV's ticrate and last tick value. + qavProcessTicker(pQAV, &pPlayer->qavTimer, &pPlayer->qavLastTick); - 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; - *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 = !cl_interpolate || cl_capfps ? MaxSmoothRatio : I_GetTimeFrac(pQAV->ticrate) * MaxSmoothRatio; - } - } - else - { - *smoothratio = MaxSmoothRatio; - } + 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; + *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 = !cl_interpolate || cl_capfps ? MaxSmoothRatio : I_GetTimeFrac(pQAV->ticrate) * MaxSmoothRatio; + } + } + else + { + *smoothratio = MaxSmoothRatio; + } } +//--------------------------------------------------------------------------- +// // This is to eliminate a huge design issue in NBlood that was apparently copied verbatim from the DOS-Version. // Sequences were cached in the resource and directly returned from there in writable form, with byte swapping directly performed in the cache on Big Endian systems. // To avoid such unsafe operations this caches the read data separately. +// +//--------------------------------------------------------------------------- + extern FMemArena seqcache; // Use the same storage as the SEQs. static TMap qavcache; QAV* getQAV(int res_id) { - auto p = qavcache.CheckKey(res_id); - if (p != nullptr) return *p; + auto p = qavcache.CheckKey(res_id); + if (p != nullptr) return *p; - int index = fileSystem.FindResource(res_id, "QAV"); - if (index < 0) - { - return nullptr; - } - auto fr = fileSystem.OpenFileReader(index); + int index = fileSystem.FindResource(res_id, "QAV"); + if (index < 0) + { + return nullptr; + } + auto fr = fileSystem.OpenFileReader(index); - // 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))); + // 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(); + // 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 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 j = 0; j < 1; j++) fr.ReadUInt8(); + // 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 j = 0; j < 1; j++) 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(); - } - } + // 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; + // Write out additions. + qavdata->res_id = res_id; + qavdata->ticrate = 120. / qavdata->ticksPerFrame; - qavcache.Insert(res_id, qavdata); - return qavdata; + qavcache.Insert(res_id, qavdata); + return qavdata; } diff --git a/source/games/blood/src/qav.h b/source/games/blood/src/qav.h index 9ace03f4e..1071dee9d 100644 --- a/source/games/blood/src/qav.h +++ b/source/games/blood/src/qav.h @@ -31,208 +31,208 @@ enum { kQavOrientationLeft = 4096 }; enum { - kQAVNone = -1, + kQAVNone = -1, - kQAVFORKUP = 0, - kQAVFORKIDLE = 1, - kQAVPFORK = 2, - kQAVFORKDOWN = 3, + kQAVFORKUP = 0, + kQAVFORKIDLE = 1, + kQAVPFORK = 2, + kQAVFORKDOWN = 3, - kQAVLITEOPEN = 4, - kQAVLITEFLAM = 5, - kQAVLITEIDLE = 6, - kQAVLITECLO2 = 7, + kQAVLITEOPEN = 4, + kQAVLITEFLAM = 5, + kQAVLITEIDLE = 6, + kQAVLITECLO2 = 7, - kQAVCANPREF = 8, - kQAVCANIDLE = 9, - kQAVCANFIRE = 10, - kQAVCANDOWN = 11, - kQAVCANFIRE2 = 12, - kQAVCANDROP = 13, - kQAVCANTHRO = 14, - kQAVCANBOOM = 15, + 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, + kQAVBUNUP = 16, + kQAVBUNDOWN = 17, + kQAVBUNUP2 = 18, + kQAVBUNDOWN2 = 19, + kQAVBUNIDLE = 20, + kQAVBUNFUSE = 21, + kQAVBUNDROP = 22, + kQAVBUNTHRO = 23, - kQAVDYNEXPLO = 24, + kQAVDYNEXPLO = 24, - kQAVPROXUP = 25, - kQAVPROXDOWN = 26, - kQAVPROXIDLE = 27, - kQAVPROXDROP = 28, - kQAVPROXTHRO = 29, + 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, + 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, + kQAVFLARUP = 41, + kQAVFLARIDLE = 42, + kQAVFLARFIR2 = 43, + kQAVFLARDOWN = 44, - kQAVFLAR2UP = 45, - kQAVFLAR2I = 46, - kQAVFLAR2F = 47, - kQAVFLAR2FIR = 48, - kQAVFLAR2DWN = 49, + 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, + 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, + kQAV2SHOTUP = 59, + kQAV2SHOTI = 60, + kQAV2SHOTF2 = 61, + kQAV2SHOTFIR = 62, + kQAV2SHOTDWN = 63, - kQAVTOMUP = 64, - kQAVTOMIDLE = 65, - kQAVTOMFIRE = 66, - kQAVTOMSPRED = 67, - kQAVTOMDOWN = 68, + kQAVTOMUP = 64, + kQAVTOMIDLE = 65, + kQAVTOMFIRE = 66, + kQAVTOMSPRED = 67, + kQAVTOMDOWN = 68, - kQAV2TOMUP = 69, - kQAV2TOMIDLE = 70, - kQAV2TOMFIRE = 71, - kQAV2TOMDOWN = 72, - kQAV2TOMALT = 73, + 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, + 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, + kQAV2SGUNUP = 82, + kQAV2SGUNIDL = 83, + kQAV2SGUNFIR = 84, + kQAV2SGUNALT = 85, + kQAV2SGUNPRE = 86, + kQAV2SGUNPST = 87, + kQAV2SGUNDWN = 88, - kQAVNAPUP = 89, - kQAVNAPIDLE = 90, - kQAVNAPFIRE = 91, - kQAVNAPDOWN = 92, + kQAVNAPUP = 89, + kQAVNAPIDLE = 90, + kQAVNAPFIRE = 91, + kQAVNAPDOWN = 92, - kQAVBSTUP = 93, - kQAVBSTIDLE = 94, - kQAVBSTATAK1 = 95, - kQAVBSTATAK2 = 96, - kQAVBSTATAK3 = 97, - kQAVBSTATAK4 = 98, - kQAVBSTDOWN = 99, + 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, + 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, + 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, + kQAV2NAPUP = 120, + kQAV2NAPIDLE = 121, + kQAV2NAPFIRE = 122, + kQAV2NAPFIR2 = 123, + kQAV2NAPDOWN = 124, - kQAVEnd = 125, + kQAVEnd = 125, - kQAVBDRIP = 256, + kQAVBDRIP = 256, }; // by NoOne: add sound flags enum { - kFlagSoundKill = 0x01, // mute QAV sounds of same priority - kFlagSoundKillAll = 0x02, // mute all QAV sounds + kFlagSoundKill = 0x01, // mute QAV sounds of same priority + kFlagSoundKillAll = 0x02, // mute all QAV sounds }; struct TILE_FRAME { - int picnum; - int x; - int y; - int z; - int stat; - int8_t shade; - int8_t palnum; - uint16_t angle; + int picnum; + int x; + int y; + int z; + int stat; + int8_t shade; + int8_t palnum; + uint16_t angle; }; struct SOUNDINFO { - int sound; - uint8_t priority; - uint8_t sndFlags; // (by NoOne) Various sound flags - uint8_t sndRange; // (by NoOne) Random sound range - uint8_t reserved[1]; + int sound; + uint8_t priority; + uint8_t sndFlags; // (by NoOne) Various sound flags + uint8_t sndRange; // (by NoOne) Random sound range + uint8_t reserved[1]; }; struct FRAMEINFO { - int nCallbackId; // 0 - SOUNDINFO sound; // 4 - TILE_FRAME tiles[8]; // 12 + int nCallbackId; // 0 + SOUNDINFO sound; // 4 + TILE_FRAME tiles[8]; // 12 }; struct QAV { - double ticrate; // 0 - int nFrames; // 8 - int ticksPerFrame; // C - int duration; // 10 - int x; // 14 - int y; // 18 - uint16_t 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); - 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, PLAYER *); - void Precache(int palette = 0); + double ticrate; // 0 + int nFrames; // 8 + int ticksPerFrame; // C + int duration; // 10 + int x; // 14 + int y; // 18 + uint16_t 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); + 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, PLAYER*); + void Precache(int palette = 0); }; QAV* getQAV(int res_id); @@ -241,13 +241,13 @@ void qavProcessTimer(PLAYER* const pPlayer, QAV* const pQAV, int* duration, doub inline bool qavIsOriginal(const int res_id) { - auto const lump = fileSystem.FindResource(res_id, "QAV"); - return lump >= 0 && fileSystem.GetFileContainer(lump) < fileSystem.GetMaxIwadNum(); + 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; + return cl_bloodweapinterp && qavIsOriginal(res_id) && fileSystem.FindResource(res_id + 10000, "QAV") != -1 ? res_id + 10000 : res_id; } END_BLD_NS diff --git a/source/games/blood/src/sbar.cpp b/source/games/blood/src/sbar.cpp index ea6d77030..05779dd09 100644 --- a/source/games/blood/src/sbar.cpp +++ b/source/games/blood/src/sbar.cpp @@ -43,45 +43,57 @@ CVAR(Bool, hud_ctf_vanilla, false, CVAR_ARCHIVE) BEGIN_BLD_NS +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + static void UpdateFrame(void) { - auto tex = tileGetTexture(kBackTile); - int width = twod->GetWidth(); - int height = twod->GetHeight(); + auto tex = tileGetTexture(kBackTile); + int width = twod->GetWidth(); + int height = twod->GetHeight(); - twod->AddFlatFill(0, 0, width, windowxy1.Y - 3, tex); - twod->AddFlatFill(0, windowxy2.Y + 4, width, height, tex); - twod->AddFlatFill(0, windowxy1.Y - 3, windowxy1.X - 3, windowxy2.Y + 4, tex); - twod->AddFlatFill(windowxy2.X + 4, windowxy1.Y - 3, width, windowxy2.Y + 4, tex); + twod->AddFlatFill(0, 0, width, windowxy1.Y - 3, tex); + twod->AddFlatFill(0, windowxy2.Y + 4, width, height, tex); + twod->AddFlatFill(0, windowxy1.Y - 3, windowxy1.X - 3, windowxy2.Y + 4, tex); + twod->AddFlatFill(windowxy2.X + 4, windowxy1.Y - 3, width, windowxy2.Y + 4, tex); - twod->AddFlatFill(windowxy1.X - 3, windowxy1.Y - 3, windowxy1.X, windowxy2.Y + 1, tex, 0, 1, 0xff545454); - twod->AddFlatFill(windowxy1.X, windowxy1.Y - 3, windowxy2.X + 4, windowxy1.Y, tex, 0, 1, 0xff545454); - twod->AddFlatFill(windowxy2.X + 1, windowxy1.Y, windowxy2.X + 4, windowxy2.Y + 4, tex, 0, 1, 0xff2a2a2a); - twod->AddFlatFill(windowxy1.X - 3, windowxy2.Y + 1, windowxy2.X + 1, windowxy2.Y + 4, tex, 0, 1, 0xff2a2a2a); + twod->AddFlatFill(windowxy1.X - 3, windowxy1.Y - 3, windowxy1.X, windowxy2.Y + 1, tex, 0, 1, 0xff545454); + twod->AddFlatFill(windowxy1.X, windowxy1.Y - 3, windowxy2.X + 4, windowxy1.Y, tex, 0, 1, 0xff545454); + twod->AddFlatFill(windowxy2.X + 1, windowxy1.Y, windowxy2.X + 4, windowxy2.Y + 4, tex, 0, 1, 0xff2a2a2a); + twod->AddFlatFill(windowxy1.X - 3, windowxy2.Y + 1, windowxy2.X + 1, windowxy2.Y + 4, tex, 0, 1, 0xff2a2a2a); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void UpdateStatusBar() { - if (automapMode == am_off && hud_size <= Hud_Stbar) - { - UpdateFrame(); - } - SummaryInfo sum; - if (gGameOptions.nGameType == 3) - { - sum.kills = gView ? gView->fragCount : 0; - sum.maxkills = -3; - } - else - { - sum.kills = gKillMgr.Kills; - sum.maxkills = gKillMgr.TotalKills; - } - sum.secrets = gSecretMgr.Founds; - sum.supersecrets = gSecretMgr.Super; - sum.maxsecrets = max(gSecretMgr.Founds, gSecretMgr.Total); // If we found more than there are, increase the total. Some levels have a bugged counter. - sum.time = Scale(PlayClock, 1000, 120); - UpdateStatusBar(&sum); + if (automapMode == am_off && hud_size <= Hud_Stbar) + { + UpdateFrame(); + } + SummaryInfo sum; + if (gGameOptions.nGameType == 3) + { + sum.kills = gView ? gView->fragCount : 0; + sum.maxkills = -3; + } + else + { + sum.kills = gKillMgr.Kills; + sum.maxkills = gKillMgr.TotalKills; + } + sum.secrets = gSecretMgr.Founds; + sum.supersecrets = gSecretMgr.Super; + sum.maxsecrets = max(gSecretMgr.Founds, gSecretMgr.Total); // If we found more than there are, increase the total. Some levels have a bugged counter. + sum.time = Scale(PlayClock, 1000, 120); + UpdateStatusBar(&sum); } diff --git a/source/games/blood/src/sectorfx.cpp b/source/games/blood/src/sectorfx.cpp index f73f9a5f4..6f7096c3c 100644 --- a/source/games/blood/src/sectorfx.cpp +++ b/source/games/blood/src/sectorfx.cpp @@ -30,321 +30,355 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. BEGIN_BLD_NS static const uint8_t flicker1[] = { - 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, - 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, - 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1 + 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, + 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1 }; static const uint8_t flicker2[] = { - 1, 2, 4, 2, 3, 4, 3, 2, 0, 0, 1, 2, 4, 3, 2, 0, - 2, 1, 0, 1, 0, 2, 3, 4, 3, 2, 1, 1, 2, 0, 0, 1, - 1, 2, 3, 4, 4, 3, 2, 1, 2, 3, 4, 4, 2, 1, 0, 1, - 0, 0, 0, 0, 1, 2, 3, 4, 3, 2, 1, 2, 3, 4, 3, 2 + 1, 2, 4, 2, 3, 4, 3, 2, 0, 0, 1, 2, 4, 3, 2, 0, + 2, 1, 0, 1, 0, 2, 3, 4, 3, 2, 1, 1, 2, 0, 0, 1, + 1, 2, 3, 4, 4, 3, 2, 1, 2, 3, 4, 4, 2, 1, 0, 1, + 0, 0, 0, 0, 1, 2, 3, 4, 3, 2, 1, 2, 3, 4, 3, 2 }; static const uint8_t flicker3[] = { - 4, 4, 4, 4, 3, 4, 4, 4, 4, 4, 4, 2, 4, 3, 4, 4, - 4, 4, 2, 1, 3, 3, 3, 4, 3, 4, 4, 4, 4, 4, 2, 4, - 4, 4, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 1, 0, 1, - 0, 1, 0, 1, 0, 2, 3, 4, 4, 4, 4, 4, 4, 4, 3, 4 + 4, 4, 4, 4, 3, 4, 4, 4, 4, 4, 4, 2, 4, 3, 4, 4, + 4, 4, 2, 1, 3, 3, 3, 4, 3, 4, 4, 4, 4, 4, 2, 4, + 4, 4, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 1, 0, 1, + 0, 1, 0, 1, 0, 2, 3, 4, 4, 4, 4, 4, 4, 4, 3, 4 }; static const uint8_t flicker4[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 4, 0, 0, 3, 0, 1, 0, 1, 0, 4, 4, 4, 4, 4, 2, 0, - 0, 0, 0, 4, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1, 4, 3, 2, - 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0, 0, 0 ,0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0, 0, 0 ,0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0, 0, 0 ,0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0, 0, 0 ,0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 0, 0, 3, 0, 1, 0, 1, 0, 4, 4, 4, 4, 4, 2, 0, + 0, 0, 0, 4, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1, 4, 3, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0, 0, 0 ,0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0, 0, 0 ,0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0, 0, 0 ,0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0, 0, 0 ,0, 0 }; static const uint8_t strobe[] = { - 64, 64, 64, 48, 36, 27, 20, 15, 11, 9, 6, 5, 4, 3, 2, 2, - 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 64, 64, 64, 48, 36, 27, 20, 15, 11, 9, 6, 5, 4, 3, 2, 2, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + int GetWaveValue(int a, int b, int c) { - b &= 2047; - switch (a) - { - case 0: - return c; - case 1: - return (b>>10)*c; - case 2: - return (abs(128-(b>>3))*c)>>7; - case 3: - return ((b>>3)*c)>>8; - case 4: - return ((255-(b>>3))*c)>>8; - case 5: - return (c+MulScale(c,Sin(b), 30))>>1; - case 6: - return flicker1[b>>5]*c; - case 7: - return (flicker2[b>>5]*c)>>2; - case 8: - return (flicker3[b>>5]*c)>>2; - case 9: - return (flicker4[b>>4]*c)>>2; - case 10: - return (strobe[b>>5]*c)>>6; - case 11: - if (b*4 > 2048) - return 0; - return (c-MulScale(c, Cos(b*4), 30))>>1; - } - return 0; + b &= 2047; + switch (a) + { + case 0: + return c; + case 1: + return (b >> 10) * c; + case 2: + return (abs(128 - (b >> 3)) * c) >> 7; + case 3: + return ((b >> 3) * c) >> 8; + case 4: + return ((255 - (b >> 3)) * c) >> 8; + case 5: + return (c + MulScale(c, Sin(b), 30)) >> 1; + case 6: + return flicker1[b >> 5] * c; + case 7: + return (flicker2[b >> 5] * c) >> 2; + case 8: + return (flicker3[b >> 5] * c) >> 2; + case 9: + return (flicker4[b >> 4] * c) >> 2; + case 10: + return (strobe[b >> 5] * c) >> 6; + case 11: + if (b * 4 > 2048) + return 0; + return (c - MulScale(c, Cos(b * 4), 30)) >> 1; + } + return 0; } +//--------------------------------------------------------------------------- +// // These can be fully regenerated after loading a savegame. +// +//--------------------------------------------------------------------------- + TArray shadeList; TArray panList; TArray wallPanList; +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void DoSectorLighting(void) { - for (auto& pSector : shadeList) - { - XSECTOR* pXSector = &pSector->xs(); - if (pXSector->shade) - { - int v4 = pXSector->shade; - if (pXSector->shadeFloor) - { - pSector->floorshade -= v4; - if (pXSector->color) - { - int nTemp = pXSector->floorpal; - pXSector->floorpal = pSector->floorpal; - pSector->floorpal = nTemp; - } - } - if (pXSector->shadeCeiling) - { - pSector->ceilingshade -= v4; - if (pXSector->color) - { - int nTemp = pXSector->ceilpal; - pXSector->ceilpal = pSector->ceilingpal; - pSector->ceilingpal = nTemp; - } - } - if (pXSector->shadeWalls) - { - for(auto& wal : wallsofsector(pSector)) - { - wal.shade -= v4; - if (pXSector->color) - { - wal.pal = pSector->floorpal; - } - } - } - pXSector->shade = 0; - } - if (pXSector->shadeAlways || pXSector->busy) - { - int t1 = pXSector->wave; - int t2 = pXSector->amplitude; - if (!pXSector->shadeAlways && pXSector->busy) - { - t2 = MulScale(t2, pXSector->busy, 16); - } - int v4 = GetWaveValue(t1, pXSector->phase*8+pXSector->freq*PlayClock, t2); - if (pXSector->shadeFloor) - { - pSector->floorshade = ClipRange(pSector->floorshade+v4, -128, 127); - if (pXSector->color && v4 != 0) - { - int nTemp = pXSector->floorpal; - pXSector->floorpal = pSector->floorpal; - pSector->floorpal = nTemp; - } - } - if (pXSector->shadeCeiling) - { - pSector->ceilingshade = ClipRange(pSector->ceilingshade+v4, -128, 127); - if (pXSector->color && v4 != 0) - { - int nTemp = pXSector->ceilpal; - pXSector->ceilpal = pSector->ceilingpal; - pSector->ceilingpal = nTemp; - } - } - if (pXSector->shadeWalls) - { - for (auto& wal : wallsofsector(pSector)) - { - wal.shade = ClipRange(wal.shade+v4, -128, 127); - if (pXSector->color && v4 != 0) - { - wal.pal = pSector->floorpal; - } - } - } - pXSector->shade = v4; - } - } + for (auto& pSector : shadeList) + { + XSECTOR* pXSector = &pSector->xs(); + if (pXSector->shade) + { + int v4 = pXSector->shade; + if (pXSector->shadeFloor) + { + pSector->floorshade -= v4; + if (pXSector->color) + { + int nTemp = pXSector->floorpal; + pXSector->floorpal = pSector->floorpal; + pSector->floorpal = nTemp; + } + } + if (pXSector->shadeCeiling) + { + pSector->ceilingshade -= v4; + if (pXSector->color) + { + int nTemp = pXSector->ceilpal; + pXSector->ceilpal = pSector->ceilingpal; + pSector->ceilingpal = nTemp; + } + } + if (pXSector->shadeWalls) + { + for (auto& wal : wallsofsector(pSector)) + { + wal.shade -= v4; + if (pXSector->color) + { + wal.pal = pSector->floorpal; + } + } + } + pXSector->shade = 0; + } + if (pXSector->shadeAlways || pXSector->busy) + { + int t1 = pXSector->wave; + int t2 = pXSector->amplitude; + if (!pXSector->shadeAlways && pXSector->busy) + { + t2 = MulScale(t2, pXSector->busy, 16); + } + int v4 = GetWaveValue(t1, pXSector->phase * 8 + pXSector->freq * PlayClock, t2); + if (pXSector->shadeFloor) + { + pSector->floorshade = ClipRange(pSector->floorshade + v4, -128, 127); + if (pXSector->color && v4 != 0) + { + int nTemp = pXSector->floorpal; + pXSector->floorpal = pSector->floorpal; + pSector->floorpal = nTemp; + } + } + if (pXSector->shadeCeiling) + { + pSector->ceilingshade = ClipRange(pSector->ceilingshade + v4, -128, 127); + if (pXSector->color && v4 != 0) + { + int nTemp = pXSector->ceilpal; + pXSector->ceilpal = pSector->ceilingpal; + pSector->ceilingpal = nTemp; + } + } + if (pXSector->shadeWalls) + { + for (auto& wal : wallsofsector(pSector)) + { + wal.shade = ClipRange(wal.shade + v4, -128, 127); + if (pXSector->color && v4 != 0) + { + wal.pal = pSector->floorpal; + } + } + } + pXSector->shade = v4; + } + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void UndoSectorLighting(void) { - for (auto& sect: sector) - { - if (sect.hasX()) - { - XSECTOR *pXSector = §.xs(); - if (pXSector->shade) - { - int v4 = pXSector->shade; - if (pXSector->shadeFloor) - { - sect.floorshade -= v4; - if (pXSector->color) - { - int nTemp = pXSector->floorpal; - pXSector->floorpal = sect.floorpal; - sect.floorpal = nTemp; - } - } - if (pXSector->shadeCeiling) - { - sect.ceilingshade -= v4; - if (pXSector->color) - { - int nTemp = pXSector->ceilpal; - pXSector->ceilpal = sect.ceilingpal; - sect.ceilingpal = nTemp; - } - } - if (pXSector->shadeWalls) - { - for(auto& wal : wallsofsector(§)) - { - wal.shade -= v4; - if (pXSector->color) - { - wal.pal = sect.floorpal; - } - } - } - pXSector->shade = 0; - } - } - } + for (auto& sect : sector) + { + if (sect.hasX()) + { + XSECTOR* pXSector = §.xs(); + if (pXSector->shade) + { + int v4 = pXSector->shade; + if (pXSector->shadeFloor) + { + sect.floorshade -= v4; + if (pXSector->color) + { + int nTemp = pXSector->floorpal; + pXSector->floorpal = sect.floorpal; + sect.floorpal = nTemp; + } + } + if (pXSector->shadeCeiling) + { + sect.ceilingshade -= v4; + if (pXSector->color) + { + int nTemp = pXSector->ceilpal; + pXSector->ceilpal = sect.ceilingpal; + sect.ceilingpal = nTemp; + } + } + if (pXSector->shadeWalls) + { + for (auto& wal : wallsofsector(§)) + { + wal.shade -= v4; + if (pXSector->color) + { + wal.pal = sect.floorpal; + } + } + } + pXSector->shade = 0; + } + } + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- void DoSectorPanning(void) { - for(auto pSector : panList) - { - XSECTOR *pXSector = &pSector->xs(); - if (pXSector->panAlways || pXSector->busy) - { - int angle = pXSector->panAngle+1024; - int speed = pXSector->panVel<<10; - if (!pXSector->panAlways && (pXSector->busy&0xffff)) - speed = MulScale(speed, pXSector->busy, 16); + for (auto pSector : panList) + { + XSECTOR* pXSector = &pSector->xs(); + if (pXSector->panAlways || pXSector->busy) + { + int angle = pXSector->panAngle + 1024; + int speed = pXSector->panVel << 10; + if (!pXSector->panAlways && (pXSector->busy & 0xffff)) + speed = MulScale(speed, pXSector->busy, 16); - if (pXSector->panFloor) // Floor - { - int nTile = pSector->floorpicnum; - if (pSector->floorstat & CSTAT_SECTOR_ALIGN) - angle -= 512; - int xBits = tileWidth(nTile) >> int((pSector->floorstat & CSTAT_SECTOR_TEXHALF) != 0); - int px = MulScale(speed << 2, Cos(angle), 30) / xBits; - int yBits = tileHeight(nTile) >> int((pSector->floorstat & CSTAT_SECTOR_TEXHALF) != 0); - int py = MulScale(speed << 2, Sin(angle), 30) / yBits; - pSector->addfloorxpan(px * (1.f / 256)); - pSector->addfloorypan(-py * (1.f / 256)); - } - if (pXSector->panCeiling) // Ceiling - { - int nTile = pSector->ceilingpicnum; - if (pSector->ceilingstat & CSTAT_SECTOR_ALIGN) - angle -= 512; - int xBits = tileWidth(nTile) >> int((pSector->ceilingstat & CSTAT_SECTOR_TEXHALF) != 0); - int px = MulScale(speed << 2, Cos(angle), 30) / xBits; - int yBits = tileHeight(nTile) >> int((pSector->ceilingstat & CSTAT_SECTOR_TEXHALF) != 0); - int py = MulScale(speed << 2, Sin(angle), 30) / yBits; - pSector->addceilingxpan(px * (1.f / 256)); - pSector->addceilingypan(-py * (1.f / 256)); - } - } - } - for (auto pWall : wallPanList) - { - XWALL *pXWall = &pWall->xw(); - if (pXWall->panAlways || pXWall->busy) - { - int psx = pXWall->panXVel<<10; - int psy = pXWall->panYVel<<10; - if (!pXWall->panAlways && (pXWall->busy & 0xffff)) - { - psx = MulScale(psx, pXWall->busy, 16); - psy = MulScale(psy, pXWall->busy, 16); - } - int nTile = pWall->picnum; - int px = (psx << 2) / tileWidth(nTile); - int py = (psy << 2) / tileHeight(nTile); + if (pXSector->panFloor) // Floor + { + int nTile = pSector->floorpicnum; + if (pSector->floorstat & CSTAT_SECTOR_ALIGN) + angle -= 512; + int xBits = tileWidth(nTile) >> int((pSector->floorstat & CSTAT_SECTOR_TEXHALF) != 0); + int px = MulScale(speed << 2, Cos(angle), 30) / xBits; + int yBits = tileHeight(nTile) >> int((pSector->floorstat & CSTAT_SECTOR_TEXHALF) != 0); + int py = MulScale(speed << 2, Sin(angle), 30) / yBits; + pSector->addfloorxpan(px * (1.f / 256)); + pSector->addfloorypan(-py * (1.f / 256)); + } + if (pXSector->panCeiling) // Ceiling + { + int nTile = pSector->ceilingpicnum; + if (pSector->ceilingstat & CSTAT_SECTOR_ALIGN) + angle -= 512; + int xBits = tileWidth(nTile) >> int((pSector->ceilingstat & CSTAT_SECTOR_TEXHALF) != 0); + int px = MulScale(speed << 2, Cos(angle), 30) / xBits; + int yBits = tileHeight(nTile) >> int((pSector->ceilingstat & CSTAT_SECTOR_TEXHALF) != 0); + int py = MulScale(speed << 2, Sin(angle), 30) / yBits; + pSector->addceilingxpan(px * (1.f / 256)); + pSector->addceilingypan(-py * (1.f / 256)); + } + } + } + for (auto pWall : wallPanList) + { + XWALL* pXWall = &pWall->xw(); + if (pXWall->panAlways || pXWall->busy) + { + int psx = pXWall->panXVel << 10; + int psy = pXWall->panYVel << 10; + if (!pXWall->panAlways && (pXWall->busy & 0xffff)) + { + psx = MulScale(psx, pXWall->busy, 16); + psy = MulScale(psy, pXWall->busy, 16); + } + int nTile = pWall->picnum; + int px = (psx << 2) / tileWidth(nTile); + int py = (psy << 2) / tileHeight(nTile); - pWall->addxpan(px * (1.f / 256)); - pWall->addypan(py * (1.f / 256)); - } - } + pWall->addxpan(px * (1.f / 256)); + pWall->addypan(py * (1.f / 256)); + } + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void InitSectorFX(void) { - shadeList.Clear(); - panList.Clear(); - wallPanList.Clear(); - for (auto& sect: sector) - { - if (sect.hasX()) - { - XSECTOR *pXSector = §.xs(); - if (pXSector->amplitude) - shadeList.Push(§); - if (pXSector->panVel) - { - panList.Push(§); + shadeList.Clear(); + panList.Clear(); + wallPanList.Clear(); + for (auto& sect : sector) + { + if (sect.hasX()) + { + XSECTOR* pXSector = §.xs(); + if (pXSector->amplitude) + shadeList.Push(§); + if (pXSector->panVel) + { + panList.Push(§); - if (pXSector->panCeiling) - { - StartInterpolation(§, Interp_Sect_CeilingPanX); - StartInterpolation(§, Interp_Sect_CeilingPanY); - } - if (pXSector->panFloor) - { - StartInterpolation(§, Interp_Sect_FloorPanX); - StartInterpolation(§, Interp_Sect_FloorPanY); - } + if (pXSector->panCeiling) + { + StartInterpolation(§, Interp_Sect_CeilingPanX); + StartInterpolation(§, Interp_Sect_CeilingPanY); + } + if (pXSector->panFloor) + { + StartInterpolation(§, Interp_Sect_FloorPanX); + StartInterpolation(§, Interp_Sect_FloorPanY); + } - } - } - } - for(auto& wal : wall) - { - if (wal.hasX()) - { - XWALL *pXWall = &wal.xw(); - if (pXWall->panXVel || pXWall->panYVel) - { - wallPanList.Push(&wal); - if (pXWall->panXVel) StartInterpolation(&wal, Interp_Wall_PanX); - if (pXWall->panXVel) StartInterpolation(&wal, Interp_Wall_PanY); - } - } - } + } + } + } + for (auto& wal : wall) + { + if (wal.hasX()) + { + XWALL* pXWall = &wal.xw(); + if (pXWall->panXVel || pXWall->panYVel) + { + wallPanList.Push(&wal); + if (pXWall->panXVel) StartInterpolation(&wal, Interp_Wall_PanX); + if (pXWall->panXVel) StartInterpolation(&wal, Interp_Wall_PanY); + } + } + } } diff --git a/source/games/blood/src/seq.cpp b/source/games/blood/src/seq.cpp index c977c9822..3ef163e91 100644 --- a/source/games/blood/src/seq.cpp +++ b/source/games/blood/src/seq.cpp @@ -351,7 +351,7 @@ void SEQINST::Update() if (!VanillaMode() && pSequence->frames[frameIndex].surfaceSound && actor->zvel == 0 && actor->xvel != 0) { if (actor->spr.sector()->upperLink) break; // don't play surface sound for stacked sectors - int surf = tileGetSurfType(actor->spr.sector()->floorpicnum); + int surf = tileGetSurfType(actor->spr.sector()->floorpicnum); if (!surf) break; static int surfSfxMove[15][4] = { /* {snd1, snd2, gameVolume, myVolume} */ @@ -704,7 +704,7 @@ void seqProcess(int nTicks) { evKillActor(actor); if ((actor->spr.hitag & kAttrRespawn) != 0 && (actor->spr.inittype >= kDudeBase && actor->spr.inittype < kDudeMax)) - evPostActor(actor, gGameOptions.nMonsterRespawnTime, kCallbackRespawn); + evPostActor(actor, gGameOptions.nMonsterRespawnTime, kCallbackRespawn); else DeleteSprite(actor); // safe to not use actPostSprite here } } @@ -747,8 +747,8 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, SEQINST& w, SEQINS ("timecounter", w.timeCounter) ("frameindex", w.frameIndex) ("target", w.target); - - arc.EndObject(); + + arc.EndObject(); } return arc; } diff --git a/source/games/blood/src/sfx.cpp b/source/games/blood/src/sfx.cpp index f6fca7dc4..1ee2b73ad 100644 --- a/source/games/blood/src/sfx.cpp +++ b/source/games/blood/src/sfx.cpp @@ -31,27 +31,27 @@ BEGIN_BLD_NS class BloodSoundEngine : public RazeSoundEngine { - // client specific parts of the sound engine go in this class. - void CalcPosVel(int type, const void* source, const float pt[3], int channum, int chanflags, FSoundID chanSound, FVector3* pos, FVector3* vel, FSoundChan *channel) override; - TArray ReadSound(int lumpnum) override; + // client specific parts of the sound engine go in this class. + void CalcPosVel(int type, const void* source, const float pt[3], int channum, int chanflags, FSoundID chanSound, FVector3* pos, FVector3* vel, FSoundChan* channel) override; + TArray ReadSound(int lumpnum) override; public: - BloodSoundEngine() - { - S_Rolloff.RolloffType = ROLLOFF_Doom; - S_Rolloff.MinDistance = 170; // these are the numbers I got when uncrunching the original sound code. - S_Rolloff.MaxDistance = 850; - } + BloodSoundEngine() + { + S_Rolloff.RolloffType = ROLLOFF_Doom; + S_Rolloff.MinDistance = 170; // these are the numbers I got when uncrunching the original sound code. + S_Rolloff.MaxDistance = 850; + } - void StopChannel(FSoundChan* chan) override - { - if (chan && chan->SysChannel != nullptr && !(chan->ChanFlags & CHANF_EVICTED) && chan->SourceType == SOURCE_Actor) - { - chan->Source = nullptr; - chan->SourceType = SOURCE_Unattached; - } - SoundEngine::StopChannel(chan); - } + void StopChannel(FSoundChan* chan) override + { + if (chan && chan->SysChannel != nullptr && !(chan->ChanFlags & CHANF_EVICTED) && chan->SourceType == SOURCE_Actor) + { + chan->Source = nullptr; + chan->SourceType = SOURCE_Unattached; + } + SoundEngine::StopChannel(chan); + } @@ -65,205 +65,240 @@ public: TArray BloodSoundEngine::ReadSound(int lumpnum) { - auto wlump = fileSystem.OpenFileReader(lumpnum); - return wlump.Read(); + auto wlump = fileSystem.OpenFileReader(lumpnum); + return wlump.Read(); } -void BloodSoundEngine::CalcPosVel(int type, const void* source, const float pt[3], int channum, int chanflags, FSoundID chanSound, FVector3* pos, FVector3* vel, FSoundChan *) +void BloodSoundEngine::CalcPosVel(int type, const void* source, const float pt[3], int channum, int chanflags, FSoundID chanSound, FVector3* pos, FVector3* vel, FSoundChan*) { - if (pos != nullptr && type != SOURCE_None) - { - FVector3 camera; - - if (gMe && gMe->actor) camera = GetSoundPos(&gMe->actor->spr.pos); - else camera = { 0, 0, 0 }; // don't crash if there is no player. + if (pos != nullptr && type != SOURCE_None) + { + FVector3 camera; - if (vel) vel->Zero(); + if (gMe && gMe->actor) camera = GetSoundPos(&gMe->actor->spr.pos); + else camera = { 0, 0, 0 }; // don't crash if there is no player. - if (type == SOURCE_Unattached) - { - pos->X = pt[0]; - pos->Y = pt[1]; - pos->Z = pt[2]; - } - else if (type == SOURCE_Actor) - { - assert(source != nullptr); - auto actor = (DBloodActor*)source; + if (vel) vel->Zero(); - // Engine expects velocity in units per second, not units per tic. - if (vel) *vel = { actor->xvel * (30 / 65536.f), actor->zvel * (-30 / 65536.f), actor->yvel * (-30 / 65536.f) }; - *pos = GetSoundPos(&actor->spr.pos); - } - else if (type == SOURCE_Ambient) - { - *pos = camera; // just to be safe. Ambient sounds are in the world but unpositioned - } - if ((chanflags & CHANF_LISTENERZ)) - { - pos->Y = camera.Y; - } - } + if (type == SOURCE_Unattached) + { + pos->X = pt[0]; + pos->Y = pt[1]; + pos->Z = pt[2]; + } + else if (type == SOURCE_Actor) + { + assert(source != nullptr); + auto actor = (DBloodActor*)source; + + // Engine expects velocity in units per second, not units per tic. + if (vel) *vel = { actor->xvel * (30 / 65536.f), actor->zvel * (-30 / 65536.f), actor->yvel * (-30 / 65536.f) }; + *pos = GetSoundPos(&actor->spr.pos); + } + else if (type == SOURCE_Ambient) + { + *pos = camera; // just to be safe. Ambient sounds are in the world but unpositioned + } + if ((chanflags & CHANF_LISTENERZ)) + { + pos->Y = camera.Y; + } + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- void GameInterface::UpdateSounds() { - SoundListener listener; + SoundListener listener; - if (gMe->actor) - { - listener.angle = -gMe->actor->spr.ang * float(BAngRadian); // Build uses a period of 2048. - listener.velocity.Zero(); - listener.position = GetSoundPos(&gMe->actor->spr.pos); - listener.valid = true; - } - else - { - listener.position.Zero(); - listener.valid = false; - } - listener.underwater = false; - // This should probably use a real environment instead of the pitch hacking in S_PlaySound3D. - // listenactor->waterlevel == 3; - //assert(primaryLevel->Zones.Size() > listenactor->Sector->ZoneNumber); - listener.Environment = 0;// primaryLevel->Zones[listenactor->Sector->ZoneNumber].Environment; + if (gMe->actor) + { + listener.angle = -gMe->actor->spr.ang * float(BAngRadian); // Build uses a period of 2048. + listener.velocity.Zero(); + listener.position = GetSoundPos(&gMe->actor->spr.pos); + listener.valid = true; + } + else + { + listener.position.Zero(); + listener.valid = false; + } + listener.underwater = false; + // This should probably use a real environment instead of the pitch hacking in S_PlaySound3D. + // listenactor->waterlevel == 3; + //assert(primaryLevel->Zones.Size() > listenactor->Sector->ZoneNumber); + listener.Environment = 0;// primaryLevel->Zones[listenactor->Sector->ZoneNumber].Environment; - listener.ListenerObject = gMe; - soundEngine->SetListener(listener); - soundEngine->UpdateSounds(I_GetTime()); + listener.ListenerObject = gMe; + soundEngine->SetListener(listener); + soundEngine->UpdateSounds(I_GetTime()); } -FSoundID getSfx(FSoundID soundId, float &attenuation, int &pitch, int &relvol) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +FSoundID getSfx(FSoundID soundId, float& attenuation, int& pitch, int& relvol) { - auto udata = soundEngine->GetUserData(soundId); - if (pitch < 0) pitch = udata ? udata[0] : 0x10000; + auto udata = soundEngine->GetUserData(soundId); + if (pitch < 0) pitch = udata ? udata[0] : 0x10000; if (relvol < 0) relvol = 0; - else if (relvol == 0) relvol = udata && udata[2] ? udata[2] : 80; - if (relvol > 255) relvol = 255; - // Limit the attenuation. More than 2.0 is simply too much. - attenuation = relvol > 0 ? clamp(80.f / relvol, 0.f, 2.f) : 1.f; - return soundId; + else if (relvol == 0) relvol = udata && udata[2] ? udata[2] : 80; + if (relvol > 255) relvol = 255; + // Limit the attenuation. More than 2.0 is simply too much. + attenuation = relvol > 0 ? clamp(80.f / relvol, 0.f, 2.f) : 1.f; + return soundId; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void sfxPlay3DSound(int x, int y, int z, int soundId, sectortype* pSector) { - if (!SoundEnabled() || soundId < 0) return; - auto sid = soundEngine->FindSoundByResID(soundId); - if (sid == 0) return; + if (!SoundEnabled() || soundId < 0) return; + auto sid = soundEngine->FindSoundByResID(soundId); + if (sid == 0) return; - vec3_t xyz = { x, y, z }; - auto svec = GetSoundPos(&xyz); + vec3_t xyz = { x, y, z }; + auto svec = GetSoundPos(&xyz); - float attenuation; - int pitch = -1; - int relvol = 0; - sid = getSfx(sid, attenuation, pitch, relvol); - auto sfx = soundEngine->GetSfx(sid); - EChanFlags flags = CHANF_OVERLAP; - if (sfx && sfx->LoopStart >= 0) flags |= CHANF_LOOP; - - auto chan = soundEngine->StartSound(SOURCE_Unattached, nullptr, &svec, -1, flags, sid, (0.8f / 80.f) * relvol, attenuation, nullptr, pitch / 65536.f); - if (chan) chan->UserData = sectnum(pSector); + float attenuation; + int pitch = -1; + int relvol = 0; + sid = getSfx(sid, attenuation, pitch, relvol); + auto sfx = soundEngine->GetSfx(sid); + EChanFlags flags = CHANF_OVERLAP; + if (sfx && sfx->LoopStart >= 0) flags |= CHANF_LOOP; + + auto chan = soundEngine->StartSound(SOURCE_Unattached, nullptr, &svec, -1, flags, sid, (0.8f / 80.f) * relvol, attenuation, nullptr, pitch / 65536.f); + if (chan) chan->UserData = sectnum(pSector); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void sfxPlay3DSoundCP(DBloodActor* pActor, int soundId, int playchannel, int playflags, int pitch, int volume) { - if (!SoundEnabled() || soundId < 0 || !pActor) return; - auto sid = soundEngine->FindSoundByResID(soundId); - if (sid == 0) return; + if (!SoundEnabled() || soundId < 0 || !pActor) return; + auto sid = soundEngine->FindSoundByResID(soundId); + if (sid == 0) return; - auto svec = GetSoundPos(&pActor->spr.pos); + auto svec = GetSoundPos(&pActor->spr.pos); - float attenuation; - sid = getSfx(sid, attenuation, pitch, volume); - if (volume == -1) volume = 80; + float attenuation; + sid = getSfx(sid, attenuation, pitch, volume); + if (volume == -1) volume = 80; - if (playchannel >= 0) - { - 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 == playchannel && (chan->Source == pActor || (playflags & FX_GlobalChannel) != 0)) - { - if ((playflags & FX_ChannelMatch) != 0 && chan->EntChannel == playchannel) - return true; - if ((playflags & FX_SoundMatch) != 0 && chan->OrgID == sid) - return true; - soundEngine->StopChannel(chan); - return -1; - } - return false; - })) return; + if (playchannel >= 0) + { + 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 == playchannel && (chan->Source == pActor || (playflags & FX_GlobalChannel) != 0)) + { + if ((playflags & FX_ChannelMatch) != 0 && chan->EntChannel == playchannel) + return true; + if ((playflags & FX_SoundMatch) != 0 && chan->OrgID == sid) + return true; + soundEngine->StopChannel(chan); + return -1; + } + return false; + })) return; - } + } - auto sfx = soundEngine->GetSfx(sid); - EChanFlags flags = playchannel == -1 ? CHANF_OVERLAP : CHANF_NONE; - if (sfx && sfx->LoopStart >= 0) - { - flags |= CHANF_LOOP; - flags &= ~CHANF_OVERLAP; - } + auto sfx = soundEngine->GetSfx(sid); + EChanFlags flags = playchannel == -1 ? CHANF_OVERLAP : CHANF_NONE; + if (sfx && sfx->LoopStart >= 0) + { + flags |= CHANF_LOOP; + flags &= ~CHANF_OVERLAP; + } - soundEngine->StartSound(SOURCE_Actor, pActor, &svec, playchannel, flags, sid, volume * (0.8f / 80.f), attenuation, nullptr, pitch / 65536.f); + soundEngine->StartSound(SOURCE_Actor, pActor, &svec, playchannel, flags, sid, volume * (0.8f / 80.f), attenuation, nullptr, pitch / 65536.f); } void sfxPlay3DSound(DBloodActor* pActor, int soundId, int a3, int a4) { - sfxPlay3DSoundCP(pActor, soundId, a3, a4, -1); + sfxPlay3DSoundCP(pActor, soundId, a3, a4, -1); } -void sfxKill3DSound(DBloodActor *pActor, int a2, int a3) -{ - if (!pActor) - return; +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- - if (a2 >= 0) a2++; - auto sid = soundEngine->FindSoundByResID(a3); - soundEngine->EnumerateChannels([=](FSoundChan* channel) - { - if (channel->SourceType == SOURCE_Actor && channel->Source == pActor && (a2 < 0 || a2 == channel->EntChannel) && (a3 < 0 || sid == channel->OrgID)) - { - soundEngine->StopChannel(channel); - } - return false; - }); +void sfxKill3DSound(DBloodActor* pActor, int a2, int a3) +{ + if (!pActor) + return; + + if (a2 >= 0) a2++; + auto sid = soundEngine->FindSoundByResID(a3); + soundEngine->EnumerateChannels([=](FSoundChan* channel) + { + if (channel->SourceType == SOURCE_Actor && channel->Source == pActor && (a2 < 0 || a2 == channel->EntChannel) && (a3 < 0 || sid == channel->OrgID)) + { + soundEngine->StopChannel(channel); + } + return false; + }); } void sfxKillAllSounds(void) { - soundEngine->EnumerateChannels([](FSoundChan* channel) - { - if (channel->SourceType == SOURCE_Actor || channel->SourceType == SOURCE_Unattached) soundEngine->StopChannel(channel); - return false; - }); + soundEngine->EnumerateChannels([](FSoundChan* channel) + { + if (channel->SourceType == SOURCE_Actor || channel->SourceType == SOURCE_Unattached) soundEngine->StopChannel(channel); + return false; + }); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void sfxSetReverb(bool toggle) { - if (toggle) - { - FX_SetReverb(128); - FX_SetReverbDelay(10); - } - else - FX_SetReverb(0); + if (toggle) + { + FX_SetReverb(128); + FX_SetReverbDelay(10); + } + else + FX_SetReverb(0); } void sfxSetReverb2(bool toggle) { - if (toggle) - { - FX_SetReverb(128); - FX_SetReverbDelay(20); - } - else - FX_SetReverb(0); + if (toggle) + { + FX_SetReverb(128); + FX_SetReverbDelay(20); + } + else + FX_SetReverb(0); } END_BLD_NS diff --git a/source/games/blood/src/sound.cpp b/source/games/blood/src/sound.cpp index c95c574b8..efff1ae3b 100644 --- a/source/games/blood/src/sound.cpp +++ b/source/games/blood/src/sound.cpp @@ -31,30 +31,30 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. BEGIN_BLD_NS int soundRates[13] = { - 11025, - 11025, - 11025, - 11025, - 11025, - 22050, - 22050, - 22050, - 22050, - 44100, - 44100, - 44100, - 44100, + 11025, + 11025, + 11025, + 11025, + 11025, + 22050, + 22050, + 22050, + 22050, + 44100, + 44100, + 44100, + 44100, }; void ByteSwapSFX(SFX* pSFX) { #if WORDS_BIGENDIAN - pSFX->relVol = LittleLong(pSFX->relVol); - pSFX->pitch = LittleLong(pSFX->pitch); - pSFX->pitchRange = LittleLong(pSFX->pitchRange); - pSFX->format = LittleLong(pSFX->format); - pSFX->loopStart = LittleLong(pSFX->loopStart); + pSFX->relVol = LittleLong(pSFX->relVol); + pSFX->pitch = LittleLong(pSFX->pitch); + pSFX->pitchRange = LittleLong(pSFX->pitchRange); + pSFX->format = LittleLong(pSFX->format); + pSFX->loopStart = LittleLong(pSFX->loopStart); #endif } @@ -69,137 +69,156 @@ void ByteSwapSFX(SFX* pSFX) static void S_AddBloodSFX(int lumpnum) { - auto sfxlump = fileSystem.ReadFile(lumpnum); - SFX* sfx = (SFX*)sfxlump.GetMem(); - ByteSwapSFX(sfx); - FStringf rawname("%s.raw", sfx->rawName); - auto rawlump = fileSystem.FindFile(rawname); - int sfxnum; + auto sfxlump = fileSystem.ReadFile(lumpnum); + SFX* sfx = (SFX*)sfxlump.GetMem(); + ByteSwapSFX(sfx); + FStringf rawname("%s.raw", sfx->rawName); + auto rawlump = fileSystem.FindFile(rawname); + int sfxnum; - if (rawlump != -1) - { - auto& S_sfx = soundEngine->GetSounds(); - sfxnum = soundEngine->AddSoundLump(sfx->rawName, rawlump, 0, fileSystem.GetResourceId(lumpnum), 6); - if (sfx->format < 5 || sfx->format > 12) - { // [0..4] + invalid formats - S_sfx[sfxnum].RawRate = 11025; - } - else if (sfx->format < 9) - { // [5..8] - S_sfx[sfxnum].RawRate = 22050; - } - else - { // [9..12] - S_sfx[sfxnum].RawRate = 44100; - } - S_sfx[sfxnum].bLoadRAW = true; - S_sfx[sfxnum].LoopStart = LittleLong(sfx->loopStart); - //S_sfx[sfxnum].Volume = sfx->relVol / 255.f; This cannot be done because this volume setting is optional. - S_sfx[sfxnum].UserData.Resize(3); - int* udata = (int*)S_sfx[sfxnum].UserData.Data(); - udata[0] = sfx->pitch; - udata[1] = sfx->pitchRange; - udata[2] = sfx->relVol; - } + if (rawlump != -1) + { + auto& S_sfx = soundEngine->GetSounds(); + sfxnum = soundEngine->AddSoundLump(sfx->rawName, rawlump, 0, fileSystem.GetResourceId(lumpnum), 6); + if (sfx->format < 5 || sfx->format > 12) + { // [0..4] + invalid formats + S_sfx[sfxnum].RawRate = 11025; + } + else if (sfx->format < 9) + { // [5..8] + S_sfx[sfxnum].RawRate = 22050; + } + else + { // [9..12] + S_sfx[sfxnum].RawRate = 44100; + } + S_sfx[sfxnum].bLoadRAW = true; + S_sfx[sfxnum].LoopStart = LittleLong(sfx->loopStart); + //S_sfx[sfxnum].Volume = sfx->relVol / 255.f; This cannot be done because this volume setting is optional. + S_sfx[sfxnum].UserData.Resize(3); + int* udata = (int*)S_sfx[sfxnum].UserData.Data(); + udata[0] = sfx->pitch; + udata[1] = sfx->pitchRange; + udata[2] = sfx->relVol; + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void sndInit(void) { - soundEngine = new BloodSoundEngine; - soundEngine->AddSoundLump("", 0, 0, -1, 6); // add a dummy entry at index #0 - for (int i = fileSystem.GetNumEntries() - 1; i >= 0; i--) - { - auto type = fileSystem.GetResourceType(i); - if (!stricmp(type, "SFX")) - { - if (soundEngine->FindSoundByResID(fileSystem.GetResourceId(i)) == 0) - S_AddBloodSFX(i); - } - else if (!stricmp(type, "WAV") || !stricmp(type, "OGG") || !stricmp(type, "FLAC") || !stricmp(type, "VOC")) - { - if (fileSystem.GetFileNamespace(i) != ns_music) - soundEngine->AddSoundLump(fileSystem.GetFileFullName(i), i, 0, fileSystem.GetResourceId(i)| 0x40000000, 6); // mark the resource ID as special. - } - } - soundEngine->HashSounds(); + soundEngine = new BloodSoundEngine; + soundEngine->AddSoundLump("", 0, 0, -1, 6); // add a dummy entry at index #0 + for (int i = fileSystem.GetNumEntries() - 1; i >= 0; i--) + { + auto type = fileSystem.GetResourceType(i); + if (!stricmp(type, "SFX")) + { + if (soundEngine->FindSoundByResID(fileSystem.GetResourceId(i)) == 0) + S_AddBloodSFX(i); + } + else if (!stricmp(type, "WAV") || !stricmp(type, "OGG") || !stricmp(type, "FLAC") || !stricmp(type, "VOC")) + { + if (fileSystem.GetFileNamespace(i) != ns_music) + soundEngine->AddSoundLump(fileSystem.GetFileFullName(i), i, 0, fileSystem.GetResourceId(i) | 0x40000000, 6); // mark the resource ID as special. + } + } + soundEngine->HashSounds(); } - - +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- int sndGetRate(int format) { - if (format < 13) - return soundRates[format]; - return 11025; + if (format < 13) + return soundRates[format]; + return 11025; } - - bool sndCheckPlaying(unsigned int nSound) { - auto snd = soundEngine->FindSoundByResID(nSound); - return snd > 0 ? soundEngine->GetSoundPlayingInfo(SOURCE_Any, nullptr, snd) : false; + auto snd = soundEngine->FindSoundByResID(nSound); + return snd > 0 ? soundEngine->GetSoundPlayingInfo(SOURCE_Any, nullptr, snd) : false; } void sndStopSample(unsigned int nSound) { - auto snd = soundEngine->FindSoundByResID(nSound); + auto snd = soundEngine->FindSoundByResID(nSound); - if (snd > 0) - { - soundEngine->StopSoundID(snd); - } + if (snd > 0) + { + soundEngine->StopSoundID(snd); + } } -void sndStartSample(const char *pzSound, int nVolume, int nChannel) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void sndStartSample(const char* pzSound, int nVolume, int nChannel) { - if (!SoundEnabled()) - return; - if (!strlen(pzSound)) - return; - auto snd = soundEngine->FindSound(pzSound); - if (snd > 0) - { - soundEngine->StartSound(SOURCE_None, nullptr, nullptr, nChannel + 1, 0, snd, nVolume / 255.f, ATTN_NONE); - } + if (!SoundEnabled()) + return; + if (!strlen(pzSound)) + return; + auto snd = soundEngine->FindSound(pzSound); + if (snd > 0) + { + soundEngine->StartSound(SOURCE_None, nullptr, nullptr, nChannel + 1, 0, snd, nVolume / 255.f, ATTN_NONE); + } } void sndStartSample(unsigned int nSound, int nVolume, int nChannel, bool bLoop, EChanFlags chanflags) { - if (!SoundEnabled()) - return; - if (nChannel >= 7) nChannel = -1; - auto snd = soundEngine->FindSoundByResID(nSound); - if (snd > 0) - { - if (nVolume < 0) - { - auto udata = soundEngine->GetUserData(snd); - if (udata) nVolume = min(Scale(udata[2], 255, 100), 255); - else nVolume = 255; - } - if (bLoop) chanflags |= CHANF_LOOP; - soundEngine->StopActorSounds(SOURCE_None, nullptr, nChannel + 1, nChannel + 1); - soundEngine->StartSound(SOURCE_None, nullptr, nullptr, (nChannel + 1), chanflags, snd, nVolume / 255.f, ATTN_NONE); - } + if (!SoundEnabled()) + return; + if (nChannel >= 7) nChannel = -1; + auto snd = soundEngine->FindSoundByResID(nSound); + if (snd > 0) + { + if (nVolume < 0) + { + auto udata = soundEngine->GetUserData(snd); + if (udata) nVolume = min(Scale(udata[2], 255, 100), 255); + else nVolume = 255; + } + if (bLoop) chanflags |= CHANF_LOOP; + soundEngine->StopActorSounds(SOURCE_None, nullptr, nChannel + 1, nChannel + 1); + soundEngine->StartSound(SOURCE_None, nullptr, nullptr, (nChannel + 1), chanflags, snd, nVolume / 255.f, ATTN_NONE); + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void sndStartWavID(unsigned int nSound, int nVolume, int nChannel) { - return sndStartSample(nSound | 0x40000000, nVolume, nChannel); + return sndStartSample(nSound | 0x40000000, nVolume, nChannel); } -void sndStartWavDisk(const char *pzFile, int nVolume, int nChannel) +void sndStartWavDisk(const char* pzFile, int nVolume, int nChannel) { - FString name = pzFile; - FixPathSeperator(name); - return sndStartSample(name, nVolume, nChannel); + FString name = pzFile; + FixPathSeperator(name); + return sndStartSample(name, nVolume, nChannel); } void sndKillAllSounds(void) { - soundEngine->StopSound(CHAN_AUTO); + soundEngine->StopSound(CHAN_AUTO); } diff --git a/source/games/blood/src/sound.h b/source/games/blood/src/sound.h index a09a6e877..bdc942c14 100644 --- a/source/games/blood/src/sound.h +++ b/source/games/blood/src/sound.h @@ -30,30 +30,30 @@ BEGIN_BLD_NS struct SFX { - int relVol; - int pitch; - int pitchRange; - int format; - int loopStart; - char rawName[9]; + int relVol; + int pitch; + int pitchRange; + int format; + int loopStart; + char rawName[9]; }; int sndGetRate(int format); bool sndCheckPlaying(unsigned int nSound); void sndStopSample(unsigned int nSound); -void sndStartSample(const char *pzSound, int nVolume, int nChannel = -1); +void sndStartSample(const char* pzSound, int nVolume, int nChannel = -1); void sndStartSample(unsigned int nSound, int nVolume, int nChannel = -1, bool bLoop = false, EChanFlags soundflags = CHANF_NONE); void sndStartWavID(unsigned int nSound, int nVolume, int nChannel = -1); -void sndStartWavDisk(const char *pzFile, int nVolume, int nChannel = -1); +void sndStartWavDisk(const char* pzFile, int nVolume, int nChannel = -1); void sndKillAllSounds(void); void sndProcess(void); void sndTerm(void); void sndInit(void); void sfxPlay3DSound(int x, int y, int z, int soundId, sectortype* pSector); -void sfxPlay3DSound(DBloodActor *pSprite, int soundId, int a3 = -1, int a4 = 0); +void sfxPlay3DSound(DBloodActor* pSprite, int soundId, int a3 = -1, int a4 = 0); void sfxPlay3DSoundCP(DBloodActor* pSprite, int soundId, int a3 = -1, int a4 = 0, int pitch = 0, int volume = 0); -void sfxKill3DSound(DBloodActor *pSprite, int a2 = -1, int a3 = -1); +void sfxKill3DSound(DBloodActor* pSprite, int a2 = -1, int a3 = -1); void sfxKillAllSounds(void); void sfxSetReverb(bool toggle); void sfxSetReverb2(bool toggle); @@ -64,9 +64,9 @@ void ambInit(void); enum EPlayFlags { - FX_GlobalChannel = 1, - FX_SoundMatch = 2, - FX_ChannelMatch = 4, + FX_GlobalChannel = 1, + FX_SoundMatch = 2, + FX_ChannelMatch = 4, }; diff --git a/source/games/blood/src/tile.cpp b/source/games/blood/src/tile.cpp index 5796c6aff..2b83673c6 100644 --- a/source/games/blood/src/tile.cpp +++ b/source/games/blood/src/tile.cpp @@ -42,6 +42,12 @@ uint8_t surfType[kMaxTiles]; int8_t tileShade[kMaxTiles]; short voxelIndex[kMaxTiles]; +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void GameInterface::LoadGameTextures() { auto hFile = fileSystem.OpenFileReader("SURFACE.DAT"); @@ -70,6 +76,12 @@ void GameInterface::LoadGameTextures() } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + int tileGetSurfType(int hit) { return surfType[hit]; @@ -90,6 +102,12 @@ int tileGetSurfType(CollisionBase& hit) } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void GameInterface::SetTileProps(int tile, int surf, int vox, int shade) { if (surf != INT_MAX) surfType[tile] = surf; diff --git a/source/games/blood/src/trig.cpp b/source/games/blood/src/trig.cpp index 34856a47a..a064b9b4b 100644 --- a/source/games/blood/src/trig.cpp +++ b/source/games/blood/src/trig.cpp @@ -31,24 +31,24 @@ int OctantTable[8] = { 5, 6, 2, 1, 4, 7, 3, 0 }; int GetOctant(int x, int y) { - int vc = abs(x)-abs(y); - return OctantTable[7-(x<0)-(y<0)*2-(vc<0)*4]; + int vc = abs(x) - abs(y); + return OctantTable[7 - (x < 0) - (y < 0) * 2 - (vc < 0) * 4]; } -void RotateVector(int *dx, int *dy, int nAngle) +void RotateVector(int* dx, int* dy, int nAngle) { - int ox = *dx; - int oy = *dy; - *dx = dmulscale30r(ox, Cos(nAngle), -oy, Sin(nAngle)); - *dy = dmulscale30r(ox, Sin(nAngle), oy, Cos(nAngle)); + int ox = *dx; + int oy = *dy; + *dx = dmulscale30r(ox, Cos(nAngle), -oy, Sin(nAngle)); + *dy = dmulscale30r(ox, Sin(nAngle), oy, Cos(nAngle)); } -void RotatePoint(int *x, int *y, int nAngle, int ox, int oy) +void RotatePoint(int* x, int* y, int nAngle, int ox, int oy) { - int dx = *x-ox; - int dy = *y-oy; - *x = ox+dmulscale30r(dx, Cos(nAngle), -dy, Sin(nAngle)); - *y = oy+dmulscale30r(dx, Sin(nAngle), dy, Cos(nAngle)); + int dx = *x - ox; + int dy = *y - oy; + *x = ox + dmulscale30r(dx, Cos(nAngle), -dy, Sin(nAngle)); + *y = oy + dmulscale30r(dx, Sin(nAngle), dy, Cos(nAngle)); } END_BLD_NS diff --git a/source/games/blood/src/triggers.cpp b/source/games/blood/src/triggers.cpp index 522880f0c..ebee86d58 100644 --- a/source/games/blood/src/triggers.cpp +++ b/source/games/blood/src/triggers.cpp @@ -32,2116 +32,2428 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. BEGIN_BLD_NS +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + unsigned int GetWaveValue(unsigned int nPhase, int nType) { - switch (nType) - { - case 0: - return 0x8000-(Cos(FixedToInt(nPhase<<10))>>15); - case 1: - return nPhase; - case 2: - return 0x10000-(Cos(FixedToInt(nPhase<<9))>>14); - case 3: - return Sin(FixedToInt(nPhase<<9))>>14; - } - return nPhase; + switch (nType) + { + case 0: + return 0x8000 - (Cos(FixedToInt(nPhase << 10)) >> 15); + case 1: + return nPhase; + case 2: + return 0x10000 - (Cos(FixedToInt(nPhase << 9)) >> 14); + case 3: + return Sin(FixedToInt(nPhase << 9)) >> 14; + } + return nPhase; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + bool SetSpriteState(DBloodActor* actor, int nState) { - if ((actor->xspr.busy & 0xffff) == 0 && actor->xspr.state == nState) - return 0; - actor->xspr.busy = IntToFixed(nState); - actor->xspr.state = nState; - evKillActor(actor); - if ((actor->spr.flags & kHitagRespawn) != 0 && actor->spr.inittype >= kDudeBase && actor->spr.inittype < kDudeMax) - { - actor->xspr.respawnPending = 3; - evPostActor(actor, gGameOptions.nMonsterRespawnTime, kCallbackRespawn); - return 1; - } - if (actor->xspr.restState != nState && actor->xspr.waitTime > 0) - evPostActor(actor, (actor->xspr.waitTime * 120) / 10, actor->xspr.restState ? kCmdOn : kCmdOff); - if (actor->xspr.txID) - { - if (actor->xspr.command != kCmdLink && actor->xspr.triggerOn && actor->xspr.state) - evSendActor(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); - if (actor->xspr.command != kCmdLink && actor->xspr.triggerOff && !actor->xspr.state) - evSendActor(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); - } - return 1; + if ((actor->xspr.busy & 0xffff) == 0 && actor->xspr.state == nState) + return 0; + actor->xspr.busy = IntToFixed(nState); + actor->xspr.state = nState; + evKillActor(actor); + if ((actor->spr.flags & kHitagRespawn) != 0 && actor->spr.inittype >= kDudeBase && actor->spr.inittype < kDudeMax) + { + actor->xspr.respawnPending = 3; + evPostActor(actor, gGameOptions.nMonsterRespawnTime, kCallbackRespawn); + return 1; + } + if (actor->xspr.restState != nState && actor->xspr.waitTime > 0) + evPostActor(actor, (actor->xspr.waitTime * 120) / 10, actor->xspr.restState ? kCmdOn : kCmdOff); + if (actor->xspr.txID) + { + if (actor->xspr.command != kCmdLink && actor->xspr.triggerOn && actor->xspr.state) + evSendActor(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + if (actor->xspr.command != kCmdLink && actor->xspr.triggerOff && !actor->xspr.state) + evSendActor(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + } + return 1; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + bool SetWallState(walltype* pWall, int nState) { - auto pXWall = &pWall->xw(); - if ((pXWall->busy&0xffff) == 0 && pXWall->state == nState) - return 0; - pXWall->busy = IntToFixed(nState); - pXWall->state = nState; - evKillWall(pWall); - if (pXWall->restState != nState && pXWall->waitTime > 0) - evPostWall(pWall, (pXWall->waitTime*120) / 10, pXWall->restState ? kCmdOn : kCmdOff); - if (pXWall->txID) - { - if (pXWall->command != kCmdLink && pXWall->triggerOn && pXWall->state) - evSendWall(pWall, pXWall->txID, (COMMAND_ID)pXWall->command); - if (pXWall->command != kCmdLink && pXWall->triggerOff && !pXWall->state) - evSendWall(pWall, pXWall->txID, (COMMAND_ID)pXWall->command); - } - return 1; + auto pXWall = &pWall->xw(); + if ((pXWall->busy & 0xffff) == 0 && pXWall->state == nState) + return 0; + pXWall->busy = IntToFixed(nState); + pXWall->state = nState; + evKillWall(pWall); + if (pXWall->restState != nState && pXWall->waitTime > 0) + evPostWall(pWall, (pXWall->waitTime * 120) / 10, pXWall->restState ? kCmdOn : kCmdOff); + if (pXWall->txID) + { + if (pXWall->command != kCmdLink && pXWall->triggerOn && pXWall->state) + evSendWall(pWall, pXWall->txID, (COMMAND_ID)pXWall->command); + if (pXWall->command != kCmdLink && pXWall->triggerOff && !pXWall->state) + evSendWall(pWall, pXWall->txID, (COMMAND_ID)pXWall->command); + } + return 1; } -bool SetSectorState(sectortype *pSector, int nState) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +bool SetSectorState(sectortype* pSector, int nState) { - assert(pSector->hasX()); - auto pXSector = &pSector->xs(); - if ((pXSector->busy&0xffff) == 0 && pXSector->state == nState) - return 0; - pXSector->busy = IntToFixed(nState); - pXSector->state = nState; - evKillSector(pSector); - if (nState == 1) - { - if (pXSector->command != kCmdLink && pXSector->triggerOn && pXSector->txID) - evSendSector(pSector,pXSector->txID, (COMMAND_ID)pXSector->command); - if (pXSector->stopOn) - { - pXSector->stopOn = 0; - pXSector->stopOff = 0; - } - else if (pXSector->reTriggerA) - evPostSector(pSector, (pXSector->waitTimeA * 120) / 10, kCmdOff); - } - else - { - if (pXSector->command != kCmdLink && pXSector->triggerOff && pXSector->txID) - evSendSector(pSector,pXSector->txID, (COMMAND_ID)pXSector->command); - if (pXSector->stopOff) - { - pXSector->stopOn = 0; - pXSector->stopOff = 0; - } - else if (pXSector->reTriggerB) - evPostSector(pSector, (pXSector->waitTimeB * 120) / 10, kCmdOn); - } - return 1; + assert(pSector->hasX()); + auto pXSector = &pSector->xs(); + if ((pXSector->busy & 0xffff) == 0 && pXSector->state == nState) + return 0; + pXSector->busy = IntToFixed(nState); + pXSector->state = nState; + evKillSector(pSector); + if (nState == 1) + { + if (pXSector->command != kCmdLink && pXSector->triggerOn && pXSector->txID) + evSendSector(pSector, pXSector->txID, (COMMAND_ID)pXSector->command); + if (pXSector->stopOn) + { + pXSector->stopOn = 0; + pXSector->stopOff = 0; + } + else if (pXSector->reTriggerA) + evPostSector(pSector, (pXSector->waitTimeA * 120) / 10, kCmdOff); + } + else + { + if (pXSector->command != kCmdLink && pXSector->triggerOff && pXSector->txID) + evSendSector(pSector, pXSector->txID, (COMMAND_ID)pXSector->command); + if (pXSector->stopOff) + { + pXSector->stopOn = 0; + pXSector->stopOff = 0; + } + else if (pXSector->reTriggerB) + evPostSector(pSector, (pXSector->waitTimeB * 120) / 10, kCmdOn); + } + return 1; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + TArray gBusy; void AddBusy(sectortype* pSector, BUSYID a2, int nDelta) { - assert(nDelta != 0); - for (auto& b : gBusy) - { - if (b.sect == pSector && b.type == a2) - { - b.delta = nDelta; - return; - } - } - BUSY b = { pSector, nDelta, nDelta > 0 ? 0 : 65536, a2 }; - gBusy.Push(b); + assert(nDelta != 0); + for (auto& b : gBusy) + { + if (b.sect == pSector && b.type == a2) + { + b.delta = nDelta; + return; + } + } + BUSY b = { pSector, nDelta, nDelta > 0 ? 0 : 65536, a2 }; + gBusy.Push(b); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void ReverseBusy(sectortype* pSector, BUSYID a2) { - for (auto& b : gBusy) - { - if (b.sect == pSector && b.type == a2) - { - b.delta = -b.delta; - break; - } - } + for (auto& b : gBusy) + { + if (b.sect == pSector && b.type == a2) + { + b.delta = -b.delta; + break; + } + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + unsigned int GetSourceBusy(EVENT& a1) { - if (a1.isSector()) - { - auto sect = a1.getSector(); - return sect->hasX()? sect->xs().busy : 0; - } - else if (a1.isWall()) - { - auto wal = a1.getWall(); - return wal->hasX()? wal->xw().busy : 0; - } - else if (a1.isActor()) - { - auto pActor = a1.getActor(); - return pActor && pActor->hasX() ? pActor->xspr.busy : false; - } - return 0; + if (a1.isSector()) + { + auto sect = a1.getSector(); + return sect->hasX() ? sect->xs().busy : 0; + } + else if (a1.isWall()) + { + auto wal = a1.getWall(); + return wal->hasX() ? wal->xw().busy : 0; + } + else if (a1.isActor()) + { + auto pActor = a1.getActor(); + return pActor && pActor->hasX() ? pActor->xspr.busy : false; + } + return 0; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void LifeLeechOperate(DBloodActor* actor, EVENT event) { - switch (event.cmd) { - case kCmdSpritePush: - { - int nPlayer = actor->xspr.data4; - if (nPlayer >= 0 && nPlayer < kMaxPlayers && playeringame[nPlayer]) - { - PLAYER *pPlayer = &gPlayer[nPlayer]; - if (pPlayer->actor->xspr.health > 0) - { - evKillActor(actor); - pPlayer->ammoCount[8] = ClipHigh(pPlayer->ammoCount[8]+actor->xspr.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; - } - } - } - break; - } - case kCmdSpriteProximity: - { - auto target = actor->GetTarget(); - if (target) - { - if (!actor->xspr.stateTimer) - { - if (target->spr.statnum == kStatDude && !(target->spr.flags&32) && target->hasX()) - { - int top, bottom; - GetActorExtents(actor, &top, &bottom); - int nType = target->spr.type-kDudeBase; - DUDEINFO *pDudeInfo = getDudeInfo(nType+kDudeBase); - int z1 = (top-actor->spr.pos.Z)-256; - int x = target->spr.pos.X; - int y = target->spr.pos.Y; - int z = target->spr.pos.Z; - int nDist = approxDist(x - actor->spr.pos.X, y - actor->spr.pos.Y); - if (nDist != 0 && cansee(actor->spr.pos.X, actor->spr.pos.Y, top, actor->spr.sector(), x, y, z, target->spr.sector())) - { - int t = DivScale(nDist, 0x1aaaaa, 12); - x += (target->xvel*t)>>12; - y += (target->yvel*t)>>12; - int angBak = actor->spr.ang; - actor->spr.ang = getangle(x-actor->spr.pos.X, y-actor->spr.pos.Y); - int dx = bcos(actor->spr.ang); - int dy = bsin(actor->spr.ang); - int tz = target->spr.pos.Z - (target->spr.yrepeat * pDudeInfo->aimHeight) * 4; - int dz = DivScale(tz - top - 256, nDist, 10); - int nMissileType = kMissileLifeLeechAltNormal + (actor->xspr.data3 ? 1 : 0); - int t2; - if (!actor->xspr.data3) - t2 = 120 / 10; - else - t2 = (3*120) / 10; - auto missile = actFireMissile(actor, 0, z1, dx, dy, dz, nMissileType); - if (missile) - { - missile->SetOwner(actor); - actor->xspr.stateTimer = 1; - evPostActor(actor, t2, kCallbackLeechStateTimer); - actor->xspr.data3 = ClipLow(actor->xspr.data3-1, 0); - if (!VanillaMode()) // disable collisions so lifeleech doesn't do that weird bobbing - missile->spr.cstat &= ~CSTAT_SPRITE_BLOCK_ALL; - } - actor->spr.ang = angBak; - } - } - } - } - return; - } - } - actPostSprite(actor, kStatFree); + switch (event.cmd) { + case kCmdSpritePush: + { + int nPlayer = actor->xspr.data4; + if (nPlayer >= 0 && nPlayer < kMaxPlayers && playeringame[nPlayer]) + { + PLAYER* pPlayer = &gPlayer[nPlayer]; + if (pPlayer->actor->xspr.health > 0) + { + evKillActor(actor); + pPlayer->ammoCount[8] = ClipHigh(pPlayer->ammoCount[8] + actor->xspr.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; + } + } + } + break; + } + case kCmdSpriteProximity: + { + auto target = actor->GetTarget(); + if (target) + { + if (!actor->xspr.stateTimer) + { + if (target->spr.statnum == kStatDude && !(target->spr.flags & 32) && target->hasX()) + { + int top, bottom; + GetActorExtents(actor, &top, &bottom); + int nType = target->spr.type - kDudeBase; + DUDEINFO* pDudeInfo = getDudeInfo(nType + kDudeBase); + int z1 = (top - actor->spr.pos.Z) - 256; + int x = target->spr.pos.X; + int y = target->spr.pos.Y; + int z = target->spr.pos.Z; + int nDist = approxDist(x - actor->spr.pos.X, y - actor->spr.pos.Y); + if (nDist != 0 && cansee(actor->spr.pos.X, actor->spr.pos.Y, top, actor->spr.sector(), x, y, z, target->spr.sector())) + { + int t = DivScale(nDist, 0x1aaaaa, 12); + x += (target->xvel * t) >> 12; + y += (target->yvel * t) >> 12; + int angBak = actor->spr.ang; + actor->spr.ang = getangle(x - actor->spr.pos.X, y - actor->spr.pos.Y); + int dx = bcos(actor->spr.ang); + int dy = bsin(actor->spr.ang); + int tz = target->spr.pos.Z - (target->spr.yrepeat * pDudeInfo->aimHeight) * 4; + int dz = DivScale(tz - top - 256, nDist, 10); + int nMissileType = kMissileLifeLeechAltNormal + (actor->xspr.data3 ? 1 : 0); + int t2; + if (!actor->xspr.data3) + t2 = 120 / 10; + else + t2 = (3 * 120) / 10; + auto missile = actFireMissile(actor, 0, z1, dx, dy, dz, nMissileType); + if (missile) + { + missile->SetOwner(actor); + actor->xspr.stateTimer = 1; + evPostActor(actor, t2, kCallbackLeechStateTimer); + actor->xspr.data3 = ClipLow(actor->xspr.data3 - 1, 0); + if (!VanillaMode()) // disable collisions so lifeleech doesn't do that weird bobbing + missile->spr.cstat &= ~CSTAT_SPRITE_BLOCK_ALL; + } + actor->spr.ang = angBak; + } + } + } + } + return; + } + } + actPostSprite(actor, kStatFree); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void ActivateGenerator(DBloodActor*); void OperateSprite(DBloodActor* actor, EVENT event) { - #ifdef NOONE_EXTENSIONS - if (gModernMap && modernTypeOperateSprite(actor, event)) - return; - #endif +#ifdef NOONE_EXTENSIONS + if (gModernMap && modernTypeOperateSprite(actor, event)) + return; +#endif - switch (event.cmd) { - case kCmdLock: - actor->xspr.locked = 1; - return; - case kCmdUnlock: - actor->xspr.locked = 0; - return; - case kCmdToggleLock: - actor->xspr.locked = actor->xspr.locked ^ 1; - return; - } + switch (event.cmd) { + case kCmdLock: + actor->xspr.locked = 1; + return; + case kCmdUnlock: + actor->xspr.locked = 0; + return; + case kCmdToggleLock: + actor->xspr.locked = actor->xspr.locked ^ 1; + return; + } - if (actor->spr.statnum == kStatDude && actor->spr.type >= kDudeBase && actor->spr.type < kDudeMax) { - - switch (event.cmd) { - case kCmdOff: - SetSpriteState(actor, 0); - break; - case kCmdSpriteProximity: - if (actor->xspr.state) break; - [[fallthrough]]; - case kCmdOn: - case kCmdSpritePush: - case kCmdSpriteTouch: - if (!actor->xspr.state) SetSpriteState(actor, 1); - aiActivateDude(actor); - break; - } + if (actor->spr.statnum == kStatDude && actor->spr.type >= kDudeBase && actor->spr.type < kDudeMax) { - return; - } + switch (event.cmd) { + case kCmdOff: + SetSpriteState(actor, 0); + break; + case kCmdSpriteProximity: + if (actor->xspr.state) break; + [[fallthrough]]; + case kCmdOn: + case kCmdSpritePush: + case kCmdSpriteTouch: + if (!actor->xspr.state) SetSpriteState(actor, 1); + aiActivateDude(actor); + break; + } + + return; + } - switch (actor->spr.type) { - case kTrapMachinegun: - if (actor->xspr.health <= 0) break; - switch (event.cmd) { - case kCmdOff: - if (!SetSpriteState(actor, 0)) break; - seqSpawn(40, actor, -1); - break; - case kCmdOn: - if (!SetSpriteState(actor, 1)) break; - seqSpawn(38, actor, nMGunOpenClient); - if (actor->xspr.data1 > 0) - actor->xspr.data2 = actor->xspr.data1; - break; - } - break; - case kThingFallingRock: - if (SetSpriteState(actor, 1)) - actor->spr.flags |= 7; - break; - case kThingWallCrack: - if (SetSpriteState(actor, 0)) - actPostSprite(actor, kStatFree); - break; - case kThingCrateFace: - if (SetSpriteState(actor, 0)) - actPostSprite(actor, kStatFree); - break; - case kTrapZapSwitchable: - switch (event.cmd) { - case kCmdOff: - actor->xspr.state = 0; - actor->spr.cstat |= CSTAT_SPRITE_INVISIBLE; - actor->spr.cstat &= ~CSTAT_SPRITE_BLOCK; - break; - case kCmdOn: - actor->xspr.state = 1; - actor->spr.cstat &= ~CSTAT_SPRITE_INVISIBLE; - actor->spr.cstat |= CSTAT_SPRITE_BLOCK; - break; - case kCmdToggle: - actor->xspr.state ^= 1; - actor->spr.cstat ^= CSTAT_SPRITE_INVISIBLE; - actor->spr.cstat ^= CSTAT_SPRITE_BLOCK; - break; - } - break; - case kTrapFlame: - switch (event.cmd) { - case kCmdOff: - if (!SetSpriteState(actor, 0)) break; - seqSpawn(40, actor, -1); - sfxKill3DSound(actor, 0, -1); - break; - case kCmdOn: - if (!SetSpriteState(actor, 1)) break; - seqSpawn(38, actor, -1); - sfxPlay3DSound(actor, 441, 0, 0); - break; - } - break; - case kSwitchPadlock: - switch (event.cmd) { - case kCmdOff: - SetSpriteState(actor, 0); - break; - case kCmdOn: - if (!SetSpriteState(actor, 1)) break; - seqSpawn(37, actor, -1); - break; - default: - SetSpriteState(actor, actor->xspr.state ^ 1); - if (actor->xspr.state) seqSpawn(37, actor, -1); - break; - } - break; - case kSwitchToggle: - switch (event.cmd) { - case kCmdOff: - if (!SetSpriteState(actor, 0)) break; - sfxPlay3DSound(actor, actor->xspr.data2, 0, 0); - break; - case kCmdOn: - if (!SetSpriteState(actor, 1)) break; - sfxPlay3DSound(actor, actor->xspr.data1, 0, 0); - break; - default: - if (!SetSpriteState(actor, actor->xspr.state ^ 1)) break; - if (actor->xspr.state) sfxPlay3DSound(actor, actor->xspr.data1, 0, 0); - else sfxPlay3DSound(actor, actor->xspr.data2, 0, 0); - break; - } - break; - case kSwitchOneWay: - switch (event.cmd) { - case kCmdOff: - if (!SetSpriteState(actor, 0)) break; - sfxPlay3DSound(actor, actor->xspr.data2, 0, 0); - break; - case kCmdOn: - if (!SetSpriteState(actor, 1)) break; - sfxPlay3DSound(actor, actor->xspr.data1, 0, 0); - break; - default: - if (!SetSpriteState(actor, actor->xspr.restState ^ 1)) break; - if (actor->xspr.state) sfxPlay3DSound(actor, actor->xspr.data1, 0, 0); - else sfxPlay3DSound(actor, actor->xspr.data2, 0, 0); - break; - } - break; - case kSwitchCombo: - switch (event.cmd) { - case kCmdOff: - actor->xspr.data1--; - if (actor->xspr.data1 < 0) - actor->xspr.data1 += actor->xspr.data3; - break; - default: - actor->xspr.data1++; - if (actor->xspr.data1 >= actor->xspr.data3) - actor->xspr.data1 -= actor->xspr.data3; - break; - } - - sfxPlay3DSound(actor, actor->xspr.data4, -1, 0); - - if (actor->xspr.command == kCmdLink && actor->xspr.txID > 0) - evSendActor(actor, actor->xspr.txID, kCmdLink); + switch (actor->spr.type) { + case kTrapMachinegun: + if (actor->xspr.health <= 0) break; + switch (event.cmd) { + case kCmdOff: + if (!SetSpriteState(actor, 0)) break; + seqSpawn(40, actor, -1); + break; + case kCmdOn: + if (!SetSpriteState(actor, 1)) break; + seqSpawn(38, actor, nMGunOpenClient); + if (actor->xspr.data1 > 0) + actor->xspr.data2 = actor->xspr.data1; + break; + } + break; + case kThingFallingRock: + if (SetSpriteState(actor, 1)) + actor->spr.flags |= 7; + break; + case kThingWallCrack: + if (SetSpriteState(actor, 0)) + actPostSprite(actor, kStatFree); + break; + case kThingCrateFace: + if (SetSpriteState(actor, 0)) + actPostSprite(actor, kStatFree); + break; + case kTrapZapSwitchable: + switch (event.cmd) { + case kCmdOff: + actor->xspr.state = 0; + actor->spr.cstat |= CSTAT_SPRITE_INVISIBLE; + actor->spr.cstat &= ~CSTAT_SPRITE_BLOCK; + break; + case kCmdOn: + actor->xspr.state = 1; + actor->spr.cstat &= ~CSTAT_SPRITE_INVISIBLE; + actor->spr.cstat |= CSTAT_SPRITE_BLOCK; + break; + case kCmdToggle: + actor->xspr.state ^= 1; + actor->spr.cstat ^= CSTAT_SPRITE_INVISIBLE; + actor->spr.cstat ^= CSTAT_SPRITE_BLOCK; + break; + } + break; + case kTrapFlame: + switch (event.cmd) { + case kCmdOff: + if (!SetSpriteState(actor, 0)) break; + seqSpawn(40, actor, -1); + sfxKill3DSound(actor, 0, -1); + break; + case kCmdOn: + if (!SetSpriteState(actor, 1)) break; + seqSpawn(38, actor, -1); + sfxPlay3DSound(actor, 441, 0, 0); + break; + } + break; + case kSwitchPadlock: + switch (event.cmd) { + case kCmdOff: + SetSpriteState(actor, 0); + break; + case kCmdOn: + if (!SetSpriteState(actor, 1)) break; + seqSpawn(37, actor, -1); + break; + default: + SetSpriteState(actor, actor->xspr.state ^ 1); + if (actor->xspr.state) seqSpawn(37, actor, -1); + break; + } + break; + case kSwitchToggle: + switch (event.cmd) { + case kCmdOff: + if (!SetSpriteState(actor, 0)) break; + sfxPlay3DSound(actor, actor->xspr.data2, 0, 0); + break; + case kCmdOn: + if (!SetSpriteState(actor, 1)) break; + sfxPlay3DSound(actor, actor->xspr.data1, 0, 0); + break; + default: + if (!SetSpriteState(actor, actor->xspr.state ^ 1)) break; + if (actor->xspr.state) sfxPlay3DSound(actor, actor->xspr.data1, 0, 0); + else sfxPlay3DSound(actor, actor->xspr.data2, 0, 0); + break; + } + break; + case kSwitchOneWay: + switch (event.cmd) { + case kCmdOff: + if (!SetSpriteState(actor, 0)) break; + sfxPlay3DSound(actor, actor->xspr.data2, 0, 0); + break; + case kCmdOn: + if (!SetSpriteState(actor, 1)) break; + sfxPlay3DSound(actor, actor->xspr.data1, 0, 0); + break; + default: + if (!SetSpriteState(actor, actor->xspr.restState ^ 1)) break; + if (actor->xspr.state) sfxPlay3DSound(actor, actor->xspr.data1, 0, 0); + else sfxPlay3DSound(actor, actor->xspr.data2, 0, 0); + break; + } + break; + case kSwitchCombo: + switch (event.cmd) { + case kCmdOff: + actor->xspr.data1--; + if (actor->xspr.data1 < 0) + actor->xspr.data1 += actor->xspr.data3; + break; + default: + actor->xspr.data1++; + if (actor->xspr.data1 >= actor->xspr.data3) + actor->xspr.data1 -= actor->xspr.data3; + break; + } - if (actor->xspr.data1 == actor->xspr.data2) - SetSpriteState(actor, 1); - else - SetSpriteState(actor, 0); + sfxPlay3DSound(actor, actor->xspr.data4, -1, 0); - break; - case kMarkerDudeSpawn: - if (gGameOptions.nMonsterSettings && actor->xspr.data1 >= kDudeBase && actor->xspr.data1 < kDudeMax) - { - auto spawned = actSpawnDude(actor, actor->xspr.data1, -1, 0); - if (spawned) { - gKillMgr.AddNewKill(1); - switch (actor->xspr.data1) { - case kDudeBurningInnocent: - case kDudeBurningCultist: - case kDudeBurningZombieButcher: - case kDudeBurningTinyCaleb: - case kDudeBurningBeast: { - spawned->xspr.health = getDudeInfo(actor->xspr.data1)->startHealth << 4; - spawned->xspr.burnTime = 10; - spawned->SetTarget(nullptr); - aiActivateDude(spawned); - break; - default: - break; - } - } - } - } - break; - case kMarkerEarthQuake: - actor->xspr.triggerOn = 0; - actor->xspr.isTriggered = 1; - SetSpriteState(actor, 1); - for (int p = connecthead; p >= 0; p = connectpoint2[p]) { - auto vec = actor->spr.pos - gPlayer[p].actor->spr.pos; - int dx = (vec.X)>>4; - int dy = (vec.Y)>>4; - int dz = (vec.Z)>>8; - int nDist = dx*dx+dy*dy+dz*dz+0x40000; - gPlayer[p].quakeEffect = DivScale(actor->xspr.data1, nDist, 16); - } - break; - case kThingTNTBarrel: - if (actor->spr.flags & kHitagRespawn) return; - [[fallthrough]]; - case kThingArmedTNTStick: - case kThingArmedTNTBundle: - case kThingArmedSpray: - actExplodeSprite(actor); - break; - case kTrapExploder: - switch (event.cmd) { - case kCmdOn: - SetSpriteState(actor, 1); - break; - default: - actor->spr.cstat &= ~CSTAT_SPRITE_INVISIBLE; - actExplodeSprite(actor); - break; - } - break; - case kThingArmedRemoteBomb: - if (actor->spr.statnum != kStatRespawn) { - if (event.cmd != kCmdOn) actExplodeSprite(actor); - else { - sfxPlay3DSound(actor, 454, 0, 0); - evPostActor(actor, 18, kCmdOff); - } - } - break; - case kThingArmedProxBomb: - if (actor->spr.statnum != kStatRespawn) { - switch (event.cmd) { - case kCmdSpriteProximity: - if (actor->xspr.state) break; - sfxPlay3DSound(actor, 452, 0, 0); - evPostActor(actor, 30, kCmdOff); - actor->xspr.state = 1; - [[fallthrough]]; - case kCmdOn: - sfxPlay3DSound(actor, 451, 0, 0); - actor->xspr.Proximity = 1; - break; - default: - actExplodeSprite(actor); - break; - } - } - break; - case kThingDroppedLifeLeech: - LifeLeechOperate(actor, event); - break; - case kGenTrigger: - case kGenDripWater: - case kGenDripBlood: - case kGenMissileFireball: - case kGenMissileEctoSkull: - case kGenDart: - case kGenBubble: - case kGenBubbleMulti: - case kGenSound: - switch (event.cmd) { - case kCmdOff: - SetSpriteState(actor, 0); - break; - case kCmdRepeat: - if (actor->spr.type != kGenTrigger) ActivateGenerator(actor); - if (actor->xspr.txID) evSendActor(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); - if (actor->xspr.busyTime > 0) { - int nRand = Random2(actor->xspr.data1); - evPostActor(actor, 120*(nRand+actor->xspr.busyTime) / 10, kCmdRepeat); - } - break; - default: - if (!actor->xspr.state) { - SetSpriteState(actor, 1); - evPostActor(actor, 0, kCmdRepeat); - } - break; - } - break; - case kSoundPlayer: - if (gGameOptions.nGameType == 0) - { - if (gMe->actor->xspr.health <= 0) - break; - gMe->restTime = 0; - } - sndStartSample(actor->xspr.data1, -1, 1, 0, CHANF_FORCE); - break; - case kThingObjectGib: - case kThingObjectExplode: - case kThingBloodBits: - case kThingBloodChunks: - case kThingZombieHead: - switch (event.cmd) { - case kCmdOff: - if (!SetSpriteState(actor, 0)) break; - actActivateGibObject(actor); - break; - case kCmdOn: - if (!SetSpriteState(actor, 1)) break; - actActivateGibObject(actor); - break; - default: - if (!SetSpriteState(actor, actor->xspr.state ^ 1)) break; - actActivateGibObject(actor); - break; - } - break; - default: - switch (event.cmd) { - case kCmdOff: - SetSpriteState(actor, 0); - break; - case kCmdOn: - SetSpriteState(actor, 1); - break; - default: - SetSpriteState(actor, actor->xspr.state ^ 1); - break; - } - break; - } + if (actor->xspr.command == kCmdLink && actor->xspr.txID > 0) + evSendActor(actor, actor->xspr.txID, kCmdLink); + + if (actor->xspr.data1 == actor->xspr.data2) + SetSpriteState(actor, 1); + else + SetSpriteState(actor, 0); + + break; + case kMarkerDudeSpawn: + if (gGameOptions.nMonsterSettings && actor->xspr.data1 >= kDudeBase && actor->xspr.data1 < kDudeMax) + { + auto spawned = actSpawnDude(actor, actor->xspr.data1, -1, 0); + if (spawned) { + gKillMgr.AddNewKill(1); + switch (actor->xspr.data1) { + case kDudeBurningInnocent: + case kDudeBurningCultist: + case kDudeBurningZombieButcher: + case kDudeBurningTinyCaleb: + case kDudeBurningBeast: { + spawned->xspr.health = getDudeInfo(actor->xspr.data1)->startHealth << 4; + spawned->xspr.burnTime = 10; + spawned->SetTarget(nullptr); + aiActivateDude(spawned); + break; + default: + break; + } + } + } + } + break; + case kMarkerEarthQuake: + actor->xspr.triggerOn = 0; + actor->xspr.isTriggered = 1; + SetSpriteState(actor, 1); + for (int p = connecthead; p >= 0; p = connectpoint2[p]) { + auto vec = actor->spr.pos - gPlayer[p].actor->spr.pos; + int dx = (vec.X) >> 4; + int dy = (vec.Y) >> 4; + int dz = (vec.Z) >> 8; + int nDist = dx * dx + dy * dy + dz * dz + 0x40000; + gPlayer[p].quakeEffect = DivScale(actor->xspr.data1, nDist, 16); + } + break; + case kThingTNTBarrel: + if (actor->spr.flags & kHitagRespawn) return; + [[fallthrough]]; + case kThingArmedTNTStick: + case kThingArmedTNTBundle: + case kThingArmedSpray: + actExplodeSprite(actor); + break; + case kTrapExploder: + switch (event.cmd) { + case kCmdOn: + SetSpriteState(actor, 1); + break; + default: + actor->spr.cstat &= ~CSTAT_SPRITE_INVISIBLE; + actExplodeSprite(actor); + break; + } + break; + case kThingArmedRemoteBomb: + if (actor->spr.statnum != kStatRespawn) { + if (event.cmd != kCmdOn) actExplodeSprite(actor); + else { + sfxPlay3DSound(actor, 454, 0, 0); + evPostActor(actor, 18, kCmdOff); + } + } + break; + case kThingArmedProxBomb: + if (actor->spr.statnum != kStatRespawn) { + switch (event.cmd) { + case kCmdSpriteProximity: + if (actor->xspr.state) break; + sfxPlay3DSound(actor, 452, 0, 0); + evPostActor(actor, 30, kCmdOff); + actor->xspr.state = 1; + [[fallthrough]]; + case kCmdOn: + sfxPlay3DSound(actor, 451, 0, 0); + actor->xspr.Proximity = 1; + break; + default: + actExplodeSprite(actor); + break; + } + } + break; + case kThingDroppedLifeLeech: + LifeLeechOperate(actor, event); + break; + case kGenTrigger: + case kGenDripWater: + case kGenDripBlood: + case kGenMissileFireball: + case kGenMissileEctoSkull: + case kGenDart: + case kGenBubble: + case kGenBubbleMulti: + case kGenSound: + switch (event.cmd) { + case kCmdOff: + SetSpriteState(actor, 0); + break; + case kCmdRepeat: + if (actor->spr.type != kGenTrigger) ActivateGenerator(actor); + if (actor->xspr.txID) evSendActor(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + if (actor->xspr.busyTime > 0) { + int nRand = Random2(actor->xspr.data1); + evPostActor(actor, 120 * (nRand + actor->xspr.busyTime) / 10, kCmdRepeat); + } + break; + default: + if (!actor->xspr.state) { + SetSpriteState(actor, 1); + evPostActor(actor, 0, kCmdRepeat); + } + break; + } + break; + case kSoundPlayer: + if (gGameOptions.nGameType == 0) + { + if (gMe->actor->xspr.health <= 0) + break; + gMe->restTime = 0; + } + sndStartSample(actor->xspr.data1, -1, 1, 0, CHANF_FORCE); + break; + case kThingObjectGib: + case kThingObjectExplode: + case kThingBloodBits: + case kThingBloodChunks: + case kThingZombieHead: + switch (event.cmd) { + case kCmdOff: + if (!SetSpriteState(actor, 0)) break; + actActivateGibObject(actor); + break; + case kCmdOn: + if (!SetSpriteState(actor, 1)) break; + actActivateGibObject(actor); + break; + default: + if (!SetSpriteState(actor, actor->xspr.state ^ 1)) break; + actActivateGibObject(actor); + break; + } + break; + default: + switch (event.cmd) { + case kCmdOff: + SetSpriteState(actor, 0); + break; + case kCmdOn: + SetSpriteState(actor, 1); + break; + default: + SetSpriteState(actor, actor->xspr.state ^ 1); + break; + } + break; + } } -void SetupGibWallState(walltype *pWall, XWALL *pXWall) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void SetupGibWallState(walltype* pWall, XWALL* pXWall) { - walltype *pWall2 = NULL; - if (pWall->twoSided()) - pWall2 = pWall->nextWall(); - if (pXWall->state) - { - pWall->cstat &= ~(CSTAT_WALL_BLOCK | CSTAT_WALL_BLOCK_HITSCAN); - if (pWall2) - { - pWall2->cstat &= ~(CSTAT_WALL_BLOCK | CSTAT_WALL_BLOCK_HITSCAN); - pWall->cstat &= ~CSTAT_WALL_MASKED; - pWall2->cstat &= ~CSTAT_WALL_MASKED; - } - return; - } - bool bVector = pXWall->triggerVector != 0; - pWall->cstat |= CSTAT_WALL_BLOCK; - if (bVector) - pWall->cstat |= CSTAT_WALL_BLOCK_HITSCAN; - if (pWall2) - { - pWall2->cstat |= CSTAT_WALL_BLOCK; - if (bVector) - pWall2->cstat |= CSTAT_WALL_BLOCK_HITSCAN; - pWall->cstat |= CSTAT_WALL_MASKED; - pWall2->cstat |= CSTAT_WALL_MASKED; - } + walltype* pWall2 = NULL; + if (pWall->twoSided()) + pWall2 = pWall->nextWall(); + if (pXWall->state) + { + pWall->cstat &= ~(CSTAT_WALL_BLOCK | CSTAT_WALL_BLOCK_HITSCAN); + if (pWall2) + { + pWall2->cstat &= ~(CSTAT_WALL_BLOCK | CSTAT_WALL_BLOCK_HITSCAN); + pWall->cstat &= ~CSTAT_WALL_MASKED; + pWall2->cstat &= ~CSTAT_WALL_MASKED; + } + return; + } + bool bVector = pXWall->triggerVector != 0; + pWall->cstat |= CSTAT_WALL_BLOCK; + if (bVector) + pWall->cstat |= CSTAT_WALL_BLOCK_HITSCAN; + if (pWall2) + { + pWall2->cstat |= CSTAT_WALL_BLOCK; + if (bVector) + pWall2->cstat |= CSTAT_WALL_BLOCK_HITSCAN; + pWall->cstat |= CSTAT_WALL_MASKED; + pWall2->cstat |= CSTAT_WALL_MASKED; + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void OperateWall(walltype* pWall, EVENT event) { - auto pXWall = &pWall->xw(); - - switch (event.cmd) { - case kCmdLock: - pXWall->locked = 1; - return; - case kCmdUnlock: - pXWall->locked = 0; - return; - case kCmdToggleLock: - pXWall->locked ^= 1; - return; - } - - #ifdef NOONE_EXTENSIONS - if (gModernMap && modernTypeOperateWall(pWall, event)) - return; - #endif + auto pXWall = &pWall->xw(); - switch (pWall->type) { - case kWallGib: - bool bStatus; - switch (event.cmd) { - case kCmdOn: - case kCmdWallImpact: - bStatus = SetWallState(pWall, 1); - break; - case kCmdOff: - bStatus = SetWallState(pWall, 0); - break; - default: - bStatus = SetWallState(pWall, pXWall->state ^ 1); - break; - } + switch (event.cmd) { + case kCmdLock: + pXWall->locked = 1; + return; + case kCmdUnlock: + pXWall->locked = 0; + return; + case kCmdToggleLock: + pXWall->locked ^= 1; + return; + } - if (bStatus) { - SetupGibWallState(pWall, pXWall); - if (pXWall->state) { - CGibVelocity vel(100, 100, 250); - int nType = ClipRange(pXWall->data, 0, 31); - if (nType > 0) - GibWall(pWall, (GIBTYPE)nType, &vel); - } - } - return; - default: - switch (event.cmd) { - case kCmdOff: - SetWallState(pWall, 0); - break; - case kCmdOn: - SetWallState(pWall, 1); - break; - default: - SetWallState(pWall, pXWall->state ^ 1); - break; - } - return; - } +#ifdef NOONE_EXTENSIONS + if (gModernMap && modernTypeOperateWall(pWall, event)) + return; +#endif + + switch (pWall->type) { + case kWallGib: + bool bStatus; + switch (event.cmd) { + case kCmdOn: + case kCmdWallImpact: + bStatus = SetWallState(pWall, 1); + break; + case kCmdOff: + bStatus = SetWallState(pWall, 0); + break; + default: + bStatus = SetWallState(pWall, pXWall->state ^ 1); + break; + } + + if (bStatus) { + SetupGibWallState(pWall, pXWall); + if (pXWall->state) { + CGibVelocity vel(100, 100, 250); + int nType = ClipRange(pXWall->data, 0, 31); + if (nType > 0) + GibWall(pWall, (GIBTYPE)nType, &vel); + } + } + return; + default: + switch (event.cmd) { + case kCmdOff: + SetWallState(pWall, 0); + break; + case kCmdOn: + SetWallState(pWall, 1); + break; + default: + SetWallState(pWall, pXWall->state ^ 1); + break; + } + return; + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void SectorStartSound(sectortype* pSector, int nState) { - BloodSectIterator it(pSector); - while (auto actor = it.Next()) - { - if (actor->spr.statnum == kStatDecoration && actor->spr.type == kSoundSector && actor->hasX()) - { - if (nState) - { - if (actor->xspr.data3) - sfxPlay3DSound(actor, actor->xspr.data3, 0, 0); - } - else - { - if (actor->xspr.data1) - sfxPlay3DSound(actor, actor->xspr.data1, 0, 0); - } - } - } + BloodSectIterator it(pSector); + while (auto actor = it.Next()) + { + if (actor->spr.statnum == kStatDecoration && actor->spr.type == kSoundSector && actor->hasX()) + { + if (nState) + { + if (actor->xspr.data3) + sfxPlay3DSound(actor, actor->xspr.data3, 0, 0); + } + else + { + if (actor->xspr.data1) + sfxPlay3DSound(actor, actor->xspr.data1, 0, 0); + } + } + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void SectorEndSound(sectortype* pSector, int nState) { - BloodSectIterator it(pSector); - while (auto actor = it.Next()) - { - if (actor->spr.statnum == kStatDecoration && actor->spr.type == kSoundSector && actor->hasX()) - { - if (nState) - { - if (actor->xspr.data2) - sfxPlay3DSound(actor, actor->xspr.data2, 0, 0); - } - else - { - if (actor->xspr.data4) - sfxPlay3DSound(actor, actor->xspr.data4, 0, 0); - } - } - } + BloodSectIterator it(pSector); + while (auto actor = it.Next()) + { + if (actor->spr.statnum == kStatDecoration && actor->spr.type == kSoundSector && actor->hasX()) + { + if (nState) + { + if (actor->xspr.data2) + sfxPlay3DSound(actor, actor->xspr.data2, 0, 0); + } + else + { + if (actor->xspr.data4) + sfxPlay3DSound(actor, actor->xspr.data4, 0, 0); + } + } + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void PathSound(sectortype* pSector, int nSound) { - BloodSectIterator it(pSector); - while (auto actor = it.Next()) - { - if (actor->spr.statnum == kStatDecoration && actor->spr.type == kSoundSector) - sfxPlay3DSound(actor, nSound, 0, 0); - } + BloodSectIterator it(pSector); + while (auto actor = it.Next()) + { + if (actor->spr.statnum == kStatDecoration && actor->spr.type == kSoundSector) + sfxPlay3DSound(actor, nSound, 0, 0); + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void DragPoint(walltype* pWall, int x, int y) { - vertexscan(pWall, [&](walltype* wal) - { - viewInterpolateWall(wal); - wal->move(x, y); - }); + vertexscan(pWall, [&](walltype* wal) + { + viewInterpolateWall(wal); + wal->move(x, y); + }); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void TranslateSector(sectortype* pSector, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11, char a12) { - int x, y; - XSECTOR *pXSector = &pSector->xs(); - int v20 = interpolatedvalue(a6, a9, a2); - int vc = interpolatedvalue(a6, a9, a3); - int v28 = vc - v20; - int v24 = interpolatedvalue(a7, a10, a2); - int v8 = interpolatedvalue(a7, a10, a3); - int v2c = v8 - v24; - int v44 = interpolatedvalue(a8, a11, a2); - int vbp = interpolatedvalue(a8, a11, a3); - int v14 = vbp - v44; - if (a12) - { - for (auto& wal : wallsofsector(pSector)) - { - x = wal.baseWall.X; - y = wal.baseWall.Y; - if (vbp) - RotatePoint((int*)&x, (int*)&y, vbp, a4, a5); - DragPoint(&wal, x+vc-a4, y+v8-a5); - } - } - else - { - for (auto& wal : wallsofsector(pSector)) - { - auto p2Wall = wal.point2Wall(); - x = wal.baseWall.X; - y = wal.baseWall.Y; - if (wal.cstat & CSTAT_WALL_MOVE_FORWARD) - { - if (vbp) - RotatePoint((int*)&x, (int*)&y, vbp, a4, a5); - DragPoint(&wal, x+vc-a4, y+v8-a5); - if ((p2Wall->cstat & CSTAT_WALL_MOVE_MASK) == 0) - { - x = p2Wall->baseWall.X; - y = p2Wall->baseWall.Y; - if (vbp) - RotatePoint((int*)&x, (int*)&y, vbp, a4, a5); - DragPoint(p2Wall, x+vc-a4, y+v8-a5); - } - continue; - } - if (wal.cstat & CSTAT_WALL_MOVE_BACKWARD) - { - if (vbp) - RotatePoint((int*)&x, (int*)&y, -vbp, a4, a5); - DragPoint(&wal, x-(vc-a4), y-(v8-a5)); - if ((p2Wall->cstat & CSTAT_WALL_MOVE_MASK) == 0) - { - x = p2Wall->baseWall.X; - y = p2Wall->baseWall.Y; - if (vbp) - RotatePoint((int*)&x, (int*)&y, -vbp, a4, a5); - DragPoint(p2Wall, x-(vc-a4), y-(v8-a5)); - } - continue; - } - } - } - BloodSectIterator it(pSector); - while (auto actor = it.Next()) - { - // allow to move markers by sector movements in game if flags 1 is added in editor. - switch (actor->spr.statnum) { - case kStatMarker: - case kStatPathMarker: - #ifdef NOONE_EXTENSIONS - if (!gModernMap || !(actor->spr.flags & 0x1)) continue; - #else - continue; - #endif - break; - } + int x, y; + XSECTOR* pXSector = &pSector->xs(); + int v20 = interpolatedvalue(a6, a9, a2); + int vc = interpolatedvalue(a6, a9, a3); + int v28 = vc - v20; + int v24 = interpolatedvalue(a7, a10, a2); + int v8 = interpolatedvalue(a7, a10, a3); + int v2c = v8 - v24; + int v44 = interpolatedvalue(a8, a11, a2); + int vbp = interpolatedvalue(a8, a11, a3); + int v14 = vbp - v44; + if (a12) + { + for (auto& wal : wallsofsector(pSector)) + { + x = wal.baseWall.X; + y = wal.baseWall.Y; + if (vbp) + RotatePoint((int*)&x, (int*)&y, vbp, a4, a5); + DragPoint(&wal, x + vc - a4, y + v8 - a5); + } + } + else + { + for (auto& wal : wallsofsector(pSector)) + { + auto p2Wall = wal.point2Wall(); + x = wal.baseWall.X; + y = wal.baseWall.Y; + if (wal.cstat & CSTAT_WALL_MOVE_FORWARD) + { + if (vbp) + RotatePoint((int*)&x, (int*)&y, vbp, a4, a5); + DragPoint(&wal, x + vc - a4, y + v8 - a5); + if ((p2Wall->cstat & CSTAT_WALL_MOVE_MASK) == 0) + { + x = p2Wall->baseWall.X; + y = p2Wall->baseWall.Y; + if (vbp) + RotatePoint((int*)&x, (int*)&y, vbp, a4, a5); + DragPoint(p2Wall, x + vc - a4, y + v8 - a5); + } + continue; + } + if (wal.cstat & CSTAT_WALL_MOVE_BACKWARD) + { + if (vbp) + RotatePoint((int*)&x, (int*)&y, -vbp, a4, a5); + DragPoint(&wal, x - (vc - a4), y - (v8 - a5)); + if ((p2Wall->cstat & CSTAT_WALL_MOVE_MASK) == 0) + { + x = p2Wall->baseWall.X; + y = p2Wall->baseWall.Y; + if (vbp) + RotatePoint((int*)&x, (int*)&y, -vbp, a4, a5); + DragPoint(p2Wall, x - (vc - a4), y - (v8 - a5)); + } + continue; + } + } + } + BloodSectIterator it(pSector); + while (auto actor = it.Next()) + { + // allow to move markers by sector movements in game if flags 1 is added in editor. + switch (actor->spr.statnum) { + case kStatMarker: + case kStatPathMarker: +#ifdef NOONE_EXTENSIONS + if (!gModernMap || !(actor->spr.flags & 0x1)) continue; +#else + continue; +#endif + break; + } - x = actor->basePoint.X; - y = actor->basePoint.Y; - if (actor->spr.cstat & CSTAT_SPRITE_MOVE_FORWARD) - { - if (vbp) - RotatePoint((int*)&x, (int*)&y, vbp, a4, a5); - viewBackupSpriteLoc(actor); - actor->spr.ang = (actor->spr.ang+v14)&2047; - actor->spr.pos.X = x+vc-a4; - actor->spr.pos.Y = y+v8-a5; - } - else if (actor->spr.cstat & CSTAT_SPRITE_MOVE_REVERSE) - { - if (vbp) - RotatePoint((int*)& x, (int*)& y, -vbp, a4, a4); - viewBackupSpriteLoc(actor); - actor->spr.ang = (actor->spr.ang-v14)&2047; - actor->spr.pos.X = x-(vc-a4); - actor->spr.pos.Y = y-(v8-a5); - } - else if (pXSector->Drag) - { - int top, bottom; - GetActorExtents(actor, &top, &bottom); - int floorZ = getflorzofslopeptr(pSector, actor->spr.pos.X, actor->spr.pos.Y); - if (!(actor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_MASK) && floorZ <= bottom) - { - if (v14) - RotatePoint((int*)&actor->spr.pos.X, (int*)&actor->spr.pos.Y, v14, v20, v24); - viewBackupSpriteLoc(actor); - actor->spr.ang = (actor->spr.ang+v14)&2047; - actor->spr.pos.X += v28; - actor->spr.pos.Y += v2c; - } - } - } + x = actor->basePoint.X; + y = actor->basePoint.Y; + if (actor->spr.cstat & CSTAT_SPRITE_MOVE_FORWARD) + { + if (vbp) + RotatePoint((int*)&x, (int*)&y, vbp, a4, a5); + viewBackupSpriteLoc(actor); + actor->spr.ang = (actor->spr.ang + v14) & 2047; + actor->spr.pos.X = x + vc - a4; + actor->spr.pos.Y = y + v8 - a5; + } + else if (actor->spr.cstat & CSTAT_SPRITE_MOVE_REVERSE) + { + if (vbp) + RotatePoint((int*)&x, (int*)&y, -vbp, a4, a4); + viewBackupSpriteLoc(actor); + actor->spr.ang = (actor->spr.ang - v14) & 2047; + actor->spr.pos.X = x - (vc - a4); + actor->spr.pos.Y = y - (v8 - a5); + } + else if (pXSector->Drag) + { + int top, bottom; + GetActorExtents(actor, &top, &bottom); + int floorZ = getflorzofslopeptr(pSector, actor->spr.pos.X, actor->spr.pos.Y); + if (!(actor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_MASK) && floorZ <= bottom) + { + if (v14) + RotatePoint((int*)&actor->spr.pos.X, (int*)&actor->spr.pos.Y, v14, v20, v24); + viewBackupSpriteLoc(actor); + actor->spr.ang = (actor->spr.ang + v14) & 2047; + actor->spr.pos.X += v28; + actor->spr.pos.Y += v2c; + } + } + } } -void ZTranslateSector(sectortype* pSector, XSECTOR *pXSector, int a3, int a4) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void ZTranslateSector(sectortype* pSector, XSECTOR* pXSector, int a3, int a4) { - viewInterpolateSector(pSector); - int dz = pXSector->onFloorZ-pXSector->offFloorZ; - if (dz != 0) - { - int oldZ = pSector->floorz; - pSector->setfloorz((pSector->baseFloor = pXSector->offFloorZ + MulScale(dz, GetWaveValue(a3, a4), 16))); - pSector->velFloor += (pSector->floorz-oldZ)<<8; + viewInterpolateSector(pSector); + int dz = pXSector->onFloorZ - pXSector->offFloorZ; + if (dz != 0) + { + int oldZ = pSector->floorz; + pSector->setfloorz((pSector->baseFloor = pXSector->offFloorZ + MulScale(dz, GetWaveValue(a3, a4), 16))); + pSector->velFloor += (pSector->floorz - oldZ) << 8; - BloodSectIterator it(pSector); - while (auto actor = it.Next()) - { - if (actor->spr.statnum == kStatMarker || actor->spr.statnum == kStatPathMarker) - continue; - int top, bottom; - GetActorExtents(actor, &top, &bottom); - if (actor->spr.cstat & CSTAT_SPRITE_MOVE_FORWARD) - { - viewBackupSpriteLoc(actor); - actor->spr.pos.Z += pSector->floorz-oldZ; - } - else if (actor->spr.flags&2) - actor->spr.flags |= 4; - else if (oldZ <= bottom && !(actor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_MASK)) - { - viewBackupSpriteLoc(actor); - actor->spr.pos.Z += pSector->floorz-oldZ; - } - } - } - dz = pXSector->onCeilZ-pXSector->offCeilZ; - if (dz != 0) - { - int oldZ = pSector->ceilingz; - pSector->setceilingz((pSector->baseCeil = pXSector->offCeilZ + MulScale(dz, GetWaveValue(a3, a4), 16))); - pSector->velCeil += (pSector->ceilingz-oldZ)<<8; + BloodSectIterator it(pSector); + while (auto actor = it.Next()) + { + if (actor->spr.statnum == kStatMarker || actor->spr.statnum == kStatPathMarker) + continue; + int top, bottom; + GetActorExtents(actor, &top, &bottom); + if (actor->spr.cstat & CSTAT_SPRITE_MOVE_FORWARD) + { + viewBackupSpriteLoc(actor); + actor->spr.pos.Z += pSector->floorz - oldZ; + } + else if (actor->spr.flags & 2) + actor->spr.flags |= 4; + else if (oldZ <= bottom && !(actor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_MASK)) + { + viewBackupSpriteLoc(actor); + actor->spr.pos.Z += pSector->floorz - oldZ; + } + } + } + dz = pXSector->onCeilZ - pXSector->offCeilZ; + if (dz != 0) + { + int oldZ = pSector->ceilingz; + pSector->setceilingz((pSector->baseCeil = pXSector->offCeilZ + MulScale(dz, GetWaveValue(a3, a4), 16))); + pSector->velCeil += (pSector->ceilingz - oldZ) << 8; - BloodSectIterator it(pSector); - while (auto actor = it.Next()) - { - if (actor->spr.statnum == kStatMarker || actor->spr.statnum == kStatPathMarker) - continue; - if (actor->spr.cstat & CSTAT_SPRITE_MOVE_REVERSE) - { - viewBackupSpriteLoc(actor); - actor->spr.pos.Z += pSector->ceilingz-oldZ; - } - } - } + BloodSectIterator it(pSector); + while (auto actor = it.Next()) + { + if (actor->spr.statnum == kStatMarker || actor->spr.statnum == kStatPathMarker) + continue; + if (actor->spr.cstat & CSTAT_SPRITE_MOVE_REVERSE) + { + viewBackupSpriteLoc(actor); + actor->spr.pos.Z += pSector->ceilingz - oldZ; + } + } + } } -DBloodActor* GetHighestSprite(sectortype* pSector, int nStatus, int *z) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +DBloodActor* GetHighestSprite(sectortype* pSector, int nStatus, int* z) { - *z = pSector->floorz; - DBloodActor* found = nullptr; + *z = pSector->floorz; + DBloodActor* found = nullptr; - BloodSectIterator it(pSector); - while (auto actor = it.Next()) - { - if (actor->spr.statnum == nStatus || nStatus == kStatFree) - { - int top, bottom; - GetActorExtents(actor, &top, &bottom); - if (top-actor->spr.pos.Z > *z) - { - *z = top-actor->spr.pos.Z; - found = actor; - } - } - } - return found; + BloodSectIterator it(pSector); + while (auto actor = it.Next()) + { + if (actor->spr.statnum == nStatus || nStatus == kStatFree) + { + int top, bottom; + GetActorExtents(actor, &top, &bottom); + if (top - actor->spr.pos.Z > *z) + { + *z = top - actor->spr.pos.Z; + found = actor; + } + } + } + return found; } -DBloodActor* GetCrushedSpriteExtents(sectortype* pSector, int *pzTop, int *pzBot) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +DBloodActor* GetCrushedSpriteExtents(sectortype* pSector, int* pzTop, int* pzBot) { - assert(pzTop != NULL && pzBot != NULL); - assert(pSector); - DBloodActor* found = nullptr; - int foundz = pSector->ceilingz; + assert(pzTop != NULL && pzBot != NULL); + assert(pSector); + DBloodActor* found = nullptr; + int foundz = pSector->ceilingz; - BloodSectIterator it(pSector); - while (auto actor = it.Next()) - { - if (actor->spr.statnum == kStatDude || actor->spr.statnum == kStatThing) - { - int top, bottom; - GetActorExtents(actor, &top, &bottom); - if (foundz > top) - { - foundz = top; - *pzTop = top; - *pzBot = bottom; - found = actor; - } - } - } - return found; + BloodSectIterator it(pSector); + while (auto actor = it.Next()) + { + if (actor->spr.statnum == kStatDude || actor->spr.statnum == kStatThing) + { + int top, bottom; + GetActorExtents(actor, &top, &bottom); + if (foundz > top) + { + foundz = top; + *pzTop = top; + *pzBot = bottom; + found = actor; + } + } + } + return found; } -int VCrushBusy(sectortype *pSector, unsigned int a2) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +int VCrushBusy(sectortype* pSector, unsigned int a2) { - assert(pSector && pSector->hasX()); - XSECTOR *pXSector = &pSector->xs(); - int nWave; - if (pXSector->busy < a2) - nWave = pXSector->busyWaveA; - else - nWave = pXSector->busyWaveB; - int dz1 = pXSector->onCeilZ - pXSector->offCeilZ; - int vc = pXSector->offCeilZ; - if (dz1 != 0) - vc += MulScale(dz1, GetWaveValue(a2, nWave), 16); - int dz2 = pXSector->onFloorZ - pXSector->offFloorZ; - int v10 = pXSector->offFloorZ; - if (dz2 != 0) - v10 += MulScale(dz2, GetWaveValue(a2, nWave), 16); - int v18; - if (GetHighestSprite(pSector, 6, &v18) && vc >= v18) - return 1; - viewInterpolateSector(pSector); - if (dz1 != 0) - pSector->setceilingz(vc); - if (dz2 != 0) - pSector->setfloorz(v10); - pXSector->busy = a2; - if (pXSector->command == kCmdLink && pXSector->txID) - evSendSector(pSector,pXSector->txID, kCmdLink); - if ((a2&0xffff) == 0) - { - SetSectorState(pSector, FixedToInt(a2)); - SectorEndSound(pSector, FixedToInt(a2)); - return 3; - } - return 0; + assert(pSector && pSector->hasX()); + XSECTOR* pXSector = &pSector->xs(); + int nWave; + if (pXSector->busy < a2) + nWave = pXSector->busyWaveA; + else + nWave = pXSector->busyWaveB; + int dz1 = pXSector->onCeilZ - pXSector->offCeilZ; + int vc = pXSector->offCeilZ; + if (dz1 != 0) + vc += MulScale(dz1, GetWaveValue(a2, nWave), 16); + int dz2 = pXSector->onFloorZ - pXSector->offFloorZ; + int v10 = pXSector->offFloorZ; + if (dz2 != 0) + v10 += MulScale(dz2, GetWaveValue(a2, nWave), 16); + int v18; + if (GetHighestSprite(pSector, 6, &v18) && vc >= v18) + return 1; + viewInterpolateSector(pSector); + if (dz1 != 0) + pSector->setceilingz(vc); + if (dz2 != 0) + pSector->setfloorz(v10); + pXSector->busy = a2; + if (pXSector->command == kCmdLink && pXSector->txID) + evSendSector(pSector, pXSector->txID, kCmdLink); + if ((a2 & 0xffff) == 0) + { + SetSectorState(pSector, FixedToInt(a2)); + SectorEndSound(pSector, FixedToInt(a2)); + return 3; + } + return 0; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + int VSpriteBusy(sectortype* pSector, unsigned int a2) { - assert(pSector && pSector->hasX()); - XSECTOR* pXSector = &pSector->xs(); - int nWave; - if (pXSector->busy < a2) - nWave = pXSector->busyWaveA; - else - nWave = pXSector->busyWaveB; - int dz1 = pXSector->onFloorZ - pXSector->offFloorZ; - if (dz1 != 0) - { - BloodSectIterator it(pSector); - while (auto actor = it.Next()) - { - if (actor->spr.cstat & CSTAT_SPRITE_MOVE_FORWARD) - { - viewBackupSpriteLoc(actor); - actor->spr.pos.Z = actor->basePoint.Z+MulScale(dz1, GetWaveValue(a2, nWave), 16); - } - } - } - int dz2 = pXSector->onCeilZ - pXSector->offCeilZ; - if (dz2 != 0) - { - BloodSectIterator it(pSector); - while (auto actor = it.Next()) - { - if (actor->spr.cstat & CSTAT_SPRITE_MOVE_REVERSE) - { - viewBackupSpriteLoc(actor); - actor->spr.pos.Z = actor->basePoint.Z + MulScale(dz2, GetWaveValue(a2, nWave), 16); - } - } - } - pXSector->busy = a2; - if (pXSector->command == kCmdLink && pXSector->txID) - evSendSector(pSector,pXSector->txID, kCmdLink); - if ((a2&0xffff) == 0) - { - SetSectorState(pSector, FixedToInt(a2)); - SectorEndSound(pSector, FixedToInt(a2)); - return 3; - } - return 0; + assert(pSector && pSector->hasX()); + XSECTOR* pXSector = &pSector->xs(); + int nWave; + if (pXSector->busy < a2) + nWave = pXSector->busyWaveA; + else + nWave = pXSector->busyWaveB; + int dz1 = pXSector->onFloorZ - pXSector->offFloorZ; + if (dz1 != 0) + { + BloodSectIterator it(pSector); + while (auto actor = it.Next()) + { + if (actor->spr.cstat & CSTAT_SPRITE_MOVE_FORWARD) + { + viewBackupSpriteLoc(actor); + actor->spr.pos.Z = actor->basePoint.Z + MulScale(dz1, GetWaveValue(a2, nWave), 16); + } + } + } + int dz2 = pXSector->onCeilZ - pXSector->offCeilZ; + if (dz2 != 0) + { + BloodSectIterator it(pSector); + while (auto actor = it.Next()) + { + if (actor->spr.cstat & CSTAT_SPRITE_MOVE_REVERSE) + { + viewBackupSpriteLoc(actor); + actor->spr.pos.Z = actor->basePoint.Z + MulScale(dz2, GetWaveValue(a2, nWave), 16); + } + } + } + pXSector->busy = a2; + if (pXSector->command == kCmdLink && pXSector->txID) + evSendSector(pSector, pXSector->txID, kCmdLink); + if ((a2 & 0xffff) == 0) + { + SetSectorState(pSector, FixedToInt(a2)); + SectorEndSound(pSector, FixedToInt(a2)); + return 3; + } + return 0; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + int VDoorBusy(sectortype* pSector, unsigned int a2) { - assert(pSector && pSector->hasX()); - XSECTOR *pXSector = &pSector->xs(); - int vbp; - if (pXSector->state) - vbp = 65536/ClipLow((120*pXSector->busyTimeA)/10, 1); - else - vbp = -65536/ClipLow((120*pXSector->busyTimeB)/10, 1); - int top, bottom; - auto actor = GetCrushedSpriteExtents(pSector, &top, &bottom); - if (actor && a2 > pXSector->busy) - { - assert(actor->hasX()); - if (pXSector->onCeilZ > pXSector->offCeilZ || pXSector->onFloorZ < pXSector->offFloorZ) - { - if (pXSector->interruptable) - { - if (pXSector->Crush) - { - if (actor->xspr.health <= 0) - return 2; - int nDamage; - if (pXSector->data == 0) - nDamage = 500; - else - nDamage = pXSector->data; - actDamageSprite(actor, actor, kDamageFall, nDamage<<4); - } - a2 = ClipRange(a2-(vbp/2)*4, 0, 65536); - } - else if (pXSector->Crush && actor->xspr.health > 0) - { - int nDamage; - if (pXSector->data == 0) - nDamage = 500; - else - nDamage = pXSector->data; - actDamageSprite(actor, actor, kDamageFall, nDamage<<4); - a2 = ClipRange(a2-(vbp/2)*4, 0, 65536); - } - } - } - else if (actor && a2 < pXSector->busy) - { - assert(actor->hasX()); - if (pXSector->offCeilZ > pXSector->onCeilZ || pXSector->offFloorZ < pXSector->onFloorZ) - { - if (pXSector->interruptable) - { - if (pXSector->Crush) - { - if (actor->xspr.health <= 0) - return 2; - int nDamage; - if (pXSector->data == 0) - nDamage = 500; - else - nDamage = pXSector->data; - actDamageSprite(actor, actor, kDamageFall, nDamage<<4); - } - a2 = ClipRange(a2+(vbp/2)*4, 0, 65536); - } - else if (pXSector->Crush && actor->xspr.health > 0) - { - int nDamage; - if (pXSector->data == 0) - nDamage = 500; - else - nDamage = pXSector->data; - actDamageSprite(actor, actor, kDamageFall, nDamage<<4); - a2 = ClipRange(a2+(vbp/2)*4, 0, 65536); - } - } - } - int nWave; - if (pXSector->busy < a2) - nWave = pXSector->busyWaveA; - else - nWave = pXSector->busyWaveB; - ZTranslateSector(pSector, pXSector, a2, nWave); - pXSector->busy = a2; - if (pXSector->command == kCmdLink && pXSector->txID) - evSendSector(pSector,pXSector->txID, kCmdLink); - if ((a2&0xffff) == 0) - { - SetSectorState(pSector, FixedToInt(a2)); - SectorEndSound(pSector, FixedToInt(a2)); - return 3; - } - return 0; + assert(pSector && pSector->hasX()); + XSECTOR* pXSector = &pSector->xs(); + int vbp; + if (pXSector->state) + vbp = 65536 / ClipLow((120 * pXSector->busyTimeA) / 10, 1); + else + vbp = -65536 / ClipLow((120 * pXSector->busyTimeB) / 10, 1); + int top, bottom; + auto actor = GetCrushedSpriteExtents(pSector, &top, &bottom); + if (actor && a2 > pXSector->busy) + { + assert(actor->hasX()); + if (pXSector->onCeilZ > pXSector->offCeilZ || pXSector->onFloorZ < pXSector->offFloorZ) + { + if (pXSector->interruptable) + { + if (pXSector->Crush) + { + if (actor->xspr.health <= 0) + return 2; + int nDamage; + if (pXSector->data == 0) + nDamage = 500; + else + nDamage = pXSector->data; + actDamageSprite(actor, actor, kDamageFall, nDamage << 4); + } + a2 = ClipRange(a2 - (vbp / 2) * 4, 0, 65536); + } + else if (pXSector->Crush && actor->xspr.health > 0) + { + int nDamage; + if (pXSector->data == 0) + nDamage = 500; + else + nDamage = pXSector->data; + actDamageSprite(actor, actor, kDamageFall, nDamage << 4); + a2 = ClipRange(a2 - (vbp / 2) * 4, 0, 65536); + } + } + } + else if (actor && a2 < pXSector->busy) + { + assert(actor->hasX()); + if (pXSector->offCeilZ > pXSector->onCeilZ || pXSector->offFloorZ < pXSector->onFloorZ) + { + if (pXSector->interruptable) + { + if (pXSector->Crush) + { + if (actor->xspr.health <= 0) + return 2; + int nDamage; + if (pXSector->data == 0) + nDamage = 500; + else + nDamage = pXSector->data; + actDamageSprite(actor, actor, kDamageFall, nDamage << 4); + } + a2 = ClipRange(a2 + (vbp / 2) * 4, 0, 65536); + } + else if (pXSector->Crush && actor->xspr.health > 0) + { + int nDamage; + if (pXSector->data == 0) + nDamage = 500; + else + nDamage = pXSector->data; + actDamageSprite(actor, actor, kDamageFall, nDamage << 4); + a2 = ClipRange(a2 + (vbp / 2) * 4, 0, 65536); + } + } + } + int nWave; + if (pXSector->busy < a2) + nWave = pXSector->busyWaveA; + else + nWave = pXSector->busyWaveB; + ZTranslateSector(pSector, pXSector, a2, nWave); + pXSector->busy = a2; + if (pXSector->command == kCmdLink && pXSector->txID) + evSendSector(pSector, pXSector->txID, kCmdLink); + if ((a2 & 0xffff) == 0) + { + SetSectorState(pSector, FixedToInt(a2)); + SectorEndSound(pSector, FixedToInt(a2)); + return 3; + } + return 0; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + int HDoorBusy(sectortype* pSector, unsigned int a2) { - assert(pSector && pSector->hasX()); - XSECTOR* pXSector = &pSector->xs(); - int nWave; - if (pXSector->busy < a2) - nWave = pXSector->busyWaveA; - else - nWave = pXSector->busyWaveB; - if (!pXSector->marker0 || !pXSector->marker1) return 0; - auto marker0 = pXSector->marker0; - auto marker1 = pXSector->marker1; - TranslateSector(pSector, GetWaveValue(pXSector->busy, nWave), GetWaveValue(a2, nWave), marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.ang, marker1->spr.pos.X, marker1->spr.pos.Y, marker1->spr.ang, pSector->type == kSectorSlide); - ZTranslateSector(pSector, pXSector, a2, nWave); - pXSector->busy = a2; - if (pXSector->command == kCmdLink && pXSector->txID) - evSendSector(pSector, pXSector->txID, kCmdLink); - if ((a2&0xffff) == 0) - { - SetSectorState(pSector, FixedToInt(a2)); - SectorEndSound(pSector, FixedToInt(a2)); - return 3; - } - return 0; + assert(pSector && pSector->hasX()); + XSECTOR* pXSector = &pSector->xs(); + int nWave; + if (pXSector->busy < a2) + nWave = pXSector->busyWaveA; + else + nWave = pXSector->busyWaveB; + if (!pXSector->marker0 || !pXSector->marker1) return 0; + auto marker0 = pXSector->marker0; + auto marker1 = pXSector->marker1; + TranslateSector(pSector, GetWaveValue(pXSector->busy, nWave), GetWaveValue(a2, nWave), marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.ang, marker1->spr.pos.X, marker1->spr.pos.Y, marker1->spr.ang, pSector->type == kSectorSlide); + ZTranslateSector(pSector, pXSector, a2, nWave); + pXSector->busy = a2; + if (pXSector->command == kCmdLink && pXSector->txID) + evSendSector(pSector, pXSector->txID, kCmdLink); + if ((a2 & 0xffff) == 0) + { + SetSectorState(pSector, FixedToInt(a2)); + SectorEndSound(pSector, FixedToInt(a2)); + return 3; + } + return 0; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + int RDoorBusy(sectortype* pSector, unsigned int a2) { - assert(pSector && pSector->hasX()); - XSECTOR* pXSector = &pSector->xs(); - int nWave; - if (pXSector->busy < a2) - nWave = pXSector->busyWaveA; - else - nWave = pXSector->busyWaveB; - if (!pXSector->marker0) return 0; - auto marker0 = pXSector->marker0; - TranslateSector(pSector, GetWaveValue(pXSector->busy, nWave), GetWaveValue(a2, nWave), marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.pos.X, marker0->spr.pos.Y, 0, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.ang, pSector->type == kSectorRotate); - ZTranslateSector(pSector, pXSector, a2, nWave); - pXSector->busy = a2; - if (pXSector->command == kCmdLink && pXSector->txID) - evSendSector(pSector, pXSector->txID, kCmdLink); - if ((a2&0xffff) == 0) - { - SetSectorState(pSector, FixedToInt(a2)); - SectorEndSound(pSector, FixedToInt(a2)); - return 3; - } - return 0; + assert(pSector && pSector->hasX()); + XSECTOR* pXSector = &pSector->xs(); + int nWave; + if (pXSector->busy < a2) + nWave = pXSector->busyWaveA; + else + nWave = pXSector->busyWaveB; + if (!pXSector->marker0) return 0; + auto marker0 = pXSector->marker0; + TranslateSector(pSector, GetWaveValue(pXSector->busy, nWave), GetWaveValue(a2, nWave), marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.pos.X, marker0->spr.pos.Y, 0, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.ang, pSector->type == kSectorRotate); + ZTranslateSector(pSector, pXSector, a2, nWave); + pXSector->busy = a2; + if (pXSector->command == kCmdLink && pXSector->txID) + evSendSector(pSector, pXSector->txID, kCmdLink); + if ((a2 & 0xffff) == 0) + { + SetSectorState(pSector, FixedToInt(a2)); + SectorEndSound(pSector, FixedToInt(a2)); + return 3; + } + return 0; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + int StepRotateBusy(sectortype* pSector, unsigned int a2) { - assert(pSector && pSector->hasX()); - XSECTOR* pXSector = &pSector->xs(); - if (!pXSector->marker0) return 0; - auto marker0 = pXSector->marker0; - int vbp; - if (pXSector->busy < a2) - { - vbp = pXSector->data+marker0->spr.ang; - int nWave = pXSector->busyWaveA; - TranslateSector(pSector, GetWaveValue(pXSector->busy, nWave), GetWaveValue(a2, nWave), marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.pos.X, marker0->spr.pos.Y, pXSector->data, marker0->spr.pos.X, marker0->spr.pos.Y, vbp, 1); - } - else - { - vbp = pXSector->data-marker0->spr.ang; - int nWave = pXSector->busyWaveB; - TranslateSector(pSector, GetWaveValue(pXSector->busy, nWave), GetWaveValue(a2, nWave), marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.pos.X, marker0->spr.pos.Y, vbp, marker0->spr.pos.X, marker0->spr.pos.Y, pXSector->data, 1); - } - pXSector->busy = a2; - if (pXSector->command == kCmdLink && pXSector->txID) - evSendSector(pSector, pXSector->txID, kCmdLink); - if ((a2&0xffff) == 0) - { - SetSectorState(pSector, FixedToInt(a2)); - SectorEndSound(pSector, FixedToInt(a2)); - pXSector->data = vbp&2047; - return 3; - } - return 0; + assert(pSector && pSector->hasX()); + XSECTOR* pXSector = &pSector->xs(); + if (!pXSector->marker0) return 0; + auto marker0 = pXSector->marker0; + int vbp; + if (pXSector->busy < a2) + { + vbp = pXSector->data + marker0->spr.ang; + int nWave = pXSector->busyWaveA; + TranslateSector(pSector, GetWaveValue(pXSector->busy, nWave), GetWaveValue(a2, nWave), marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.pos.X, marker0->spr.pos.Y, pXSector->data, marker0->spr.pos.X, marker0->spr.pos.Y, vbp, 1); + } + else + { + vbp = pXSector->data - marker0->spr.ang; + int nWave = pXSector->busyWaveB; + TranslateSector(pSector, GetWaveValue(pXSector->busy, nWave), GetWaveValue(a2, nWave), marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.pos.X, marker0->spr.pos.Y, vbp, marker0->spr.pos.X, marker0->spr.pos.Y, pXSector->data, 1); + } + pXSector->busy = a2; + if (pXSector->command == kCmdLink && pXSector->txID) + evSendSector(pSector, pXSector->txID, kCmdLink); + if ((a2 & 0xffff) == 0) + { + SetSectorState(pSector, FixedToInt(a2)); + SectorEndSound(pSector, FixedToInt(a2)); + pXSector->data = vbp & 2047; + return 3; + } + return 0; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + int GenSectorBusy(sectortype* pSector, unsigned int a2) { - assert(pSector && pSector->hasX()); - XSECTOR* pXSector = &pSector->xs(); - pXSector->busy = a2; - if (pXSector->command == kCmdLink && pXSector->txID) - evSendSector(pSector, pXSector->txID, kCmdLink); - if ((a2&0xffff) == 0) - { - SetSectorState(pSector, FixedToInt(a2)); - SectorEndSound(pSector, FixedToInt(a2)); - return 3; - } - return 0; + assert(pSector && pSector->hasX()); + XSECTOR* pXSector = &pSector->xs(); + pXSector->busy = a2; + if (pXSector->command == kCmdLink && pXSector->txID) + evSendSector(pSector, pXSector->txID, kCmdLink); + if ((a2 & 0xffff) == 0) + { + SetSectorState(pSector, FixedToInt(a2)); + SectorEndSound(pSector, FixedToInt(a2)); + return 3; + } + return 0; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + int PathBusy(sectortype* pSector, unsigned int a2) { - assert(pSector && pSector->hasX()); - XSECTOR* pXSector = &pSector->xs(); + assert(pSector && pSector->hasX()); + XSECTOR* pXSector = &pSector->xs(); - auto basepath = pXSector->basePath; - auto marker0 = pXSector->marker0; - auto marker1 = pXSector->marker1; - if (!basepath || !marker0 || !marker1) return 0; + auto basepath = pXSector->basePath; + auto marker0 = pXSector->marker0; + auto marker1 = pXSector->marker1; + if (!basepath || !marker0 || !marker1) return 0; - int nWave = marker0->xspr.wave; - TranslateSector(pSector, GetWaveValue(pXSector->busy, nWave), GetWaveValue(a2, nWave), basepath->spr.pos.X, basepath->spr.pos.Y, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.ang, marker1->spr.pos.X, marker1->spr.pos.Y, marker1->spr.ang, 1); - ZTranslateSector(pSector, pXSector, a2, nWave); - pXSector->busy = a2; - if ((a2&0xffff) == 0) - { - evPostSector(pSector, (120*marker1->xspr.waitTime)/10, kCmdOn); - pXSector->state = 0; - pXSector->busy = 0; - if (marker0->xspr.data4) - PathSound(pSector, marker0->xspr.data4); - pXSector->marker0 = marker1; - pXSector->data = marker1->xspr.data1; - return 3; - } - return 0; + int nWave = marker0->xspr.wave; + TranslateSector(pSector, GetWaveValue(pXSector->busy, nWave), GetWaveValue(a2, nWave), basepath->spr.pos.X, basepath->spr.pos.Y, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.ang, marker1->spr.pos.X, marker1->spr.pos.Y, marker1->spr.ang, 1); + ZTranslateSector(pSector, pXSector, a2, nWave); + pXSector->busy = a2; + if ((a2 & 0xffff) == 0) + { + evPostSector(pSector, (120 * marker1->xspr.waitTime) / 10, kCmdOn); + pXSector->state = 0; + pXSector->busy = 0; + if (marker0->xspr.data4) + PathSound(pSector, marker0->xspr.data4); + pXSector->marker0 = marker1; + pXSector->data = marker1->xspr.data1; + return 3; + } + return 0; } -void OperateDoor(sectortype* pSector, EVENT event, BUSYID busyWave) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void OperateDoor(sectortype* pSector, EVENT event, BUSYID busyWave) { - auto pXSector = &pSector->xs(); - switch (event.cmd) { - case kCmdOff: - if (!pXSector->busy) break; - AddBusy(pSector, busyWave, -65536/ClipLow((pXSector->busyTimeB*120)/10, 1)); - SectorStartSound(pSector, 1); - break; - case kCmdOn: - if (pXSector->busy == 0x10000) break; - AddBusy(pSector, busyWave, 65536/ClipLow((pXSector->busyTimeA*120)/10, 1)); - SectorStartSound(pSector, 0); - break; - default: - if (pXSector->busy & 0xffff) { - if (pXSector->interruptable) { - ReverseBusy(pSector, busyWave); - pXSector->state = !pXSector->state; - } - } else { - char t = !pXSector->state; int nDelta; - - if (t) nDelta = 65536/ClipLow((pXSector->busyTimeA*120)/10, 1); - else nDelta = -65536/ClipLow((pXSector->busyTimeB*120)/10, 1); - - AddBusy(pSector, busyWave, nDelta); - SectorStartSound(pSector, pXSector->state); - } - break; - } + auto pXSector = &pSector->xs(); + switch (event.cmd) { + case kCmdOff: + if (!pXSector->busy) break; + AddBusy(pSector, busyWave, -65536 / ClipLow((pXSector->busyTimeB * 120) / 10, 1)); + SectorStartSound(pSector, 1); + break; + case kCmdOn: + if (pXSector->busy == 0x10000) break; + AddBusy(pSector, busyWave, 65536 / ClipLow((pXSector->busyTimeA * 120) / 10, 1)); + SectorStartSound(pSector, 0); + break; + default: + if (pXSector->busy & 0xffff) { + if (pXSector->interruptable) { + ReverseBusy(pSector, busyWave); + pXSector->state = !pXSector->state; + } + } + else { + char t = !pXSector->state; int nDelta; + + if (t) nDelta = 65536 / ClipLow((pXSector->busyTimeA * 120) / 10, 1); + else nDelta = -65536 / ClipLow((pXSector->busyTimeB * 120) / 10, 1); + + AddBusy(pSector, busyWave, nDelta); + SectorStartSound(pSector, pXSector->state); + } + break; + } } -bool SectorContainsDudes(sectortype * pSector) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +bool SectorContainsDudes(sectortype* pSector) { - BloodSectIterator it(pSector); - while (auto actor = it.Next()) - { - if (actor->spr.statnum == kStatDude) - return 1; - } - return 0; + BloodSectIterator it(pSector); + while (auto actor = it.Next()) + { + if (actor->spr.statnum == kStatDude) + return 1; + } + return 0; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void TeleFrag(DBloodActor* killer, sectortype* pSector) { - BloodSectIterator it(pSector); - while (auto victim = it.Next()) - { - if (victim->spr.statnum == kStatDude) - actDamageSprite(killer, victim, kDamageExplode, 4000); - else if (victim->spr.statnum == kStatThing) - actDamageSprite(killer, victim, kDamageExplode, 4000); - } + BloodSectIterator it(pSector); + while (auto victim = it.Next()) + { + if (victim->spr.statnum == kStatDude) + actDamageSprite(killer, victim, kDamageExplode, 4000); + else if (victim->spr.statnum == kStatThing) + actDamageSprite(killer, victim, kDamageExplode, 4000); + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void OperateTeleport(sectortype* pSector) { - assert(pSector); - auto pXSector = &pSector->xs(); - auto destactor = pXSector->marker0; - assert(destactor != nullptr); - assert(destactor->spr.statnum == kStatMarker); - assert(destactor->spr.type == kMarkerWarpDest); - assert(destactor->spr.insector()); - BloodSectIterator it(pSector); - while (auto actor = it.Next()) - { - if (actor->spr.statnum == kStatDude) - { - PLAYER *pPlayer; - char bPlayer = actor->IsPlayerActor(); - if (bPlayer) - pPlayer = &gPlayer[actor->spr.type-kDudePlayer1]; - else - pPlayer = NULL; - if (bPlayer || !SectorContainsDudes(destactor->spr.sector())) - { - if (!(gGameOptions.uNetGameFlags & 2)) - { - TeleFrag(pXSector->actordata, destactor->spr.sector()); - } - actor->spr.pos.X = destactor->spr.pos.X; - actor->spr.pos.Y = destactor->spr.pos.Y; - actor->spr.pos.Z += destactor->spr.sector()->floorz - pSector->floorz; - actor->spr.ang = destactor->spr.ang; - ChangeActorSect(actor, destactor->spr.sector()); - sfxPlay3DSound(destactor, 201, -1, 0); - actor->xvel = actor->yvel = actor->zvel = 0; - actor->interpolated = false; - viewBackupSpriteLoc(actor); - if (pPlayer) - { - playerResetInertia(pPlayer); - pPlayer->zViewVel = pPlayer->zWeaponVel = 0; - pPlayer->angle.settarget(actor->spr.ang, true); - } - } - } - } + assert(pSector); + auto pXSector = &pSector->xs(); + auto destactor = pXSector->marker0; + assert(destactor != nullptr); + assert(destactor->spr.statnum == kStatMarker); + assert(destactor->spr.type == kMarkerWarpDest); + assert(destactor->spr.insector()); + BloodSectIterator it(pSector); + while (auto actor = it.Next()) + { + if (actor->spr.statnum == kStatDude) + { + PLAYER* pPlayer; + char bPlayer = actor->IsPlayerActor(); + if (bPlayer) + pPlayer = &gPlayer[actor->spr.type - kDudePlayer1]; + else + pPlayer = NULL; + if (bPlayer || !SectorContainsDudes(destactor->spr.sector())) + { + if (!(gGameOptions.uNetGameFlags & 2)) + { + TeleFrag(pXSector->actordata, destactor->spr.sector()); + } + actor->spr.pos.X = destactor->spr.pos.X; + actor->spr.pos.Y = destactor->spr.pos.Y; + actor->spr.pos.Z += destactor->spr.sector()->floorz - pSector->floorz; + actor->spr.ang = destactor->spr.ang; + ChangeActorSect(actor, destactor->spr.sector()); + sfxPlay3DSound(destactor, 201, -1, 0); + actor->xvel = actor->yvel = actor->zvel = 0; + actor->interpolated = false; + viewBackupSpriteLoc(actor); + if (pPlayer) + { + playerResetInertia(pPlayer); + pPlayer->zViewVel = pPlayer->zWeaponVel = 0; + pPlayer->angle.settarget(actor->spr.ang, true); + } + } + } + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void OperatePath(sectortype* pSector, EVENT event) { - DBloodActor* actor; - assert(pSector); - auto pXSector = &pSector->xs(); - if (!pXSector->marker0) return; - auto marker0 = pXSector->marker0; - auto marker1 = pXSector->marker1; - int nId = marker1->xspr.data2; - - BloodStatIterator it(kStatPathMarker); - while ((actor = it.Next())) - { - if (actor->spr.type == kMarkerPath) - { - if (actor->xspr.data1 == nId) - break; - } - } + DBloodActor* actor; + assert(pSector); + auto pXSector = &pSector->xs(); + if (!pXSector->marker0) return; + auto marker0 = pXSector->marker0; + auto marker1 = pXSector->marker1; + int nId = marker1->xspr.data2; - // trigger marker after it gets reached - #ifdef NOONE_EXTENSIONS - if (gModernMap && marker1->xspr.state != 1) - trTriggerSprite(pXSector->marker0, kCmdOn); - #endif + BloodStatIterator it(kStatPathMarker); + while ((actor = it.Next())) + { + if (actor->spr.type == kMarkerPath) + { + if (actor->xspr.data1 == nId) + break; + } + } - if (actor == nullptr) { - viewSetSystemMessage("Unable to find path marker with id #%d for path sector", nId); - pXSector->state = 0; - pXSector->busy = 0; - return; - } - - pXSector->marker1 = actor; - pXSector->offFloorZ = marker0->spr.pos.Z; - pXSector->onFloorZ = actor->spr.pos.Z; - switch (event.cmd) { - case kCmdOn: - pXSector->state = 0; - pXSector->busy = 0; - AddBusy(pSector, BUSYID_7, 65536/ClipLow((120*marker1->xspr.busyTime)/10,1)); - if (marker1->xspr.data3) PathSound(pSector, marker1->xspr.data3); - break; - } + // trigger marker after it gets reached +#ifdef NOONE_EXTENSIONS + if (gModernMap && marker1->xspr.state != 1) + trTriggerSprite(pXSector->marker0, kCmdOn); +#endif + + if (actor == nullptr) { + viewSetSystemMessage("Unable to find path marker with id #%d for path sector", nId); + pXSector->state = 0; + pXSector->busy = 0; + return; + } + + pXSector->marker1 = actor; + pXSector->offFloorZ = marker0->spr.pos.Z; + pXSector->onFloorZ = actor->spr.pos.Z; + switch (event.cmd) { + case kCmdOn: + pXSector->state = 0; + pXSector->busy = 0; + AddBusy(pSector, BUSYID_7, 65536 / ClipLow((120 * marker1->xspr.busyTime) / 10, 1)); + if (marker1->xspr.data3) PathSound(pSector, marker1->xspr.data3); + break; + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void OperateSector(sectortype* pSector, EVENT event) { - if (!pSector->hasX()) return; - auto pXSector = &pSector->xs(); - #ifdef NOONE_EXTENSIONS - if (gModernMap && modernTypeOperateSector(pSector, event)) - return; - #endif + if (!pSector->hasX()) return; + auto pXSector = &pSector->xs(); +#ifdef NOONE_EXTENSIONS + if (gModernMap && modernTypeOperateSector(pSector, event)) + return; +#endif - switch (event.cmd) { - case kCmdLock: - pXSector->locked = 1; - break; - case kCmdUnlock: - pXSector->locked = 0; - break; - case kCmdToggleLock: - pXSector->locked ^= 1; - break; - case kCmdStopOff: - pXSector->stopOn = 0; - pXSector->stopOff = 1; - break; - case kCmdStopOn: - pXSector->stopOn = 1; - pXSector->stopOff = 0; - break; - case kCmdStopNext: - pXSector->stopOn = 1; - pXSector->stopOff = 1; - break; - default: - #ifdef NOONE_EXTENSIONS - if (gModernMap && pXSector->unused1) break; - #endif - switch (pSector->type) { - case kSectorZMotionSprite: - OperateDoor(pSector,event, BUSYID_1); - break; - case kSectorZMotion: - OperateDoor(pSector,event, BUSYID_2); - break; - case kSectorSlideMarked: - case kSectorSlide: - OperateDoor(pSector,event, BUSYID_3); - break; - case kSectorRotateMarked: - case kSectorRotate: - OperateDoor(pSector,event, BUSYID_4); - break; - case kSectorRotateStep: - switch (event.cmd) { - case kCmdOn: - pXSector->state = 0; - pXSector->busy = 0; - AddBusy(pSector, BUSYID_5, 65536/ClipLow((120*pXSector->busyTimeA)/10, 1)); - SectorStartSound(pSector, 0); - break; - case kCmdOff: - pXSector->state = 1; - pXSector->busy = 65536; - AddBusy(pSector, BUSYID_5, -65536/ClipLow((120*pXSector->busyTimeB)/10, 1)); - SectorStartSound(pSector, 1); - break; - } - break; - case kSectorTeleport: - OperateTeleport(pSector); - break; - case kSectorPath: - OperatePath(pSector, event); - break; - default: - if (!pXSector->busyTimeA && !pXSector->busyTimeB) { - - switch (event.cmd) { - case kCmdOff: - SetSectorState(pSector, 0); - break; - case kCmdOn: - SetSectorState(pSector, 1); - break; - default: - SetSectorState(pSector, pXSector->state ^ 1); - break; - } + switch (event.cmd) { + case kCmdLock: + pXSector->locked = 1; + break; + case kCmdUnlock: + pXSector->locked = 0; + break; + case kCmdToggleLock: + pXSector->locked ^= 1; + break; + case kCmdStopOff: + pXSector->stopOn = 0; + pXSector->stopOff = 1; + break; + case kCmdStopOn: + pXSector->stopOn = 1; + pXSector->stopOff = 0; + break; + case kCmdStopNext: + pXSector->stopOn = 1; + pXSector->stopOff = 1; + break; + default: +#ifdef NOONE_EXTENSIONS + if (gModernMap && pXSector->unused1) break; +#endif + switch (pSector->type) { + case kSectorZMotionSprite: + OperateDoor(pSector, event, BUSYID_1); + break; + case kSectorZMotion: + OperateDoor(pSector, event, BUSYID_2); + break; + case kSectorSlideMarked: + case kSectorSlide: + OperateDoor(pSector, event, BUSYID_3); + break; + case kSectorRotateMarked: + case kSectorRotate: + OperateDoor(pSector, event, BUSYID_4); + break; + case kSectorRotateStep: + switch (event.cmd) { + case kCmdOn: + pXSector->state = 0; + pXSector->busy = 0; + AddBusy(pSector, BUSYID_5, 65536 / ClipLow((120 * pXSector->busyTimeA) / 10, 1)); + SectorStartSound(pSector, 0); + break; + case kCmdOff: + pXSector->state = 1; + pXSector->busy = 65536; + AddBusy(pSector, BUSYID_5, -65536 / ClipLow((120 * pXSector->busyTimeB) / 10, 1)); + SectorStartSound(pSector, 1); + break; + } + break; + case kSectorTeleport: + OperateTeleport(pSector); + break; + case kSectorPath: + OperatePath(pSector, event); + break; + default: + if (!pXSector->busyTimeA && !pXSector->busyTimeB) { - } else { - - OperateDoor(pSector,event, BUSYID_6); + switch (event.cmd) { + case kCmdOff: + SetSectorState(pSector, 0); + break; + case kCmdOn: + SetSectorState(pSector, 1); + break; + default: + SetSectorState(pSector, pXSector->state ^ 1); + break; + } - } + } + else { - break; - } - break; - } + OperateDoor(pSector, event, BUSYID_6); + + } + + break; + } + break; + } } -void InitPath(sectortype* pSector, XSECTOR *pXSector) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void InitPath(sectortype* pSector, XSECTOR* pXSector) { - DBloodActor* actor = nullptr; - assert(pSector); - int nId = pXSector->data; + DBloodActor* actor = nullptr; + assert(pSector); + int nId = pXSector->data; - BloodStatIterator it(kStatPathMarker); - while ((actor = it.Next())) - { - if (actor->spr.type == kMarkerPath && actor->hasX()) - { - if (actor->xspr.data1 == nId) - break; - } - } - - if (actor == nullptr) { - viewSetSystemMessage("Unable to find path marker with id #%d for path sector", nId); - return; - - } + BloodStatIterator it(kStatPathMarker); + while ((actor = it.Next())) + { + if (actor->spr.type == kMarkerPath && actor->hasX()) + { + if (actor->xspr.data1 == nId) + break; + } + } - pXSector->basePath = pXSector->marker0 = actor; - if (pXSector->state) - evPostSector(pSector, 0, kCmdOn); + if (actor == nullptr) { + viewSetSystemMessage("Unable to find path marker with id #%d for path sector", nId); + return; + + } + + pXSector->basePath = pXSector->marker0 = actor; + if (pXSector->state) + evPostSector(pSector, 0, kCmdOn); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void LinkSector(sectortype* pSector, EVENT event) { - auto pXSector = &pSector->xs(); - int nBusy = GetSourceBusy(event); - switch (pSector->type) { - case kSectorZMotionSprite: - VSpriteBusy(pSector, nBusy); - break; - case kSectorZMotion: - VDoorBusy(pSector, nBusy); - break; - case kSectorSlideMarked: - case kSectorSlide: - HDoorBusy(pSector, nBusy); - break; - case kSectorRotateMarked: - case kSectorRotate: - // force synchronised input here for now. - setForcedSyncInput(); - RDoorBusy(pSector, nBusy); - break; - default: - pXSector->busy = nBusy; - if ((pXSector->busy&0xffff) == 0) - SetSectorState(pSector, FixedToInt(nBusy)); - break; - } + auto pXSector = &pSector->xs(); + int nBusy = GetSourceBusy(event); + switch (pSector->type) { + case kSectorZMotionSprite: + VSpriteBusy(pSector, nBusy); + break; + case kSectorZMotion: + VDoorBusy(pSector, nBusy); + break; + case kSectorSlideMarked: + case kSectorSlide: + HDoorBusy(pSector, nBusy); + break; + case kSectorRotateMarked: + case kSectorRotate: + // force synchronised input here for now. + setForcedSyncInput(); + RDoorBusy(pSector, nBusy); + break; + default: + pXSector->busy = nBusy; + if ((pXSector->busy & 0xffff) == 0) + SetSectorState(pSector, FixedToInt(nBusy)); + break; + } } -void LinkSprite(DBloodActor* actor, EVENT event) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void LinkSprite(DBloodActor* actor, EVENT event) { - int nBusy = GetSourceBusy(event); + int nBusy = GetSourceBusy(event); - switch (actor->spr.type) { - case kSwitchCombo: - { - if (event.isActor()) - { - auto actor2 = event.getActor(); + switch (actor->spr.type) { + case kSwitchCombo: + { + if (event.isActor()) + { + auto actor2 = event.getActor(); - actor->xspr.data1 = actor2 && actor2->hasX()? actor2->xspr.data1 : 0; - if (actor->xspr.data1 == actor->xspr.data2) - SetSpriteState(actor, 1); - else - SetSpriteState(actor, 0); - } - } - break; - default: - { - actor->xspr.busy = nBusy; - if ((actor->xspr.busy & 0xffff) == 0) - SetSpriteState(actor, FixedToInt(nBusy)); - } - break; - } + actor->xspr.data1 = actor2 && actor2->hasX() ? actor2->xspr.data1 : 0; + if (actor->xspr.data1 == actor->xspr.data2) + SetSpriteState(actor, 1); + else + SetSpriteState(actor, 0); + } + } + break; + default: + { + actor->xspr.busy = nBusy; + if ((actor->xspr.busy & 0xffff) == 0) + SetSpriteState(actor, FixedToInt(nBusy)); + } + break; + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void LinkWall(walltype* pWall, EVENT& event) { - int nBusy = GetSourceBusy(event); - pWall->xw().busy = nBusy; - if ((pWall->xw().busy & 0xffff) == 0) - SetWallState(pWall, FixedToInt(nBusy)); + int nBusy = GetSourceBusy(event); + pWall->xw().busy = nBusy; + if ((pWall->xw().busy & 0xffff) == 0) + SetWallState(pWall, FixedToInt(nBusy)); } -void trTriggerSector(sectortype* pSector, int command) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void trTriggerSector(sectortype* pSector, int command) { - auto pXSector = &pSector->xs(); - if (!pXSector->locked && !pXSector->isTriggered) { - - if (pXSector->triggerOnce) - pXSector->isTriggered = 1; - - if (pXSector->decoupled && pXSector->txID > 0) - evSendSector(pSector, pXSector->txID, (COMMAND_ID)pXSector->command); - - else { - EVENT event; - event.cmd = command; - OperateSector(pSector, event); - } + auto pXSector = &pSector->xs(); + if (!pXSector->locked && !pXSector->isTriggered) { - } + if (pXSector->triggerOnce) + pXSector->isTriggered = 1; + + if (pXSector->decoupled && pXSector->txID > 0) + evSendSector(pSector, pXSector->txID, (COMMAND_ID)pXSector->command); + + else { + EVENT event; + event.cmd = command; + OperateSector(pSector, event); + } + + } } -void trTriggerWall(walltype* pWall, int command) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void trTriggerWall(walltype* pWall, int command) { - if (!pWall->hasX()) return; - auto pXWall = &pWall->xw(); - if (!pXWall->locked && !pXWall->isTriggered) { - - if (pXWall->triggerOnce) - pXWall->isTriggered = 1; - - if (pXWall->decoupled && pXWall->txID > 0) - evSendWall(pWall, pXWall->txID, (COMMAND_ID)pXWall->command); + if (!pWall->hasX()) return; + auto pXWall = &pWall->xw(); + if (!pXWall->locked && !pXWall->isTriggered) { - else { - EVENT event; - event.cmd = command; - OperateWall(pWall, event); - } + if (pXWall->triggerOnce) + pXWall->isTriggered = 1; - } + if (pXWall->decoupled && pXWall->txID > 0) + evSendWall(pWall, pXWall->txID, (COMMAND_ID)pXWall->command); + + else { + EVENT event; + event.cmd = command; + OperateWall(pWall, event); + } + + } } -void trTriggerSprite(DBloodActor* actor, int command) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void trTriggerSprite(DBloodActor* actor, int command) { - if (!actor->xspr.locked && !actor->xspr.isTriggered) { - - if (actor->xspr.triggerOnce) - actor->xspr.isTriggered = 1; + if (!actor->xspr.locked && !actor->xspr.isTriggered) { - if (actor->xspr.Decoupled && actor->xspr.txID > 0) - evSendActor(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); - - else { - EVENT event; - event.cmd = command; - OperateSprite(actor, event); - } + if (actor->xspr.triggerOnce) + actor->xspr.isTriggered = 1; - } + if (actor->xspr.Decoupled && actor->xspr.txID > 0) + evSendActor(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + + else { + EVENT event; + event.cmd = command; + OperateSprite(actor, event); + } + + } } -void trMessageSector(sectortype* pSector, EVENT event) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void trMessageSector(sectortype* pSector, EVENT event) { - if (!pSector->hasX()) return; - XSECTOR *pXSector = &pSector->xs(); - if (!pXSector->locked || event.cmd == kCmdUnlock || event.cmd == kCmdToggleLock) - { - switch (event.cmd) - { - case kCmdLink: - LinkSector(pSector, event); - break; - #ifdef NOONE_EXTENSIONS - case kCmdModernUse: - modernTypeTrigger(OBJ_SECTOR, pSector, nullptr, nullptr, event); - break; - #endif - default: - OperateSector(pSector, event); - break; - } - } + if (!pSector->hasX()) return; + XSECTOR* pXSector = &pSector->xs(); + if (!pXSector->locked || event.cmd == kCmdUnlock || event.cmd == kCmdToggleLock) + { + switch (event.cmd) + { + case kCmdLink: + LinkSector(pSector, event); + break; +#ifdef NOONE_EXTENSIONS + case kCmdModernUse: + modernTypeTrigger(OBJ_SECTOR, pSector, nullptr, nullptr, event); + break; +#endif + default: + OperateSector(pSector, event); + break; + } + } } -void trMessageWall(walltype* pWall, EVENT& event) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void trMessageWall(walltype* pWall, EVENT& event) { - assert(pWall->hasX()); - - XWALL *pXWall = &pWall->xw(); - if (!pXWall->locked || event.cmd == kCmdUnlock || event.cmd == kCmdToggleLock) - { - switch (event.cmd) { - case kCmdLink: - LinkWall(pWall, event); - break; - #ifdef NOONE_EXTENSIONS - case kCmdModernUse: - modernTypeTrigger(OBJ_WALL, nullptr, pWall, nullptr, event); - break; - #endif - default: - OperateWall(pWall, event); - break; - } - } + assert(pWall->hasX()); + + XWALL* pXWall = &pWall->xw(); + if (!pXWall->locked || event.cmd == kCmdUnlock || event.cmd == kCmdToggleLock) + { + switch (event.cmd) { + case kCmdLink: + LinkWall(pWall, event); + break; +#ifdef NOONE_EXTENSIONS + case kCmdModernUse: + modernTypeTrigger(OBJ_WALL, nullptr, pWall, nullptr, event); + break; +#endif + default: + OperateWall(pWall, event); + break; + } + } } -void trMessageSprite(DBloodActor* actor, EVENT event) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void trMessageSprite(DBloodActor* actor, EVENT event) { - if (actor->spr.statnum != kStatFree) { + if (actor->spr.statnum != kStatFree) { - if (!actor->xspr.locked || event.cmd == kCmdUnlock || event.cmd == kCmdToggleLock) - { - switch (event.cmd) - { - case kCmdLink: - LinkSprite(actor, event); - break; - #ifdef NOONE_EXTENSIONS - case kCmdModernUse: - modernTypeTrigger(OBJ_SPRITE, 0, 0, actor, event); - break; - #endif - default: - OperateSprite(actor, event); - break; - } - } - } + if (!actor->xspr.locked || event.cmd == kCmdUnlock || event.cmd == kCmdToggleLock) + { + switch (event.cmd) + { + case kCmdLink: + LinkSprite(actor, event); + break; +#ifdef NOONE_EXTENSIONS + case kCmdModernUse: + modernTypeTrigger(OBJ_SPRITE, 0, 0, actor, event); + break; +#endif + default: + OperateSprite(actor, event); + break; + } + } + } } - +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- void ProcessMotion(void) { - for(auto& sect: sector) - { - sectortype* pSector = § + for (auto& sect : sector) + { + sectortype* pSector = § - if (!pSector->hasX()) continue; - XSECTOR* pXSector = &pSector->xs(); - if (pXSector->bobSpeed != 0) - { - if (pXSector->bobAlways) - pXSector->bobTheta += pXSector->bobSpeed; - else if (pXSector->busy == 0) - continue; - else - pXSector->bobTheta += MulScale(pXSector->bobSpeed, pXSector->busy, 16); - int vdi = MulScale(Sin(pXSector->bobTheta), pXSector->bobZRange<<8, 30); + if (!pSector->hasX()) continue; + XSECTOR* pXSector = &pSector->xs(); + if (pXSector->bobSpeed != 0) + { + if (pXSector->bobAlways) + pXSector->bobTheta += pXSector->bobSpeed; + else if (pXSector->busy == 0) + continue; + else + pXSector->bobTheta += MulScale(pXSector->bobSpeed, pXSector->busy, 16); + int vdi = MulScale(Sin(pXSector->bobTheta), pXSector->bobZRange << 8, 30); - BloodSectIterator it(pSector); - while (auto actor = it.Next()) - { - if (actor->spr.cstat & CSTAT_SPRITE_MOVE_MASK) - { - viewBackupSpriteLoc(actor); - actor->spr.pos.Z += vdi; - } - } - if (pXSector->bobFloor) - { - int floorZ = pSector->floorz; - viewInterpolateSector(pSector); - pSector->setfloorz(pSector->baseFloor + vdi); + BloodSectIterator it(pSector); + while (auto actor = it.Next()) + { + if (actor->spr.cstat & CSTAT_SPRITE_MOVE_MASK) + { + viewBackupSpriteLoc(actor); + actor->spr.pos.Z += vdi; + } + } + if (pXSector->bobFloor) + { + int floorZ = pSector->floorz; + viewInterpolateSector(pSector); + pSector->setfloorz(pSector->baseFloor + vdi); - BloodSectIterator itr(pSector); - while (auto actor = itr.Next()) - { - if (actor->spr.flags&2) - actor->spr.flags |= 4; - else - { - int top, bottom; - GetActorExtents(actor, &top, &bottom); - if (bottom >= floorZ && (actor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_MASK) == 0) - { - viewBackupSpriteLoc(actor); - actor->spr.pos.Z += vdi; - } - } - } - } - if (pXSector->bobCeiling) - { - int ceilZ = pSector->ceilingz; - viewInterpolateSector(pSector); - pSector->setceilingz(pSector->baseCeil + vdi); + BloodSectIterator itr(pSector); + while (auto actor = itr.Next()) + { + if (actor->spr.flags & 2) + actor->spr.flags |= 4; + else + { + int top, bottom; + GetActorExtents(actor, &top, &bottom); + if (bottom >= floorZ && (actor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_MASK) == 0) + { + viewBackupSpriteLoc(actor); + actor->spr.pos.Z += vdi; + } + } + } + } + if (pXSector->bobCeiling) + { + int ceilZ = pSector->ceilingz; + viewInterpolateSector(pSector); + pSector->setceilingz(pSector->baseCeil + vdi); - BloodSectIterator itr(pSector); - while (auto actor = itr.Next()) - { - int top, bottom; - GetActorExtents(actor, &top, &bottom); - if (top <= ceilZ && (actor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_MASK) == 0) - { - viewBackupSpriteLoc(actor); - actor->spr.pos.Z += vdi; - } - } - } - } - } + BloodSectIterator itr(pSector); + while (auto actor = itr.Next()) + { + int top, bottom; + GetActorExtents(actor, &top, &bottom); + if (top <= ceilZ && (actor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_MASK) == 0) + { + viewBackupSpriteLoc(actor); + actor->spr.pos.Z += vdi; + } + } + } + } + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void AlignSlopes(void) { - for(auto& sect: sector) - { - if (sect.slopewallofs) - { - walltype *pWall = sect.firstWall() + sect.slopewallofs; - walltype *pWall2 = pWall->point2Wall(); - if (pWall->twoSided()) - { - auto pNextSector = pWall->nextSector(); + for (auto& sect : sector) + { + if (sect.slopewallofs) + { + walltype* pWall = sect.firstWall() + sect.slopewallofs; + walltype* pWall2 = pWall->point2Wall(); + if (pWall->twoSided()) + { + auto pNextSector = pWall->nextSector(); - int x = (pWall->pos.X+pWall2->pos.X)/2; - int y = (pWall->pos.Y+pWall2->pos.Y)/2; - viewInterpolateSector(§); - alignflorslope(§, x, y, getflorzofslopeptr(pNextSector, x, y)); - alignceilslope(§, x, y, getceilzofslopeptr(pNextSector, x, y)); - } - } - } + int x = (pWall->pos.X + pWall2->pos.X) / 2; + int y = (pWall->pos.Y + pWall2->pos.Y) / 2; + viewInterpolateSector(§); + alignflorslope(§, x, y, getflorzofslopeptr(pNextSector, x, y)); + alignceilslope(§, x, y, getceilzofslopeptr(pNextSector, x, y)); + } + } + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + int(*gBusyProc[])(sectortype*, unsigned int) = { - VCrushBusy, - VSpriteBusy, - VDoorBusy, - HDoorBusy, - RDoorBusy, - StepRotateBusy, - GenSectorBusy, - PathBusy + VCrushBusy, + VSpriteBusy, + VDoorBusy, + HDoorBusy, + RDoorBusy, + StepRotateBusy, + GenSectorBusy, + PathBusy }; void trProcessBusy(void) { - for (auto& sect: sector) - { - sect.velCeil = sect.velFloor = 0; - } - for (auto& b : backwards(gBusy)) - { - int nStatus; - int oldBusy = b.busy; - b.busy = ClipRange(oldBusy+b.delta*4, 0, 65536); - #ifdef NOONE_EXTENSIONS - if (!gModernMap || !b.sect->xs().unused1) nStatus = gBusyProc[b.type](b.sect, b.busy); - else nStatus = 3; // allow to pause/continue motion for sectors any time by sending special command - #else - nStatus = gBusyProc[b.type](b.at0, b.at8); - #endif - switch (nStatus) { - case 1: - b.busy = oldBusy; - break; - case 2: - b.busy = oldBusy; - b.delta = -b.delta; - break; - case 3: - b = gBusy.Last(); - gBusy.Pop(); - break; - } - } - ProcessMotion(); - AlignSlopes(); + for (auto& sect : sector) + { + sect.velCeil = sect.velFloor = 0; + } + for (auto& b : backwards(gBusy)) + { + int nStatus; + int oldBusy = b.busy; + b.busy = ClipRange(oldBusy + b.delta * 4, 0, 65536); +#ifdef NOONE_EXTENSIONS + if (!gModernMap || !b.sect->xs().unused1) nStatus = gBusyProc[b.type](b.sect, b.busy); + else nStatus = 3; // allow to pause/continue motion for sectors any time by sending special command +#else + nStatus = gBusyProc[b.type](b.at0, b.at8); +#endif + switch (nStatus) { + case 1: + b.busy = oldBusy; + break; + case 2: + b.busy = oldBusy; + b.delta = -b.delta; + break; + case 3: + b = gBusy.Last(); + gBusy.Pop(); + break; + } + } + ProcessMotion(); + AlignSlopes(); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void InitGenerator(DBloodActor*); void trInit(TArray& actors) { - gBusy.Clear(); - for(auto& wal : wall) - { - wal.baseWall.X = wal.pos.X; - wal.baseWall.Y = wal.pos.Y; - } - for(auto actor : actors) - { - if (!actor->exists()) continue; - actor->spr.inittype = actor->spr.type; - actor->basePoint = actor->spr.pos; - } - for(auto& wal : wall) - { - if (wal.hasX()) - { - XWALL *pXWall = &wal.xw(); - if (pXWall->state) - pXWall->busy = 65536; - } - } + gBusy.Clear(); + for (auto& wal : wall) + { + wal.baseWall.X = wal.pos.X; + wal.baseWall.Y = wal.pos.Y; + } + for (auto actor : actors) + { + if (!actor->exists()) continue; + actor->spr.inittype = actor->spr.type; + actor->basePoint = actor->spr.pos; + } + for (auto& wal : wall) + { + if (wal.hasX()) + { + XWALL* pXWall = &wal.xw(); + if (pXWall->state) + pXWall->busy = 65536; + } + } - for(auto& sect: sector) - { - sectortype *pSector = § - pSector->baseFloor = pSector->floorz; - pSector->baseCeil = pSector->ceilingz; - if (pSector->hasX()) - { - XSECTOR *pXSector = &pSector->xs(); - if (pXSector->state) - pXSector->busy = 65536; - switch (pSector->type) - { - case kSectorCounter: - #ifdef NOONE_EXTENSIONS - if (gModernMap) - pXSector->triggerOff = false; - else - #endif - pXSector->triggerOnce = 1; - evPostSector(pSector, 0, kCallbackCounterCheck); - break; - case kSectorZMotion: - case kSectorZMotionSprite: - ZTranslateSector(pSector, pXSector, pXSector->busy, 1); - break; - case kSectorSlideMarked: - case kSectorSlide: - { - auto marker0 = pXSector->marker0; - auto marker1 = pXSector->marker1; - TranslateSector(pSector, 0, -65536, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.ang, marker1->spr.pos.X, marker1->spr.pos.Y, marker1->spr.ang, pSector->type == kSectorSlide); - for(auto& wal : wallsofsector(pSector)) - { - wal.baseWall.X = wal.pos.X; - wal.baseWall.Y = wal.pos.Y; - } - BloodSectIterator it(pSector); - while (auto actor = it.Next()) - { - actor->basePoint = actor->spr.pos; - } - TranslateSector(pSector, 0, pXSector->busy, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.ang, marker1->spr.pos.X, marker1->spr.pos.Y, marker1->spr.ang, pSector->type == kSectorSlide); - ZTranslateSector(pSector, pXSector, pXSector->busy, 1); - break; - } - case kSectorRotateMarked: - case kSectorRotate: - { - auto marker0 = pXSector->marker0; - TranslateSector(pSector, 0, -65536, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.pos.X, marker0->spr.pos.Y, 0, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.ang, pSector->type == kSectorRotate); - for (auto& wal : wallsofsector(pSector)) - { - wal.baseWall.X = wal.pos.X; - wal.baseWall.Y = wal.pos.Y; - } - BloodSectIterator it(pSector); - while (auto actor = it.Next()) - { - actor->basePoint = actor->spr.pos; - } - TranslateSector(pSector, 0, pXSector->busy, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.pos.X, marker0->spr.pos.Y, 0, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.ang, pSector->type == kSectorRotate); - ZTranslateSector(pSector, pXSector, pXSector->busy, 1); - break; - } - case kSectorPath: - InitPath(pSector, pXSector); - break; - default: - break; - } - } - } + for (auto& sect : sector) + { + sectortype* pSector = § + pSector->baseFloor = pSector->floorz; + pSector->baseCeil = pSector->ceilingz; + if (pSector->hasX()) + { + XSECTOR* pXSector = &pSector->xs(); + if (pXSector->state) + pXSector->busy = 65536; + switch (pSector->type) + { + case kSectorCounter: +#ifdef NOONE_EXTENSIONS + if (gModernMap) + pXSector->triggerOff = false; + else +#endif + pXSector->triggerOnce = 1; + evPostSector(pSector, 0, kCallbackCounterCheck); + break; + case kSectorZMotion: + case kSectorZMotionSprite: + ZTranslateSector(pSector, pXSector, pXSector->busy, 1); + break; + case kSectorSlideMarked: + case kSectorSlide: + { + auto marker0 = pXSector->marker0; + auto marker1 = pXSector->marker1; + TranslateSector(pSector, 0, -65536, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.ang, marker1->spr.pos.X, marker1->spr.pos.Y, marker1->spr.ang, pSector->type == kSectorSlide); + for (auto& wal : wallsofsector(pSector)) + { + wal.baseWall.X = wal.pos.X; + wal.baseWall.Y = wal.pos.Y; + } + BloodSectIterator it(pSector); + while (auto actor = it.Next()) + { + actor->basePoint = actor->spr.pos; + } + TranslateSector(pSector, 0, pXSector->busy, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.ang, marker1->spr.pos.X, marker1->spr.pos.Y, marker1->spr.ang, pSector->type == kSectorSlide); + ZTranslateSector(pSector, pXSector, pXSector->busy, 1); + break; + } + case kSectorRotateMarked: + case kSectorRotate: + { + auto marker0 = pXSector->marker0; + TranslateSector(pSector, 0, -65536, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.pos.X, marker0->spr.pos.Y, 0, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.ang, pSector->type == kSectorRotate); + for (auto& wal : wallsofsector(pSector)) + { + wal.baseWall.X = wal.pos.X; + wal.baseWall.Y = wal.pos.Y; + } + BloodSectIterator it(pSector); + while (auto actor = it.Next()) + { + actor->basePoint = actor->spr.pos; + } + TranslateSector(pSector, 0, pXSector->busy, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.pos.X, marker0->spr.pos.Y, 0, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.ang, pSector->type == kSectorRotate); + ZTranslateSector(pSector, pXSector, pXSector->busy, 1); + break; + } + case kSectorPath: + InitPath(pSector, pXSector); + break; + default: + break; + } + } + } - for (auto actor : actors) - { - if (actor->spr.statnum < kStatFree && actor->hasX()) - { - if (actor->xspr.state) - actor->xspr.busy = 65536; - switch (actor->spr.type) { - case kSwitchPadlock: - actor->xspr.triggerOnce = 1; - break; - #ifdef NOONE_EXTENSIONS - case kModernRandom: - case kModernRandom2: + for (auto actor : actors) + { + if (actor->spr.statnum < kStatFree && actor->hasX()) + { + if (actor->xspr.state) + actor->xspr.busy = 65536; + switch (actor->spr.type) { + case kSwitchPadlock: + actor->xspr.triggerOnce = 1; + break; +#ifdef NOONE_EXTENSIONS + case kModernRandom: + case kModernRandom2: - if (!gModernMap || actor->xspr.state == actor->xspr.restState) break; - evPostActor(actor, (120 * actor->xspr.busyTime) / 10, kCmdRepeat); - if (actor->xspr.waitTime > 0) - evPostActor(actor, (actor->xspr.waitTime * 120) / 10, actor->xspr.restState ? kCmdOn : kCmdOff); - break; - case kModernSeqSpawner: - case kModernObjDataAccumulator: - case kModernDudeTargetChanger: - case kModernEffectSpawner: - case kModernWindGenerator: - if (actor->xspr.state == actor->xspr.restState) break; - evPostActor(actor, 0, kCmdRepeat); - if (actor->xspr.waitTime > 0) - evPostActor(actor, (actor->xspr.waitTime * 120) / 10, actor->xspr.restState ? kCmdOn : kCmdOff); - break; - #endif - case kGenTrigger: - case kGenDripWater: - case kGenDripBlood: - case kGenMissileFireball: - case kGenDart: - case kGenBubble: - case kGenBubbleMulti: - case kGenMissileEctoSkull: - case kGenSound: - InitGenerator(actor); - break; - case kThingArmedProxBomb: - actor->xspr.Proximity = 1; - break; - case kThingFallingRock: - if (actor->xspr.state) actor->spr.flags |= 7; - else actor->spr.flags &= ~7; - break; - } - if (actor->xspr.Vector) actor->spr.cstat |= CSTAT_SPRITE_BLOCK_HITSCAN; - if (actor->xspr.Push) actor->spr.cstat |= CSTAT_SPRITE_BLOOD_BIT1; - } - } - - evSendGame(kChannelLevelStart, kCmdOn); - switch (gGameOptions.nGameType) { - case 1: - evSendGame(kChannelLevelStartCoop, kCmdOn); - break; - case 2: - evSendGame(kChannelLevelStartMatch, kCmdOn); - break; - case 3: - evSendGame(kChannelLevelStartMatch, kCmdOn); - evSendGame(kChannelLevelStartTeamsOnly, kCmdOn); - break; - } + if (!gModernMap || actor->xspr.state == actor->xspr.restState) break; + evPostActor(actor, (120 * actor->xspr.busyTime) / 10, kCmdRepeat); + if (actor->xspr.waitTime > 0) + evPostActor(actor, (actor->xspr.waitTime * 120) / 10, actor->xspr.restState ? kCmdOn : kCmdOff); + break; + case kModernSeqSpawner: + case kModernObjDataAccumulator: + case kModernDudeTargetChanger: + case kModernEffectSpawner: + case kModernWindGenerator: + if (actor->xspr.state == actor->xspr.restState) break; + evPostActor(actor, 0, kCmdRepeat); + if (actor->xspr.waitTime > 0) + evPostActor(actor, (actor->xspr.waitTime * 120) / 10, actor->xspr.restState ? kCmdOn : kCmdOff); + break; +#endif + case kGenTrigger: + case kGenDripWater: + case kGenDripBlood: + case kGenMissileFireball: + case kGenDart: + case kGenBubble: + case kGenBubbleMulti: + case kGenMissileEctoSkull: + case kGenSound: + InitGenerator(actor); + break; + case kThingArmedProxBomb: + actor->xspr.Proximity = 1; + break; + case kThingFallingRock: + if (actor->xspr.state) actor->spr.flags |= 7; + else actor->spr.flags &= ~7; + break; + } + if (actor->xspr.Vector) actor->spr.cstat |= CSTAT_SPRITE_BLOCK_HITSCAN; + if (actor->xspr.Push) actor->spr.cstat |= CSTAT_SPRITE_BLOOD_BIT1; + } + } + + evSendGame(kChannelLevelStart, kCmdOn); + switch (gGameOptions.nGameType) { + case 1: + evSendGame(kChannelLevelStartCoop, kCmdOn); + break; + case 2: + evSendGame(kChannelLevelStartMatch, kCmdOn); + break; + case 3: + evSendGame(kChannelLevelStartMatch, kCmdOn); + evSendGame(kChannelLevelStartTeamsOnly, kCmdOn); + break; + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void trTextOver(int nId) { - const char *pzMessage = currentLevel->GetMessage(nId); - if (pzMessage) - viewSetMessage(pzMessage, VanillaMode() ? 0 : 8, MESSAGE_PRIORITY_INI); // 8: gold + const char* pzMessage = currentLevel->GetMessage(nId); + if (pzMessage) + viewSetMessage(pzMessage, VanillaMode() ? 0 : 8, MESSAGE_PRIORITY_INI); // 8: gold } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void InitGenerator(DBloodActor* actor) { - assert(actor->hasX()); - switch (actor->spr.type) { - case kGenTrigger: - actor->spr.cstat &= ~CSTAT_SPRITE_BLOCK; - actor->spr.cstat |= CSTAT_SPRITE_INVISIBLE; - break; - } - if (actor->xspr.state != actor->xspr.restState && actor->xspr.busyTime > 0) - evPostActor(actor, (120*(actor->xspr.busyTime+Random2(actor->xspr.data1)))/10, kCmdRepeat); + assert(actor->hasX()); + switch (actor->spr.type) { + case kGenTrigger: + actor->spr.cstat &= ~CSTAT_SPRITE_BLOCK; + actor->spr.cstat |= CSTAT_SPRITE_INVISIBLE; + break; + } + if (actor->xspr.state != actor->xspr.restState && actor->xspr.busyTime > 0) + evPostActor(actor, (120 * (actor->xspr.busyTime + Random2(actor->xspr.data1))) / 10, kCmdRepeat); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void ActivateGenerator(DBloodActor* actor) { - assert(actor->hasX()); - switch (actor->spr.type) { - case kGenDripWater: - case kGenDripBlood: { - int top, bottom; - GetActorExtents(actor, &top, &bottom); - actSpawnThing(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y, bottom, (actor->spr.type == kGenDripWater) ? kThingDripWater : kThingDripBlood); - break; - } - case kGenSound: - sfxPlay3DSound(actor, actor->xspr.data2, -1, 0); - break; - case kGenMissileFireball: - switch (actor->xspr.data2) { - case 0: - FireballTrapSeqCallback(3, actor); - break; - case 1: - seqSpawn(35, actor, nFireballTrapClient); - break; - case 2: - seqSpawn(36, actor, nFireballTrapClient); - break; - } - break; - case kGenMissileEctoSkull: - break; - case kGenBubble: - case kGenBubbleMulti: { - int top, bottom; - GetActorExtents(actor, &top, &bottom); - gFX.fxSpawnActor((actor->spr.type == kGenBubble) ? FX_23 : FX_26, actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y, top, 0); - break; - } - } + assert(actor->hasX()); + switch (actor->spr.type) { + case kGenDripWater: + case kGenDripBlood: { + int top, bottom; + GetActorExtents(actor, &top, &bottom); + actSpawnThing(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y, bottom, (actor->spr.type == kGenDripWater) ? kThingDripWater : kThingDripBlood); + break; + } + case kGenSound: + sfxPlay3DSound(actor, actor->xspr.data2, -1, 0); + break; + case kGenMissileFireball: + switch (actor->xspr.data2) { + case 0: + FireballTrapSeqCallback(3, actor); + break; + case 1: + seqSpawn(35, actor, nFireballTrapClient); + break; + case 2: + seqSpawn(36, actor, nFireballTrapClient); + break; + } + break; + case kGenMissileEctoSkull: + break; + case kGenBubble: + case kGenBubbleMulti: { + int top, bottom; + GetActorExtents(actor, &top, &bottom); + gFX.fxSpawnActor((actor->spr.type == kGenBubble) ? FX_23 : FX_26, actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y, top, 0); + break; + } + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void FireballTrapSeqCallback(int, DBloodActor* actor) { - if (actor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_FLOOR) - actFireMissile(actor, 0, 0, 0, 0, (actor->spr.cstat & CSTAT_SPRITE_YFLIP) ? 0x4000 : -0x4000, kMissileFireball); - else - actFireMissile(actor, 0, 0, bcos(actor->spr.ang), bsin(actor->spr.ang), 0, kMissileFireball); + if (actor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_FLOOR) + actFireMissile(actor, 0, 0, 0, 0, (actor->spr.cstat & CSTAT_SPRITE_YFLIP) ? 0x4000 : -0x4000, kMissileFireball); + else + actFireMissile(actor, 0, 0, bcos(actor->spr.ang), bsin(actor->spr.ang), 0, kMissileFireball); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void MGunFireSeqCallback(int, DBloodActor* actor) { - if (actor->xspr.data2 > 0 || actor->xspr.data1 == 0) - { - if (actor->xspr.data2 > 0) - { - actor->xspr.data2--; - if (actor->xspr.data2 == 0) - evPostActor(actor, 1, kCmdOff); - } - int dx = bcos(actor->spr.ang)+Random2(1000); - int dy = bsin(actor->spr.ang)+Random2(1000); - int dz = Random2(1000); - actFireVector(actor, 0, 0, dx, dy, dz, kVectorBullet); - sfxPlay3DSound(actor, 359, -1, 0); - } + if (actor->xspr.data2 > 0 || actor->xspr.data1 == 0) + { + if (actor->xspr.data2 > 0) + { + actor->xspr.data2--; + if (actor->xspr.data2 == 0) + evPostActor(actor, 1, kCmdOff); + } + int dx = bcos(actor->spr.ang) + Random2(1000); + int dy = bsin(actor->spr.ang) + Random2(1000); + int dz = Random2(1000); + actFireVector(actor, 0, 0, dx, dy, dz, kVectorBullet); + sfxPlay3DSound(actor, 359, -1, 0); + } } void MGunOpenSeqCallback(int, DBloodActor* actor) { - seqSpawn(39, actor, nMGunFireClient); + seqSpawn(39, actor, nMGunFireClient); } diff --git a/source/games/blood/src/triggers.h b/source/games/blood/src/triggers.h index 217eebc9d..75471edf0 100644 --- a/source/games/blood/src/triggers.h +++ b/source/games/blood/src/triggers.h @@ -32,26 +32,26 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. BEGIN_BLD_NS enum BUSYID { - BUSYID_0 = 0, - BUSYID_1, - BUSYID_2, - BUSYID_3, - BUSYID_4, - BUSYID_5, - BUSYID_6, - BUSYID_7, + BUSYID_0 = 0, + BUSYID_1, + BUSYID_2, + BUSYID_3, + BUSYID_4, + BUSYID_5, + BUSYID_6, + BUSYID_7, }; struct BUSY { - sectortype* sect; - int delta; - int busy; - int/*BUSYID*/ type; + sectortype* sect; + int delta; + int busy; + int/*BUSYID*/ type; }; extern TArray gBusy; -void trTriggerSector(sectortype *pSector, int command); +void trTriggerSector(sectortype* pSector, int command); void trMessageSector(sectortype* pSector, EVENT event); void trTriggerWall(walltype*, int command); void trMessageWall(walltype* pWall, EVENT& event); diff --git a/source/games/blood/src/view.cpp b/source/games/blood/src/view.cpp index 05fa8a2cf..1318aa9d5 100644 --- a/source/games/blood/src/view.cpp +++ b/source/games/blood/src/view.cpp @@ -56,256 +56,321 @@ double gInterpolate; int gScreenTilt; +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void viewBackupView(int nPlayer) { - PLAYER *pPlayer = &gPlayer[nPlayer]; - VIEW *pView = &gPrevView[nPlayer]; - pView->angle = pPlayer->angle.ang; - pView->x = pPlayer->actor->spr.pos.X; - pView->y = pPlayer->actor->spr.pos.Y; - pView->viewz = pPlayer->zView; - pView->weaponZ = pPlayer->zWeapon-pPlayer->zView-0xc00; - pView->horiz = pPlayer->horizon.horiz; - pView->horizoff = pPlayer->horizon.horizoff; - pView->at2c = pPlayer->slope; - pView->bobHeight = pPlayer->bobHeight; - pView->bobWidth = pPlayer->bobWidth; - pView->shakeBobY = pPlayer->swayHeight; - pView->shakeBobX = pPlayer->swayWidth; - pView->look_ang = pPlayer->angle.look_ang; - pView->rotscrnang = pPlayer->angle.rotscrnang; - pPlayer->angle.backup(); - pPlayer->horizon.backup(); + PLAYER* pPlayer = &gPlayer[nPlayer]; + VIEW* pView = &gPrevView[nPlayer]; + pView->angle = pPlayer->angle.ang; + pView->x = pPlayer->actor->spr.pos.X; + pView->y = pPlayer->actor->spr.pos.Y; + pView->viewz = pPlayer->zView; + pView->weaponZ = pPlayer->zWeapon - pPlayer->zView - 0xc00; + pView->horiz = pPlayer->horizon.horiz; + pView->horizoff = pPlayer->horizon.horizoff; + pView->at2c = pPlayer->slope; + pView->bobHeight = pPlayer->bobHeight; + pView->bobWidth = pPlayer->bobWidth; + pView->shakeBobY = pPlayer->swayHeight; + pView->shakeBobX = pPlayer->swayWidth; + pView->look_ang = pPlayer->angle.look_ang; + pView->rotscrnang = pPlayer->angle.rotscrnang; + pPlayer->angle.backup(); + pPlayer->horizon.backup(); } -void viewCorrectViewOffsets(int nPlayer, vec3_t const *oldpos) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void viewCorrectViewOffsets(int nPlayer, vec3_t const* oldpos) { - PLAYER *pPlayer = &gPlayer[nPlayer]; - VIEW *pView = &gPrevView[nPlayer]; - pView->x += pPlayer->actor->spr.pos.X-oldpos->X; - pView->y += pPlayer->actor->spr.pos.Y-oldpos->Y; - pView->viewz += pPlayer->actor->spr.pos.Z-oldpos->Z; + PLAYER* pPlayer = &gPlayer[nPlayer]; + VIEW* pView = &gPrevView[nPlayer]; + pView->x += pPlayer->actor->spr.pos.X - oldpos->X; + pView->y += pPlayer->actor->spr.pos.Y - oldpos->Y; + pView->viewz += pPlayer->actor->spr.pos.Z - oldpos->Z; } -void viewDrawText(FFont* pFont, const char *pString, int x, int y, int nShade, int nPalette, int position, bool shadow) -{ - if (!pString) return; +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- - //y += pFont->yoff; +void viewDrawText(FFont* pFont, const char* pString, int x, int y, int nShade, int nPalette, int position, bool shadow) +{ + if (!pString) return; + + //y += pFont->yoff; if (position == 1) x -= pFont->StringWidth(pString) / 2; - if (position == 2) x -= pFont->StringWidth(pString); + if (position == 2) x -= pFont->StringWidth(pString); if (shadow) { - DrawText(twod, pFont, CR_UNTRANSLATED, x+1, y+1, pString, DTA_FullscreenScale, FSMode_Fit320x200, DTA_Color, 0xff000000, DTA_Alpha, 0.5, TAG_DONE); + DrawText(twod, pFont, CR_UNTRANSLATED, x + 1, y + 1, pString, DTA_FullscreenScale, FSMode_Fit320x200, DTA_Color, 0xff000000, DTA_Alpha, 0.5, TAG_DONE); } DrawText(twod, pFont, CR_NATIVEPAL, x, y, pString, DTA_FullscreenScale, FSMode_Fit320x200, DTA_TranslationIndex, TRANSLATION(Translation_Remap, nPalette), - DTA_Color, shadeToLight(nShade), TAG_DONE); + DTA_Color, shadeToLight(nShade), TAG_DONE); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + GameStats GameInterface::getStats() { return { gKillMgr.Kills, gKillMgr.TotalKills, gSecretMgr.Founds, gSecretMgr.Total, gFrameCount / kTicsPerSec, gPlayer[myconnectindex].fragCount }; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void viewDrawAimedPlayerName(void) { - if (!cl_idplayers || (gView->aim.dx == 0 && gView->aim.dy == 0)) - return; + if (!cl_idplayers || (gView->aim.dx == 0 && gView->aim.dy == 0)) + return; - int hit = HitScan(gView->actor, gView->zView, gView->aim.dx, gView->aim.dy, gView->aim.dz, CLIPMASK0, 512); - if (hit == 3) - { - auto actor = gHitInfo.actor(); - if (actor && actor->IsPlayerActor()) - { - int nPlayer = actor->spr.type-kDudePlayer1; - const char* szName = PlayerName(nPlayer); - int nPalette = (gPlayer[nPlayer].teamId&3)+11; - viewDrawText(DigiFont, szName, 160, 125, -128, nPalette, 1, 1); - } - } + int hit = HitScan(gView->actor, gView->zView, gView->aim.dx, gView->aim.dy, gView->aim.dz, CLIPMASK0, 512); + if (hit == 3) + { + auto actor = gHitInfo.actor(); + if (actor && actor->IsPlayerActor()) + { + int nPlayer = actor->spr.type - kDudePlayer1; + const char* szName = PlayerName(nPlayer); + int nPalette = (gPlayer[nPlayer].teamId & 3) + 11; + viewDrawText(DigiFont, szName, 160, 125, -128, nPalette, 1, 1); + } + } } static TArray lensdata; -int *lensTable; +int* lensTable; extern int dword_172CE0[16][3]; +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void viewInit(void) { - Printf("Initializing status bar\n"); + Printf("Initializing status bar\n"); - lensdata = fileSystem.LoadFile("lens.dat"); - assert(lensdata.Size() == kLensSize * kLensSize * sizeof(int)); + lensdata = fileSystem.LoadFile("lens.dat"); + assert(lensdata.Size() == kLensSize * kLensSize * sizeof(int)); - lensTable = (int*)lensdata.Data(); + lensTable = (int*)lensdata.Data(); #if WORDS_BIGENDIAN - for (int i = 0; i < kLensSize*kLensSize; i++) - { - lensTable[i] = LittleLong(lensTable[i]); - } + for (int i = 0; i < kLensSize * kLensSize; i++) + { + lensTable[i] = LittleLong(lensTable[i]); + } #endif - uint8_t *data = TileFiles.tileCreate(4077, kLensSize, kLensSize); - memset(data, TRANSPARENT_INDEX, kLensSize*kLensSize); + uint8_t* data = TileFiles.tileCreate(4077, kLensSize, kLensSize); + memset(data, TRANSPARENT_INDEX, kLensSize * kLensSize); - for (int i = 0; i < 16; i++) - { - dword_172CE0[i][0] = MulScale(wrand(), 2048, 16); - dword_172CE0[i][1] = MulScale(wrand(), 2048, 16); - dword_172CE0[i][2] = MulScale(wrand(), 2048, 16); - } + for (int i = 0; i < 16; i++) + { + dword_172CE0[i][0] = MulScale(wrand(), 2048, 16); + dword_172CE0[i][1] = MulScale(wrand(), 2048, 16); + dword_172CE0[i][2] = MulScale(wrand(), 2048, 16); + } } int othercameradist = 1280; int othercameraclock; +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + #if 0 -void CalcOtherPosition(DBloodActor *actor, int *pX, int *pY, int *pZ, sectortype** vsectnum, int nAng, fixed_t zm, int smoothratio) // currently unused +void CalcOtherPosition(DBloodActor* actor, int* pX, int* pY, int* pZ, sectortype** vsectnum, int nAng, fixed_t zm, int smoothratio) // currently unused { - int vX = MulScale(-Cos(nAng), 1280, 30); - int vY = MulScale(-Sin(nAng), 1280, 30); - int vZ = FixedToInt(MulScale(zm, 1280, 3))-(16<<8); - int bakCstat = pSprite->cstat; - pSprite->cstat &= ~CSTAT_SPRITE_BLOCK_HITSCAN; - assert(validSectorIndex(*vsectnum)); - FindSector(*pX, *pY, *pZ, vsectnum); - int nHSector; - int hX, hY; - vec3_t pos = {*pX, *pY, *pZ}; - hitscan(&pos, *vsectnum, vX, vY, vZ, &hitdata, CLIPMASK1); - nHSector = hitdata.sect; - hX = hitdata.pos.x; - hY = hitdata.pos.y; - int dX = hX-*pX; - int dY = hY-*pY; - if (abs(vX)+abs(vY) > abs(dX)+abs(dY)) - { - *vsectnum = nHSector; - dX -= Sgn(vX)<<6; - dY -= Sgn(vY)<<6; - int nDist; - if (abs(vX) > abs(vY)) - { - nDist = ClipHigh(DivScale(dX,vX, 16), othercameradist); - } - else - { - nDist = ClipHigh(DivScale(dY,vY, 16), othercameradist); - } - othercameradist = nDist; - } - *pX += MulScale(vX, othercameradist, 16); - *pY += MulScale(vY, othercameradist, 16); - *pZ += MulScale(vZ, othercameradist, 16); - int myclock = PlayClock + MulScale(4, smoothratio, 16); - othercameradist = ClipHigh(othercameradist+((myclock-othercameraclock)<<10), 65536); - othercameraclock = myclock; + int vX = MulScale(-Cos(nAng), 1280, 30); + int vY = MulScale(-Sin(nAng), 1280, 30); + int vZ = FixedToInt(MulScale(zm, 1280, 3)) - (16 << 8); + int bakCstat = pSprite->cstat; + pSprite->cstat &= ~CSTAT_SPRITE_BLOCK_HITSCAN; assert(validSectorIndex(*vsectnum)); - FindSector(*pX, *pY, *pZ, vsectnum); - pSprite->cstat = bakCstat; + FindSector(*pX, *pY, *pZ, vsectnum); + int nHSector; + int hX, hY; + vec3_t pos = { *pX, *pY, *pZ }; + hitscan(&pos, *vsectnum, vX, vY, vZ, &hitdata, CLIPMASK1); + nHSector = hitdata.sect; + hX = hitdata.pos.x; + hY = hitdata.pos.y; + int dX = hX - *pX; + int dY = hY - *pY; + if (abs(vX) + abs(vY) > abs(dX) + abs(dY)) + { + *vsectnum = nHSector; + dX -= Sgn(vX) << 6; + dY -= Sgn(vY) << 6; + int nDist; + if (abs(vX) > abs(vY)) + { + nDist = ClipHigh(DivScale(dX, vX, 16), othercameradist); + } + else + { + nDist = ClipHigh(DivScale(dY, vY, 16), othercameradist); + } + othercameradist = nDist; + } + *pX += MulScale(vX, othercameradist, 16); + *pY += MulScale(vY, othercameradist, 16); + *pZ += MulScale(vZ, othercameradist, 16); + int myclock = PlayClock + MulScale(4, smoothratio, 16); + othercameradist = ClipHigh(othercameradist + ((myclock - othercameraclock) << 10), 65536); + othercameraclock = myclock; + assert(validSectorIndex(*vsectnum)); + FindSector(*pX, *pY, *pZ, vsectnum); + pSprite->cstat = bakCstat; } #endif +//--------------------------------------------------------------------------- +// // by NoOne: show warning msgs in game instead of throwing errors (in some cases) +// +//--------------------------------------------------------------------------- + void viewSetSystemMessage(const char* pMessage, ...) { - char buffer[1024]; va_list args; va_start(args, pMessage); - vsprintf(buffer, pMessage, args); - - Printf(PRINT_HIGH | PRINT_NOTIFY, "%s\n", buffer); // print it also in console + char buffer[1024]; va_list args; va_start(args, pMessage); + vsprintf(buffer, pMessage, args); + + Printf(PRINT_HIGH | PRINT_NOTIFY, "%s\n", buffer); // print it also in console } -void viewSetMessage(const char *pMessage, const int pal, const MESSAGE_PRIORITY priority) +void viewSetMessage(const char* pMessage, const int pal, const MESSAGE_PRIORITY priority) { int printlevel = priority <= MESSAGE_PRIORITY_NORMAL ? PRINT_LOW : priority < MESSAGE_PRIORITY_SYSTEM ? PRINT_MEDIUM : PRINT_HIGH; - Printf(printlevel|PRINT_NOTIFY, "%s\n", pMessage); + Printf(printlevel | PRINT_NOTIFY, "%s\n", pMessage); } -void viewSetErrorMessage(const char *pMessage) +void viewSetErrorMessage(const char* pMessage) { - Printf(PRINT_BOLD|PRINT_NOTIFY, "%s\n", pMessage); + Printf(PRINT_BOLD | PRINT_NOTIFY, "%s\n", pMessage); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void DoLensEffect(void) { // To investigate whether this can be implemented as a shader effect. - auto d = tileData(4077); - assert(d != NULL); + auto d = tileData(4077); + assert(d != NULL); auto s = tilePtr(4079); - assert(s != NULL); - for (int i = 0; i < kLensSize*kLensSize; i++, d++) - if (lensTable[i] >= 0) - *d = s[lensTable[i]]; - TileFiles.InvalidateTile(4077); + assert(s != NULL); + for (int i = 0; i < kLensSize * kLensSize; i++, d++) + if (lensTable[i] >= 0) + *d = s[lensTable[i]]; + TileFiles.InvalidateTile(4077); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void UpdateDacs(int nPalette, bool bNoTint) { - gLastPal = 0; - auto& tint = lookups.tables[MAXPALOOKUPS - 1]; - tint.tintFlags = 0; - switch (nPalette) - { - case 0: - default: - tint.tintColor.r = 255; - tint.tintColor.g = 255; - tint.tintColor.b = 255; - break; - case 1: - tint.tintColor.r = 132; - tint.tintColor.g = 164; - tint.tintColor.b = 255; - break; - case 2: - tint.tintColor.r = 255; - tint.tintColor.g = 126; - tint.tintColor.b = 105; - break; - case 3: - tint.tintColor.r = 162; - tint.tintColor.g = 186; - tint.tintColor.b = 15; - break; - case 4: - tint.tintColor.r = 255; - tint.tintColor.g = 255; - tint.tintColor.b = 255; - break; - } - videoSetPalette(nPalette); + gLastPal = 0; + auto& tint = lookups.tables[MAXPALOOKUPS - 1]; + tint.tintFlags = 0; + switch (nPalette) + { + case 0: + default: + tint.tintColor.r = 255; + tint.tintColor.g = 255; + tint.tintColor.b = 255; + break; + case 1: + tint.tintColor.r = 132; + tint.tintColor.g = 164; + tint.tintColor.b = 255; + break; + case 2: + tint.tintColor.r = 255; + tint.tintColor.g = 126; + tint.tintColor.b = 105; + break; + case 3: + tint.tintColor.r = 162; + tint.tintColor.g = 186; + tint.tintColor.b = 15; + break; + case 4: + tint.tintColor.r = 255; + tint.tintColor.g = 255; + tint.tintColor.b = 255; + break; + } + videoSetPalette(nPalette); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void UpdateBlend() { - int nRed = 0; - int nGreen = 0; - int nBlue = 0; + int nRed = 0; + int nGreen = 0; + int nBlue = 0; - nRed += gView->pickupEffect; - nGreen += gView->pickupEffect; - nBlue -= gView->pickupEffect; + nRed += gView->pickupEffect; + nGreen += gView->pickupEffect; + nBlue -= gView->pickupEffect; - nRed += ClipHigh(gView->painEffect, 85) * 2; - nGreen -= ClipHigh(gView->painEffect, 85) * 3; - nBlue -= ClipHigh(gView->painEffect, 85) * 3; + nRed += ClipHigh(gView->painEffect, 85) * 2; + nGreen -= ClipHigh(gView->painEffect, 85) * 3; + nBlue -= ClipHigh(gView->painEffect, 85) * 3; - nRed -= gView->blindEffect; - nGreen -= gView->blindEffect; - nBlue -= gView->blindEffect; + nRed -= gView->blindEffect; + nGreen -= gView->blindEffect; + nBlue -= gView->blindEffect; - nRed -= gView->chokeEffect >> 6; - nGreen -= gView->chokeEffect >> 5; - nBlue -= gView->chokeEffect >> 6; + nRed -= gView->chokeEffect >> 6; + nGreen -= gView->chokeEffect >> 5; + nBlue -= gView->chokeEffect >> 6; - nRed = ClipRange(nRed, -255, 255); - nGreen = ClipRange(nGreen, -255, 255); - nBlue = ClipRange(nBlue, -255, 255); + nRed = ClipRange(nRed, -255, 255); + nGreen = ClipRange(nGreen, -255, 255); + nBlue = ClipRange(nBlue, -255, 255); - videoTintBlood(nRed, nGreen, nBlue); + videoTintBlood(nRed, nGreen, nBlue); } // int gVisibility; @@ -315,16 +380,22 @@ int gScreenTiltO, deliriumTurnO, deliriumPitchO; int gShowFrameRate = 1; +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void viewUpdateDelirium(void) { - gScreenTiltO = gScreenTilt; - deliriumTurnO = deliriumTurn; - deliriumPitchO = deliriumPitch; + gScreenTiltO = gScreenTilt; + deliriumTurnO = deliriumTurn; + deliriumPitchO = deliriumPitch; int powerCount; if ((powerCount = powerupCheck(gView, kPwUpDeliriumShroom)) != 0) { int tilt1 = 170, tilt2 = 170, pitch = 20; - int timer = PlayClock*4; + int timer = PlayClock * 4; if (powerCount < 512) { int powerScale = IntToFixed(powerCount) / 512; @@ -332,16 +403,16 @@ void viewUpdateDelirium(void) tilt2 = MulScale(tilt2, powerScale, 16); pitch = MulScale(pitch, powerScale, 16); } - int sin2 = Sin(2*timer) >> 1; - int sin3 = Sin(3*timer) >> 1; - gScreenTilt = MulScale(sin2+sin3,tilt1, 30); - int sin4 = Sin(4*timer) >> 1; - deliriumTurn = MulScale(sin3+sin4,tilt2, 30); - int sin5 = Sin(5*timer) >> 1; - deliriumPitch = MulScale(sin4+sin5,pitch, 30); + int sin2 = Sin(2 * timer) >> 1; + int sin3 = Sin(3 * timer) >> 1; + gScreenTilt = MulScale(sin2 + sin3, tilt1, 30); + int sin4 = Sin(4 * timer) >> 1; + deliriumTurn = MulScale(sin3 + sin4, tilt2, 30); + int sin5 = Sin(5 * timer) >> 1; + deliriumPitch = MulScale(sin4 + sin5, pitch, 30); return; } - gScreenTilt = ((gScreenTilt+1024)&2047)-1024; + gScreenTilt = ((gScreenTilt + 1024) & 2047) - 1024; if (gScreenTilt > 0) { gScreenTilt -= 8; @@ -356,24 +427,30 @@ void viewUpdateDelirium(void) } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void viewUpdateShake(int& cX, int& cY, int& cZ, binangle& cA, fixedhoriz& cH, double& pshakeX, double& pshakeY) { - auto doEffect = [&](const int& effectType) - { - if (effectType) - { - int nValue = ClipHigh(effectType * 8, 2000); - cH += buildhoriz(QRandom2(nValue >> 8)); - cA += buildang(QRandom2(nValue >> 8)); - cX += QRandom2(nValue >> 4); - cY += QRandom2(nValue >> 4); - cZ += QRandom2(nValue); - pshakeX += QRandom2(nValue); - pshakeY += QRandom2(nValue); - } - }; - doEffect(gView->flickerEffect); - doEffect(gView->quakeEffect); + auto doEffect = [&](const int& effectType) + { + if (effectType) + { + int nValue = ClipHigh(effectType * 8, 2000); + cH += buildhoriz(QRandom2(nValue >> 8)); + cA += buildang(QRandom2(nValue >> 8)); + cX += QRandom2(nValue >> 4); + cY += QRandom2(nValue >> 4); + cZ += QRandom2(nValue); + pshakeX += QRandom2(nValue); + pshakeY += QRandom2(nValue); + } + }; + doEffect(gView->flickerEffect); + doEffect(gView->quakeEffect); } @@ -381,167 +458,191 @@ int gLastPal = 0; int32_t g_frameRate; +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + static void DrawMap(DBloodActor* view) { - int tm = 0; - if (windowxy1.X > 0) - { - setViewport(Hud_Stbar); - tm = 1; - } - VIEW* pView = &gPrevView[gViewIndex]; - int x = interpolatedvalue(pView->x, view->spr.pos.X, gInterpolate); - int y = interpolatedvalue(pView->y, view->spr.pos.Y, gInterpolate); - int ang = (!SyncInput() ? gView->angle.sum() : gView->angle.interpolatedsum(gInterpolate)).asbuild(); - DrawOverheadMap(x, y, ang, gInterpolate); - if (tm) - setViewport(hud_size); + int tm = 0; + if (windowxy1.X > 0) + { + setViewport(Hud_Stbar); + tm = 1; + } + VIEW* pView = &gPrevView[gViewIndex]; + int x = interpolatedvalue(pView->x, view->spr.pos.X, gInterpolate); + int y = interpolatedvalue(pView->y, view->spr.pos.Y, gInterpolate); + int ang = (!SyncInput() ? gView->angle.sum() : gView->angle.interpolatedsum(gInterpolate)).asbuild(); + DrawOverheadMap(x, y, ang, gInterpolate); + if (tm) + setViewport(hud_size); } -void SetupView(int &cX, int& cY, int& cZ, binangle& cA, fixedhoriz& cH, sectortype*& pSector, double& zDelta, double& shakeX, double& shakeY, binangle& rotscrnang) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void SetupView(int& cX, int& cY, int& cZ, binangle& cA, fixedhoriz& cH, sectortype*& pSector, double& zDelta, double& shakeX, double& shakeY, binangle& rotscrnang) { - int bobWidth, bobHeight; - - pSector = gView->actor->spr.sector(); + int bobWidth, bobHeight; + + pSector = gView->actor->spr.sector(); #if 0 - if (numplayers > 1 && gView == gMe && gPrediction && gMe->actor->xspr.health > 0) - { - nSectnum = predict. sectnum; - cX = interpolatedvalue(predictOld.x, predict.x, gInterpolate); - cY = interpolatedvalue(predictOld.y, predict.y, gInterpolate); - cZ = interpolatedvalue(predictOld.viewz, predict.viewz, gInterpolate); - zDelta = interpolatedvaluef(predictOld.weaponZ, predict.weaponZ, gInterpolate); - bobWidth = interpolatedvalue(predictOld.bobWidth, predict.bobWidth, gInterpolate); - bobHeight = interpolatedvalue(predictOld.bobHeight, predict.bobHeight, gInterpolate); - shakeX = interpolatedvaluef(predictOld.shakeBobX, predict.shakeBobX, gInterpolate); - shakeY = interpolatedvaluef(predictOld.shakeBobY, predict.shakeBobY, gInterpolate); + if (numplayers > 1 && gView == gMe && gPrediction && gMe->actor->xspr.health > 0) + { + nSectnum = predict.sectnum; + cX = interpolatedvalue(predictOld.x, predict.x, gInterpolate); + cY = interpolatedvalue(predictOld.y, predict.y, gInterpolate); + cZ = interpolatedvalue(predictOld.viewz, predict.viewz, gInterpolate); + zDelta = interpolatedvaluef(predictOld.weaponZ, predict.weaponZ, gInterpolate); + bobWidth = interpolatedvalue(predictOld.bobWidth, predict.bobWidth, gInterpolate); + bobHeight = interpolatedvalue(predictOld.bobHeight, predict.bobHeight, gInterpolate); + shakeX = interpolatedvaluef(predictOld.shakeBobX, predict.shakeBobX, gInterpolate); + shakeY = interpolatedvaluef(predictOld.shakeBobY, predict.shakeBobY, gInterpolate); - if (!SyncInput()) - { - cA = bamang(predict.angle.asbam() + predict.look_ang.asbam()); - cH = predict.horiz + predict.horizoff; - rotscrnang = predict.rotscrnang; - } - else - { - cA = interpolatedangle(predictOld.angle + predictOld.look_ang, predict.angle + predict.look_ang, gInterpolate); - cH = interpolatedhorizon(predictOld.horiz + predictOld.horizoff, predict.horiz + predict.horizoff, gInterpolate); - rotscrnang = interpolatedangle(predictOld.rotscrnang, predict.rotscrnang, gInterpolate); - } - } - else + if (!SyncInput()) + { + cA = bamang(predict.angle.asbam() + predict.look_ang.asbam()); + cH = predict.horiz + predict.horizoff; + rotscrnang = predict.rotscrnang; + } + else + { + cA = interpolatedangle(predictOld.angle + predictOld.look_ang, predict.angle + predict.look_ang, gInterpolate); + cH = interpolatedhorizon(predictOld.horiz + predictOld.horizoff, predict.horiz + predict.horizoff, gInterpolate); + rotscrnang = interpolatedangle(predictOld.rotscrnang, predict.rotscrnang, gInterpolate); + } + } + else #endif - { - VIEW* pView = &gPrevView[gViewIndex]; - cX = interpolatedvalue(pView->x, gView->actor->spr.pos.X, gInterpolate); - cY = interpolatedvalue(pView->y, gView->actor->spr.pos.Y, gInterpolate); - cZ = interpolatedvalue(pView->viewz, gView->zView, gInterpolate); - zDelta = interpolatedvaluef(pView->weaponZ, gView->zWeapon - gView->zView - (12 << 8), gInterpolate); - bobWidth = interpolatedvalue(pView->bobWidth, gView->bobWidth, gInterpolate); - bobHeight = interpolatedvalue(pView->bobHeight, gView->bobHeight, gInterpolate); - shakeX = interpolatedvaluef(pView->shakeBobX, gView->swayWidth, gInterpolate); - shakeY = interpolatedvaluef(pView->shakeBobY, gView->swayHeight, gInterpolate); + { + VIEW* pView = &gPrevView[gViewIndex]; + cX = interpolatedvalue(pView->x, gView->actor->spr.pos.X, gInterpolate); + cY = interpolatedvalue(pView->y, gView->actor->spr.pos.Y, gInterpolate); + cZ = interpolatedvalue(pView->viewz, gView->zView, gInterpolate); + zDelta = interpolatedvaluef(pView->weaponZ, gView->zWeapon - gView->zView - (12 << 8), gInterpolate); + bobWidth = interpolatedvalue(pView->bobWidth, gView->bobWidth, gInterpolate); + bobHeight = interpolatedvalue(pView->bobHeight, gView->bobHeight, gInterpolate); + shakeX = interpolatedvaluef(pView->shakeBobX, gView->swayWidth, gInterpolate); + shakeY = interpolatedvaluef(pView->shakeBobY, gView->swayHeight, gInterpolate); - if (!SyncInput()) - { - cA = gView->angle.sum(); - cH = gView->horizon.sum(); - rotscrnang = gView->angle.rotscrnang; - } - else - { - cA = gView->angle.interpolatedsum(gInterpolate); - cH = gView->horizon.interpolatedsum(gInterpolate); - rotscrnang = gView->angle.interpolatedrotscrn(gInterpolate); - } - } + if (!SyncInput()) + { + cA = gView->angle.sum(); + cH = gView->horizon.sum(); + rotscrnang = gView->angle.rotscrnang; + } + else + { + cA = gView->angle.interpolatedsum(gInterpolate); + cH = gView->horizon.interpolatedsum(gInterpolate); + rotscrnang = gView->angle.interpolatedrotscrn(gInterpolate); + } + } - viewUpdateShake(cX, cY, cZ, cA, cH, shakeX, shakeY); - cH += buildhoriz(MulScale(0x40000000 - Cos(gView->tiltEffect << 2), 30, 30)); - if (gViewPos == 0) - { - if (cl_viewhbob) - { - cX -= MulScale(bobWidth, Sin(cA.asbuild()), 30) >> 4; - cY += MulScale(bobWidth, Cos(cA.asbuild()), 30) >> 4; - } - if (cl_viewvbob) - { - cZ += bobHeight; - } - cZ += xs_CRoundToInt(cH.asq16() / 6553.6); - cameradist = -1; - cameraclock = PlayClock + MulScale(4, (int)gInterpolate, 16); - } - else - { - calcChaseCamPos((int*)&cX, (int*)&cY, (int*)&cZ, gView->actor, &pSector, cA, cH, gInterpolate); - } - CheckLink((int*)&cX, (int*)&cY, (int*)&cZ, &pSector); + viewUpdateShake(cX, cY, cZ, cA, cH, shakeX, shakeY); + cH += buildhoriz(MulScale(0x40000000 - Cos(gView->tiltEffect << 2), 30, 30)); + if (gViewPos == 0) + { + if (cl_viewhbob) + { + cX -= MulScale(bobWidth, Sin(cA.asbuild()), 30) >> 4; + cY += MulScale(bobWidth, Cos(cA.asbuild()), 30) >> 4; + } + if (cl_viewvbob) + { + cZ += bobHeight; + } + cZ += xs_CRoundToInt(cH.asq16() / 6553.6); + cameradist = -1; + cameraclock = PlayClock + MulScale(4, (int)gInterpolate, 16); + } + else + { + calcChaseCamPos((int*)&cX, (int*)&cY, (int*)&cZ, gView->actor, &pSector, cA, cH, gInterpolate); + } + CheckLink((int*)&cX, (int*)&cY, (int*)&cZ, &pSector); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void renderCrystalBall() { #if 0 - int tmp = (PlayClock / 240) % (gNetPlayers - 1); - int i = connecthead; - while (1) - { - if (i == gViewIndex) - i = connectpoint2[i]; - if (tmp == 0) - break; - i = connectpoint2[i]; - tmp--; - } - PLAYER* pOther = &gPlayer[i]; - //othercameraclock = PlayClock + MulScale(4, (int)gInterpolate, 16);; - if (!tileData(4079)) - { - TileFiles.tileCreate(4079, 128, 128); - } - //renderSetTarget(4079, 128, 128); - renderSetAspect(65536, 78643); - int vd8 = pOther->actor->spr.x; - int vd4 = pOther->actor->spr.y; - int vd0 = pOther->zView; - int vcc = pOther->actor->spr. sectnum; - int v50 = pOther->actor->spr.ang; - int v54 = 0; - if (pOther->flickerEffect) - { - int nValue = ClipHigh(pOther->flickerEffect * 8, 2000); - v54 += QRandom2(nValue >> 8); - v50 += QRandom2(nValue >> 8); - vd8 += QRandom2(nValue >> 4); - vd4 += QRandom2(nValue >> 4); - vd0 += QRandom2(nValue); - } - if (pOther->quakeEffect) - { - int nValue = ClipHigh(pOther->quakeEffect * 8, 2000); - v54 += QRandom2(nValue >> 8); - v50 += QRandom2(nValue >> 8); - vd8 += QRandom2(nValue >> 4); - vd4 += QRandom2(nValue >> 4); - vd0 += QRandom2(nValue); - } - CalcOtherPosition(pOther->actor, &vd8, &vd4, &vd0, &vcc, v50, 0, (int)gInterpolate); - CheckLink(&vd8, &vd4, &vd0, &vcc); - uint8_t v14 = 0; - if (IsUnderwaterSector(vcc)) - { - v14 = 10; - } - drawrooms(vd8, vd4, vd0, v50, v54, vcc); - viewProcessSprites(vd8, vd4, vd0, v50, gInterpolate); - renderDrawMasks(); - renderRestoreTarget(); + int tmp = (PlayClock / 240) % (gNetPlayers - 1); + int i = connecthead; + while (1) + { + if (i == gViewIndex) + i = connectpoint2[i]; + if (tmp == 0) + break; + i = connectpoint2[i]; + tmp--; + } + PLAYER* pOther = &gPlayer[i]; + //othercameraclock = PlayClock + MulScale(4, (int)gInterpolate, 16);; + if (!tileData(4079)) + { + TileFiles.tileCreate(4079, 128, 128); + } + //renderSetTarget(4079, 128, 128); + renderSetAspect(65536, 78643); + int vd8 = pOther->actor->spr.x; + int vd4 = pOther->actor->spr.y; + int vd0 = pOther->zView; + int vcc = pOther->actor->spr.sectnum; + int v50 = pOther->actor->spr.ang; + int v54 = 0; + if (pOther->flickerEffect) + { + int nValue = ClipHigh(pOther->flickerEffect * 8, 2000); + v54 += QRandom2(nValue >> 8); + v50 += QRandom2(nValue >> 8); + vd8 += QRandom2(nValue >> 4); + vd4 += QRandom2(nValue >> 4); + vd0 += QRandom2(nValue); + } + if (pOther->quakeEffect) + { + int nValue = ClipHigh(pOther->quakeEffect * 8, 2000); + v54 += QRandom2(nValue >> 8); + v50 += QRandom2(nValue >> 8); + vd8 += QRandom2(nValue >> 4); + vd4 += QRandom2(nValue >> 4); + vd0 += QRandom2(nValue); + } + CalcOtherPosition(pOther->actor, &vd8, &vd4, &vd0, &vcc, v50, 0, (int)gInterpolate); + CheckLink(&vd8, &vd4, &vd0, &vcc); + uint8_t v14 = 0; + if (IsUnderwaterSector(vcc)) + { + v14 = 10; + } + drawrooms(vd8, vd4, vd0, v50, v54, vcc); + viewProcessSprites(vd8, vd4, vd0, v50, gInterpolate); + renderDrawMasks(); + renderRestoreTarget(); #endif } void render3DViewPolymost(int nSectnum, int cX, int cY, int cZ, binangle cA, fixedhoriz cH); +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void viewDrawScreen(bool sceneonly) { if (testgotpic(2342, true)) @@ -549,258 +650,276 @@ void viewDrawScreen(bool sceneonly) FireProcess(); } - if (!paused && (!M_Active() || gGameOptions.nGameType != 0)) - { - gInterpolate = !cl_interpolate || cl_capfps ? MaxSmoothRatio : I_GetTimeFrac() * MaxSmoothRatio; - } - else gInterpolate = MaxSmoothRatio; - pm_smoothratio = (int)gInterpolate; + if (!paused && (!M_Active() || gGameOptions.nGameType != 0)) + { + gInterpolate = !cl_interpolate || cl_capfps ? MaxSmoothRatio : I_GetTimeFrac() * MaxSmoothRatio; + } + else gInterpolate = MaxSmoothRatio; + pm_smoothratio = (int)gInterpolate; - if (cl_interpolate) - { - DoInterpolations(gInterpolate / MaxSmoothRatio); - } + if (cl_interpolate) + { + DoInterpolations(gInterpolate / MaxSmoothRatio); + } - if (automapMode != am_full) - { - DoSectorLighting(); - } - if (automapMode == am_off) - { - int basepal = 0; - if (powerupCheck(gView, kPwUpDeathMask) > 0) basepal = 4; - else if (powerupCheck(gView, kPwUpReflectShots) > 0) basepal = 1; - else if (gView->isUnderwater) { - if (gView->nWaterPal) basepal = gView->nWaterPal; - else { - if (gView->actor->xspr.medium == kMediumWater) basepal = 1; - else if (gView->actor->xspr.medium == kMediumGoo) basepal = 3; - else basepal = 2; - } - } - UpdateDacs(basepal); - UpdateBlend(); + if (automapMode != am_full) + { + DoSectorLighting(); + } + if (automapMode == am_off) + { + int basepal = 0; + if (powerupCheck(gView, kPwUpDeathMask) > 0) basepal = 4; + else if (powerupCheck(gView, kPwUpReflectShots) > 0) basepal = 1; + else if (gView->isUnderwater) { + if (gView->nWaterPal) basepal = gView->nWaterPal; + else { + if (gView->actor->xspr.medium == kMediumWater) basepal = 1; + else if (gView->actor->xspr.medium == kMediumGoo) basepal = 3; + else basepal = 2; + } + } + UpdateDacs(basepal); + UpdateBlend(); - int cX, cY, cZ; - binangle cA; - fixedhoriz cH; - sectortype* pSector; - double zDelta; - double shakeX, shakeY; - binangle rotscrnang; - SetupView(cX, cY, cZ, cA, cH, pSector, zDelta, shakeX, shakeY, rotscrnang); + int cX, cY, cZ; + binangle cA; + fixedhoriz cH; + sectortype* pSector; + double zDelta; + double shakeX, shakeY; + binangle rotscrnang; + SetupView(cX, cY, cZ, cA, cH, pSector, zDelta, shakeX, shakeY, rotscrnang); - binangle tilt = interpolatedangle(buildang(gScreenTiltO), buildang(gScreenTilt), gInterpolate); - bool bDelirium = powerupCheck(gView, kPwUpDeliriumShroom) > 0; - static bool bDeliriumOld = false; - //int tiltcs, tiltdim; - uint8_t otherview = powerupCheck(gView, kPwUpCrystalBall) > 0; - if (tilt.asbam() || bDelirium) - { - rotscrnang = tilt; - } - else if (otherview && gNetPlayers > 1) - { + binangle tilt = interpolatedangle(buildang(gScreenTiltO), buildang(gScreenTilt), gInterpolate); + bool bDelirium = powerupCheck(gView, kPwUpDeliriumShroom) > 0; + static bool bDeliriumOld = false; + //int tiltcs, tiltdim; + uint8_t otherview = powerupCheck(gView, kPwUpCrystalBall) > 0; + if (tilt.asbam() || bDelirium) + { + rotscrnang = tilt; + } + else if (otherview && gNetPlayers > 1) + { #if 0 - renderCrystalBall(); + renderCrystalBall(); #endif - } - else - { - othercameraclock = PlayClock + MulScale(4, (int)gInterpolate, 16); - } + } + else + { + othercameraclock = PlayClock + MulScale(4, (int)gInterpolate, 16); + } - if (!bDelirium) - { - deliriumTilt = 0; - deliriumTurn = 0; - deliriumPitch = 0; - } - int brightness = 0; + if (!bDelirium) + { + deliriumTilt = 0; + deliriumTurn = 0; + deliriumPitch = 0; + } + int brightness = 0; - BloodStatIterator it(kStatExplosion); - while (auto actor = it.Next()) - { - if (actor->hasX() && gotsector[actor->spr.sectno()]) - { - brightness += actor->xspr.data3 * 32; - } - } - it.Reset(kStatProjectile); - while (auto actor = it.Next()) - { - switch (actor->spr.type) { - case kMissileFlareRegular: - case kMissileTeslaAlt: - case kMissileFlareAlt: - case kMissileTeslaRegular: - if (gotsector[actor->spr.sectno()]) brightness += 256; - break; - } - } - g_visibility = (int32_t)(ClipLow(gVisibility - 32 * gView->visibility - brightness, 0)); - cA += interpolatedangle(buildang(deliriumTurnO), buildang(deliriumTurn), gInterpolate); + BloodStatIterator it(kStatExplosion); + while (auto actor = it.Next()) + { + if (actor->hasX() && gotsector[actor->spr.sectno()]) + { + brightness += actor->xspr.data3 * 32; + } + } + it.Reset(kStatProjectile); + while (auto actor = it.Next()) + { + switch (actor->spr.type) { + case kMissileFlareRegular: + case kMissileTeslaAlt: + case kMissileFlareAlt: + case kMissileTeslaRegular: + if (gotsector[actor->spr.sectno()]) brightness += 256; + break; + } + } + g_visibility = (int32_t)(ClipLow(gVisibility - 32 * gView->visibility - brightness, 0)); + cA += interpolatedangle(buildang(deliriumTurnO), buildang(deliriumTurn), gInterpolate); - int ceilingZ, floorZ; - getzsofslopeptr(pSector, cX, cY, &ceilingZ, &floorZ); - if ((cZ > floorZ - (1 << 8)) && (pSector->upperLink == nullptr)) // clamp to floor - { - cZ = floorZ - (1 << 8); - } - if ((cZ < ceilingZ + (1 << 8)) && (pSector->lowerLink == nullptr)) // clamp to ceiling - { - cZ = ceilingZ + (1 << 8); - } - cH = q16horiz(ClipRange(cH.asq16(), gi->playerHorizMin(), gi->playerHorizMax())); + int ceilingZ, floorZ; + getzsofslopeptr(pSector, cX, cY, &ceilingZ, &floorZ); + if ((cZ > floorZ - (1 << 8)) && (pSector->upperLink == nullptr)) // clamp to floor + { + cZ = floorZ - (1 << 8); + } + if ((cZ < ceilingZ + (1 << 8)) && (pSector->lowerLink == nullptr)) // clamp to ceiling + { + cZ = ceilingZ + (1 << 8); + } + cH = q16horiz(ClipRange(cH.asq16(), gi->playerHorizMin(), gi->playerHorizMax())); - if ((tilt.asbam() || bDelirium) && !sceneonly) - { - if (gDeliriumBlur) - { - // todo: Set up a blurring postprocessing shader. - //const float fBlur = pow(1.f/3.f, 30.f/g_frameRate); - //g lAccum(GL _MULT, fBlur); - //g lAccum(GL _ACCUM, 1.f-fBlur); - //g lAccum(GL _RETURN, 1.f); - } - } + if ((tilt.asbam() || bDelirium) && !sceneonly) + { + if (gDeliriumBlur) + { + // todo: Set up a blurring postprocessing shader. + //const float fBlur = pow(1.f/3.f, 30.f/g_frameRate); + //g lAccum(GL _MULT, fBlur); + //g lAccum(GL _ACCUM, 1.f-fBlur); + //g lAccum(GL _RETURN, 1.f); + } + } - if (testnewrenderer) - { - fixedhoriz deliriumPitchI = q16horiz(interpolatedvalue(IntToFixed(deliriumPitchO), IntToFixed(deliriumPitch), gInterpolate)); - auto bakCstat = gView->actor->spr.cstat; - gView->actor->spr.cstat |= (gViewPos == 0) ? CSTAT_SPRITE_INVISIBLE : CSTAT_SPRITE_TRANSLUCENT | CSTAT_SPRITE_TRANS_FLIP; - render_drawrooms(gView->actor, { cX, cY, cZ }, sectnum(pSector), cA, cH + deliriumPitchI, rotscrnang, gInterpolate); - gView->actor->spr.cstat = bakCstat; - } - else - { - renderSetRollAngle((float)rotscrnang.asbuildf()); - render3DViewPolymost(sectnum(pSector), cX, cY, cZ, cA, cH); - } - bDeliriumOld = bDelirium && gDeliriumBlur; + if (testnewrenderer) + { + fixedhoriz deliriumPitchI = q16horiz(interpolatedvalue(IntToFixed(deliriumPitchO), IntToFixed(deliriumPitch), gInterpolate)); + auto bakCstat = gView->actor->spr.cstat; + gView->actor->spr.cstat |= (gViewPos == 0) ? CSTAT_SPRITE_INVISIBLE : CSTAT_SPRITE_TRANSLUCENT | CSTAT_SPRITE_TRANS_FLIP; + render_drawrooms(gView->actor, { cX, cY, cZ }, sectnum(pSector), cA, cH + deliriumPitchI, rotscrnang, gInterpolate); + gView->actor->spr.cstat = bakCstat; + } + else + { + renderSetRollAngle((float)rotscrnang.asbuildf()); + render3DViewPolymost(sectnum(pSector), cX, cY, cZ, cA, cH); + } + bDeliriumOld = bDelirium && gDeliriumBlur; - int nClipDist = gView->actor->spr.clipdist << 2; - int vec, vf4; - Collision c1, c2; - GetZRange(gView->actor, &vf4, &c1, &vec, &c2, nClipDist, 0); - if (sceneonly) return; + int nClipDist = gView->actor->spr.clipdist << 2; + int vec, vf4; + Collision c1, c2; + GetZRange(gView->actor, &vf4, &c1, &vec, &c2, nClipDist, 0); + if (sceneonly) return; #if 0 - int tmpSect = nSectnum; - if ((vf0 & 0xc000) == 0x4000) - { - tmpSect = vf0 & (kMaxWalls - 1); - } - int v8 = byte_1CE5C2 > 0 && (sector [tmpSect].ceilingstat & CSTAT_SECTOR_SKY); - if (gWeather.at12d8 > 0 || v8) - { - gWeather.Draw(cX, cY, cZ, cA.asq16(), cH.asq16() + deliriumPitch, gWeather.at12d8); - if (v8) - { - gWeather.at12d8 = ClipRange(delta * 8 + gWeather.at12d8, 0, 4095); - } - else - { - gWeather.at12d8 = ClipRange(gWeather.at12d8 - delta * 64, 0, 4095); - } - } + int tmpSect = nSectnum; + if ((vf0 & 0xc000) == 0x4000) + { + tmpSect = vf0 & (kMaxWalls - 1); + } + int v8 = byte_1CE5C2 > 0 && (sector[tmpSect].ceilingstat & CSTAT_SECTOR_SKY); + if (gWeather.at12d8 > 0 || v8) + { + gWeather.Draw(cX, cY, cZ, cA.asq16(), cH.asq16() + deliriumPitch, gWeather.at12d8); + if (v8) + { + gWeather.at12d8 = ClipRange(delta * 8 + gWeather.at12d8, 0, 4095); + } + else + { + gWeather.at12d8 = ClipRange(gWeather.at12d8 - delta * 64, 0, 4095); + } + } #endif - hudDraw(gView, pSector, shakeX, shakeY, zDelta, basepal, gInterpolate); - } - UpdateDacs(0, true); // keep the view palette active only for the actual 3D view and its overlays. - if (automapMode != am_off) - { - DrawMap (gView->actor); - } - UpdateStatusBar(); - int zn = ((gView->zWeapon-gView->zView-(12<<8))>>7)+220; - PLAYER *pPSprite = &gPlayer[gMe->actor->spr.type-kDudePlayer1]; - if (gMe->actor->IsPlayerActor() && pPSprite->hand == 1) - { - gChoke.animateChoke(160, zn, (int)gInterpolate); - } + hudDraw(gView, pSector, shakeX, shakeY, zDelta, basepal, gInterpolate); + } + UpdateDacs(0, true); // keep the view palette active only for the actual 3D view and its overlays. + if (automapMode != am_off) + { + DrawMap(gView->actor); + } + UpdateStatusBar(); + int zn = ((gView->zWeapon - gView->zView - (12 << 8)) >> 7) + 220; + PLAYER* pPSprite = &gPlayer[gMe->actor->spr.type - kDudePlayer1]; + if (gMe->actor->IsPlayerActor() && pPSprite->hand == 1) + { + gChoke.animateChoke(160, zn, (int)gInterpolate); + } - viewDrawAimedPlayerName(); - if (paused) - { - auto text = GStrings("TXTB_PAUSED"); - viewDrawText(PickBigFont(text), text, 160, 10, 0, 0, 1, 0); - } - else if (gView != gMe) - { - FStringf gTempStr("] %s [", PlayerName(gView->nPlayer)); - viewDrawText(OriginalSmallFont, gTempStr, 160, 10, 0, 0, 1, 0); - } - if (cl_interpolate) - { - RestoreInterpolations(); - } + viewDrawAimedPlayerName(); + if (paused) + { + auto text = GStrings("TXTB_PAUSED"); + viewDrawText(PickBigFont(text), text, 160, 10, 0, 0, 1, 0); + } + else if (gView != gMe) + { + FStringf gTempStr("] %s [", PlayerName(gView->nPlayer)); + viewDrawText(OriginalSmallFont, gTempStr, 160, 10, 0, 0, 1, 0); + } + if (cl_interpolate) + { + RestoreInterpolations(); + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + bool GameInterface::GenerateSavePic() { - viewDrawScreen(true); - return true; + viewDrawScreen(true); + return true; } FString GameInterface::GetCoordString() { - FString out; + FString out; - out.Format("pos= %d, %d, %d - angle = %2.3f", - gMe->actor->spr.pos.X, gMe->actor->spr.pos.Y, gMe->actor->spr.pos.Z, gMe->actor->spr.ang * BAngToDegree); + out.Format("pos= %d, %d, %d - angle = %2.3f", + gMe->actor->spr.pos.X, gMe->actor->spr.pos.Y, gMe->actor->spr.pos.Z, gMe->actor->spr.ang * BAngToDegree); - return out; + return out; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + bool GameInterface::DrawAutomapPlayer(int mx, int my, int x, int y, int z, int a, double const smoothratio) { - for (int i = connecthead; i >= 0; i = connectpoint2[i]) - { - PLAYER* pPlayer = &gPlayer[i]; - auto actor = pPlayer->actor; + for (int i = connecthead; i >= 0; i = connectpoint2[i]) + { + PLAYER* pPlayer = &gPlayer[i]; + auto actor = pPlayer->actor; - int xvect = -bsin(a) * z; - int yvect = -bcos(a) * z; - int ox = mx - x; - int oy = my - y; - int x1 = DMulScale(ox, xvect, -oy, yvect, 16); - int y1 = DMulScale(oy, xvect, ox, yvect, 16); - int xx = xdim / 2. + x1 / 4096.; - int yy = ydim / 2. + y1 / 4096.; + int xvect = -bsin(a) * z; + int yvect = -bcos(a) * z; + int ox = mx - x; + int oy = my - y; + int x1 = DMulScale(ox, xvect, -oy, yvect, 16); + int y1 = DMulScale(oy, xvect, ox, yvect, 16); + int xx = xdim / 2. + x1 / 4096.; + int yy = ydim / 2. + y1 / 4096.; - if (i == gView->nPlayer || gGameOptions.nGameType == 1) - { - int nTile = actor->spr.picnum; - int ceilZ, floorZ; - Collision ceilHit, floorHit; - GetZRange(gView->actor, &ceilZ, &ceilHit, &floorZ, &floorHit, (actor->spr.clipdist << 2) + 16, CLIPMASK0, PARALLAXCLIP_CEILING | PARALLAXCLIP_FLOOR); - int nTop, nBottom; - GetActorExtents(actor, &nTop, &nBottom); - int nScale = (actor->spr.yrepeat + ((floorZ - nBottom) >> 8)) * z; - nScale = ClipRange(nScale, 8000, 65536 << 1); - // Players on automap - double xsize = xdim / 2. + x1 / double(1 << 12); - double ysize = ydim / 2. + y1 / double(1 << 12); - // This very likely needs fixing later - DrawTexture(twod, tileGetTexture(nTile, true), xx, yy, DTA_ClipLeft, windowxy1.X, DTA_ClipTop, windowxy1.Y, DTA_ScaleX, z/1536., DTA_ScaleY, z/1536., DTA_CenterOffset, true, - DTA_ClipRight, windowxy2.X + 1, DTA_ClipBottom, windowxy2.Y + 1, DTA_Alpha, (actor->spr.cstat & CSTAT_SPRITE_TRANSLUCENT ? 0.5 : 1.), TAG_DONE); - } - } - return true; + if (i == gView->nPlayer || gGameOptions.nGameType == 1) + { + int nTile = actor->spr.picnum; + int ceilZ, floorZ; + Collision ceilHit, floorHit; + GetZRange(gView->actor, &ceilZ, &ceilHit, &floorZ, &floorHit, (actor->spr.clipdist << 2) + 16, CLIPMASK0, PARALLAXCLIP_CEILING | PARALLAXCLIP_FLOOR); + int nTop, nBottom; + GetActorExtents(actor, &nTop, &nBottom); + int nScale = (actor->spr.yrepeat + ((floorZ - nBottom) >> 8)) * z; + nScale = ClipRange(nScale, 8000, 65536 << 1); + // Players on automap + double xsize = xdim / 2. + x1 / double(1 << 12); + double ysize = ydim / 2. + y1 / double(1 << 12); + // This very likely needs fixing later + DrawTexture(twod, tileGetTexture(nTile, true), xx, yy, DTA_ClipLeft, windowxy1.X, DTA_ClipTop, windowxy1.Y, DTA_ScaleX, z / 1536., DTA_ScaleY, z / 1536., DTA_CenterOffset, true, + DTA_ClipRight, windowxy2.X + 1, DTA_ClipBottom, windowxy2.Y + 1, DTA_Alpha, (actor->spr.cstat & CSTAT_SPRITE_TRANSLUCENT ? 0.5 : 1.), TAG_DONE); + } + } + return true; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void SerializeView(FSerializer& arc) { - if (arc.BeginObject("view")) - { - arc("screentilt", gScreenTilt) - ("deliriumtilt", deliriumTilt) - ("deliriumturn", deliriumTurn) - ("deliriumpitch", deliriumPitch) - .EndObject(); - } + if (arc.BeginObject("view")) + { + arc("screentilt", gScreenTilt) + ("deliriumtilt", deliriumTilt) + ("deliriumturn", deliriumTurn) + ("deliriumpitch", deliriumPitch) + .EndObject(); + } } diff --git a/source/games/blood/src/view.h b/source/games/blood/src/view.h index 90e97f61e..ee7a2d90d 100644 --- a/source/games/blood/src/view.h +++ b/source/games/blood/src/view.h @@ -32,46 +32,46 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. BEGIN_BLD_NS struct VIEW { - int bobPhase; - int Kills; - int bobHeight; // bob height - int bobWidth; // bob width - int at10; - int at14; - int shakeBobY; // bob sway y - int shakeBobX; // bob sway x - fixedhoriz horiz; // horiz - fixedhoriz horizoff; // horizoff - int at2c; - binangle angle; // angle - int weaponZ; // weapon z - int viewz; // view z - int at3c; - int at40; - int at44; - int at48; // posture - double spin; // spin - union { - struct - { - int32_t x, y, z; - }; - vec3_t pos; - }; - int xvel; //xvel - int yvel; //yvel - int zvel; //zvel - int sectnum; // sectnum - unsigned int floordist; // floordist - uint8_t at6e; // look center - uint8_t at6f; - uint8_t at70; // run - uint8_t at71; // jump - uint8_t at72; // underwater - int16_t at73; // sprite flags - SPRITEHIT at75; - binangle look_ang; - binangle rotscrnang; + int bobPhase; + int Kills; + int bobHeight; // bob height + int bobWidth; // bob width + int at10; + int at14; + int shakeBobY; // bob sway y + int shakeBobX; // bob sway x + fixedhoriz horiz; // horiz + fixedhoriz horizoff; // horizoff + int at2c; + binangle angle; // angle + int weaponZ; // weapon z + int viewz; // view z + int at3c; + int at40; + int at44; + int at48; // posture + double spin; // spin + union { + struct + { + int32_t x, y, z; + }; + vec3_t pos; + }; + int xvel; //xvel + int yvel; //yvel + int zvel; //zvel + int sectnum; // sectnum + unsigned int floordist; // floordist + uint8_t at6e; // look center + uint8_t at6f; + uint8_t at70; // run + uint8_t at71; // jump + uint8_t at72; // underwater + int16_t at73; // sprite flags + SPRITEHIT at75; + binangle look_ang; + binangle rotscrnang; }; extern VIEW gPrevView[kMaxPlayers]; @@ -80,55 +80,55 @@ extern VIEW predict, predictOld; extern bool gPrediction; enum VIEW_EFFECT { - kViewEffectShadow = 0, - kViewEffectFlareHalo, - kViewEffectCeilGlow, - kViewEffectFloorGlow, - kViewEffectTorchHigh, - kViewEffectTorchLow, - kViewEffectSmokeHigh, - kViewEffectSmokeLow, - kViewEffectFlame, - kViewEffectSpear, - kViewEffectTrail, - kViewEffectPhase, - kViewEffectShowWeapon, - kViewEffectReflectiveBall, - kViewEffectShoot, - kViewEffectTesla, - kViewEffectFlag, - kViewEffectBigFlag, - kViewEffectAtom, - kViewEffectSpotProgress, + kViewEffectShadow = 0, + kViewEffectFlareHalo, + kViewEffectCeilGlow, + kViewEffectFloorGlow, + kViewEffectTorchHigh, + kViewEffectTorchLow, + kViewEffectSmokeHigh, + kViewEffectSmokeLow, + kViewEffectFlame, + kViewEffectSpear, + kViewEffectTrail, + kViewEffectPhase, + kViewEffectShowWeapon, + kViewEffectReflectiveBall, + kViewEffectShoot, + kViewEffectTesla, + kViewEffectFlag, + kViewEffectBigFlag, + kViewEffectAtom, + kViewEffectSpotProgress, }; enum VIEWPOS { - VIEWPOS_0 = 0, - VIEWPOS_1 + VIEWPOS_0 = 0, + VIEWPOS_1 }; enum { - kBackTile = 253, + kBackTile = 253, - kCrosshairTile = 2319, - kLoadScreen = 2049, - kLoadScreenWideBack = 9216, - kLoadScreenWideLeft = 9217, - kLoadScreenWideRight = 9218, - kLoadScreenWideMiddle = 9219, + kCrosshairTile = 2319, + kLoadScreen = 2049, + kLoadScreenWideBack = 9216, + kLoadScreenWideLeft = 9217, + kLoadScreenWideRight = 9218, + kLoadScreenWideMiddle = 9219, - kSBarNumberHealth = 9220, - kSBarNumberAmmo = 9230, - kSBarNumberInv = 9240, - kSBarNumberArmor1 = 9250, - kSBarNumberArmor2 = 9260, - kSBarNumberArmor3 = 9270, + kSBarNumberHealth = 9220, + kSBarNumberAmmo = 9230, + kSBarNumberInv = 9240, + kSBarNumberArmor1 = 9250, + kSBarNumberArmor2 = 9260, + kSBarNumberArmor3 = 9270, }; enum { kFontNum = 5 }; -extern FFont *gFont[kFontNum]; +extern FFont* gFont[kFontNum]; extern VIEWPOS gViewPos; extern int gViewIndex; extern int gScreenTilt; @@ -140,44 +140,44 @@ extern double gInterpolate; void hudDraw(PLAYER* gView, sectortype* pSector, double bobx, double boby, double zDelta, int basepal, double smoothratio); void viewInitializePrediction(void); -void viewUpdatePrediction(InputPacket *pInput); +void viewUpdatePrediction(InputPacket* pInput); void viewCorrectPrediction(void); void viewBackupView(int nPlayer); -void viewCorrectViewOffsets(int nPlayer, vec3_t const *oldpos); +void viewCorrectViewOffsets(int nPlayer, vec3_t const* oldpos); void InitStatusBar(void); void UpdateStatusBar(); void viewInit(void); void viewprocessSprites(tspritetype* tsprite, int& spritesortcnt, int32_t cX, int32_t cY, int32_t cZ, int32_t cA, int32_t smooth); -void viewSetMessage(const char *pMessage, const int pal = 0, const MESSAGE_PRIORITY priority = MESSAGE_PRIORITY_NORMAL); +void viewSetMessage(const char* pMessage, const int pal = 0, const MESSAGE_PRIORITY priority = MESSAGE_PRIORITY_NORMAL); -void viewSetErrorMessage(const char *pMessage); +void viewSetErrorMessage(const char* pMessage); void DoLensEffect(void); void UpdateDacs(int nPalette, bool bNoTint = false); void viewDrawScreen(bool sceneonly = false); void viewUpdateDelirium(void); void viewSetSystemMessage(const char* pMessage, ...); -inline void viewInterpolateSector(sectortype *pSector) +inline void viewInterpolateSector(sectortype* pSector) { - StartInterpolation(pSector, Interp_Sect_Floorz); - StartInterpolation(pSector, Interp_Sect_Ceilingz); - StartInterpolation(pSector, Interp_Sect_Floorheinum); + StartInterpolation(pSector, Interp_Sect_Floorz); + StartInterpolation(pSector, Interp_Sect_Ceilingz); + StartInterpolation(pSector, Interp_Sect_Floorheinum); } -inline void viewInterpolateWall(walltype *pWall) +inline void viewInterpolateWall(walltype* pWall) { - StartInterpolation(pWall, Interp_Wall_X); - StartInterpolation(pWall, Interp_Wall_Y); + StartInterpolation(pWall, Interp_Wall_X); + StartInterpolation(pWall, Interp_Wall_Y); } inline void viewBackupSpriteLoc(DBloodActor* actor) { - if (!actor->interpolated) - { - actor->spr.backuploc(); - actor->interpolated = true; - } + if (!actor->interpolated) + { + actor->spr.backuploc(); + actor->interpolated = true; + } } diff --git a/source/games/blood/src/warp.cpp b/source/games/blood/src/warp.cpp index fd42cc046..3ed632dc2 100644 --- a/source/games/blood/src/warp.cpp +++ b/source/games/blood/src/warp.cpp @@ -30,268 +30,293 @@ BEGIN_BLD_NS ZONE gStartZone[8]; #ifdef NOONE_EXTENSIONS - ZONE gStartZoneTeam1[8]; - ZONE gStartZoneTeam2[8]; - bool gTeamsSpawnUsed = false; +ZONE gStartZoneTeam1[8]; +ZONE gStartZoneTeam2[8]; +bool gTeamsSpawnUsed = false; #endif +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void validateLinks() { - int snum = 0; - for (auto& sect: sector) - { - DCoreActor* upper = sect.upperLink; - if (upper && !static_cast(upper)->GetOwner()) - { - Printf(PRINT_HIGH, "Unpartnered upper link in sector %d\n", snum); - sect.upperLink = nullptr; - } - DCoreActor* lower = sect.lowerLink; - if (lower && !static_cast(lower)->GetOwner()) - { - Printf(PRINT_HIGH, "Unpartnered lower link in sector %d\n", snum); - sect.lowerLink = nullptr; - } - snum++; - } + int snum = 0; + for (auto& sect : sector) + { + DCoreActor* upper = sect.upperLink; + if (upper && !static_cast(upper)->GetOwner()) + { + Printf(PRINT_HIGH, "Unpartnered upper link in sector %d\n", snum); + sect.upperLink = nullptr; + } + DCoreActor* lower = sect.lowerLink; + if (lower && !static_cast(lower)->GetOwner()) + { + Printf(PRINT_HIGH, "Unpartnered lower link in sector %d\n", snum); + sect.lowerLink = nullptr; + } + snum++; + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void warpInit(TArray& actors) { - #ifdef NOONE_EXTENSIONS - int team1 = 0; int team2 = 0; gTeamsSpawnUsed = false; // increment if team start positions specified. - #endif +#ifdef NOONE_EXTENSIONS + int team1 = 0; int team2 = 0; gTeamsSpawnUsed = false; // increment if team start positions specified. +#endif - for(auto actor : actors) - { - if (!actor->exists()) continue; - if (actor->hasX()) { - switch (actor->spr.type) { - case kMarkerSPStart: - if (gGameOptions.nGameType < 2 && actor->xspr.data1 >= 0 && actor->xspr.data1 < kMaxPlayers) { - ZONE *pZone = &gStartZone[actor->xspr.data1]; - pZone->x = actor->spr.pos.X; - pZone->y = actor->spr.pos.Y; - pZone->z = actor->spr.pos.Z; - pZone->sector = actor->spr.sector(); - pZone->ang = actor->spr.ang; - } - DeleteSprite(actor); - break; - case kMarkerMPStart: - if (actor->xspr.data1 >= 0 && actor->xspr.data2 < kMaxPlayers) { - if (gGameOptions.nGameType >= 2) { - // default if BB or teams without data2 specified - ZONE* pZone = &gStartZone[actor->xspr.data1]; - pZone->x = actor->spr.pos.X; - pZone->y = actor->spr.pos.Y; - pZone->z = actor->spr.pos.Z; - pZone->sector = actor->spr.sector(); - pZone->ang = actor->spr.ang; - - #ifdef NOONE_EXTENSIONS - // fill player spawn position according team of player in TEAMS mode. - if (gModernMap && gGameOptions.nGameType == 3) { - if (actor->xspr.data2 == 1) { - pZone = &gStartZoneTeam1[team1]; - pZone->x = actor->spr.pos.X; - pZone->y = actor->spr.pos.Y; - pZone->z = actor->spr.pos.Z; - pZone->sector = actor->spr.sector(); - pZone->ang = actor->spr.ang; - team1++; + for (auto actor : actors) + { + if (!actor->exists()) continue; + if (actor->hasX()) { + switch (actor->spr.type) { + case kMarkerSPStart: + if (gGameOptions.nGameType < 2 && actor->xspr.data1 >= 0 && actor->xspr.data1 < kMaxPlayers) { + ZONE* pZone = &gStartZone[actor->xspr.data1]; + pZone->x = actor->spr.pos.X; + pZone->y = actor->spr.pos.Y; + pZone->z = actor->spr.pos.Z; + pZone->sector = actor->spr.sector(); + pZone->ang = actor->spr.ang; + } + DeleteSprite(actor); + break; + case kMarkerMPStart: + if (actor->xspr.data1 >= 0 && actor->xspr.data2 < kMaxPlayers) { + if (gGameOptions.nGameType >= 2) { + // default if BB or teams without data2 specified + ZONE* pZone = &gStartZone[actor->xspr.data1]; + pZone->x = actor->spr.pos.X; + pZone->y = actor->spr.pos.Y; + pZone->z = actor->spr.pos.Z; + pZone->sector = actor->spr.sector(); + pZone->ang = actor->spr.ang; - } else if (actor->xspr.data2 == 2) { - pZone = &gStartZoneTeam2[team2]; - pZone->x = actor->spr.pos.X; - pZone->y = actor->spr.pos.Y; - pZone->z = actor->spr.pos.Z; - pZone->sector = actor->spr.sector(); - pZone->ang = actor->spr.ang; - team2++; - } - } - #endif +#ifdef NOONE_EXTENSIONS + // fill player spawn position according team of player in TEAMS mode. + if (gModernMap && gGameOptions.nGameType == 3) { + if (actor->xspr.data2 == 1) { + pZone = &gStartZoneTeam1[team1]; + pZone->x = actor->spr.pos.X; + pZone->y = actor->spr.pos.Y; + pZone->z = actor->spr.pos.Z; + pZone->sector = actor->spr.sector(); + pZone->ang = actor->spr.ang; + team1++; - } - DeleteSprite(actor); - } - break; - case kMarkerUpLink: - actor->spr.sector()->upperLink = actor; - actor->spr.cstat |= CSTAT_SPRITE_INVISIBLE; - actor->spr.cstat &= ~CSTAT_SPRITE_BLOCK_ALL; - break; - case kMarkerLowLink: - actor->spr.sector()->lowerLink = actor; - actor->spr.cstat |= CSTAT_SPRITE_INVISIBLE; - actor->spr.cstat &= ~CSTAT_SPRITE_BLOCK_ALL; - break; - case kMarkerUpWater: - case kMarkerUpStack: - case kMarkerUpGoo: - actor->spr.sector()->upperLink = actor; - actor->spr.cstat |= CSTAT_SPRITE_INVISIBLE; - actor->spr.cstat &= ~CSTAT_SPRITE_BLOCK_ALL; - actor->spr.pos.Z = getflorzofslopeptr(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y); - break; - case kMarkerLowWater: - case kMarkerLowStack: - case kMarkerLowGoo: - actor->spr.sector()->lowerLink = actor; - actor->spr.cstat |= CSTAT_SPRITE_INVISIBLE; - actor->spr.cstat &= ~CSTAT_SPRITE_BLOCK_ALL; - actor->spr.pos.Z = getceilzofslopeptr(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y); - break; - } - } - } - - #ifdef NOONE_EXTENSIONS - // check if there is enough start positions for teams, if any used - if (team1 > 0 || team2 > 0) { - gTeamsSpawnUsed = true; - if (team1 < kMaxPlayers / 2 || team2 < kMaxPlayers / 2) { - viewSetSystemMessage("At least 4 spawn positions for each team is recommended."); - viewSetSystemMessage("Team A positions: %d, Team B positions: %d.", team1, team2); - } - } - #endif + } + else if (actor->xspr.data2 == 2) { + pZone = &gStartZoneTeam2[team2]; + pZone->x = actor->spr.pos.X; + pZone->y = actor->spr.pos.Y; + pZone->z = actor->spr.pos.Z; + pZone->sector = actor->spr.sector(); + pZone->ang = actor->spr.ang; + team2++; + } + } +#endif - for(auto& sect: sector) - { - auto actor = barrier_cast(sect.upperLink); - if (actor && actor->hasX()) - { - int nLink = actor->xspr.data1; - for(auto& isect: sector) - { - auto actor2 = barrier_cast(isect.lowerLink); - if (actor2 && actor2->hasX()) - { - if (actor2->xspr.data1 == nLink) - { - actor->SetOwner(actor2); - actor2->SetOwner(actor); - } - } - } - } - } + } + DeleteSprite(actor); + } + break; + case kMarkerUpLink: + actor->spr.sector()->upperLink = actor; + actor->spr.cstat |= CSTAT_SPRITE_INVISIBLE; + actor->spr.cstat &= ~CSTAT_SPRITE_BLOCK_ALL; + break; + case kMarkerLowLink: + actor->spr.sector()->lowerLink = actor; + actor->spr.cstat |= CSTAT_SPRITE_INVISIBLE; + actor->spr.cstat &= ~CSTAT_SPRITE_BLOCK_ALL; + break; + case kMarkerUpWater: + case kMarkerUpStack: + case kMarkerUpGoo: + actor->spr.sector()->upperLink = actor; + actor->spr.cstat |= CSTAT_SPRITE_INVISIBLE; + actor->spr.cstat &= ~CSTAT_SPRITE_BLOCK_ALL; + actor->spr.pos.Z = getflorzofslopeptr(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y); + break; + case kMarkerLowWater: + case kMarkerLowStack: + case kMarkerLowGoo: + actor->spr.sector()->lowerLink = actor; + actor->spr.cstat |= CSTAT_SPRITE_INVISIBLE; + actor->spr.cstat &= ~CSTAT_SPRITE_BLOCK_ALL; + actor->spr.pos.Z = getceilzofslopeptr(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y); + break; + } + } + } + +#ifdef NOONE_EXTENSIONS + // check if there is enough start positions for teams, if any used + if (team1 > 0 || team2 > 0) { + gTeamsSpawnUsed = true; + if (team1 < kMaxPlayers / 2 || team2 < kMaxPlayers / 2) { + viewSetSystemMessage("At least 4 spawn positions for each team is recommended."); + viewSetSystemMessage("Team A positions: %d, Team B positions: %d.", team1, team2); + } + } +#endif + + for (auto& sect : sector) + { + auto actor = barrier_cast(sect.upperLink); + if (actor && actor->hasX()) + { + int nLink = actor->xspr.data1; + for (auto& isect : sector) + { + auto actor2 = barrier_cast(isect.lowerLink); + if (actor2 && actor2->hasX()) + { + if (actor2->xspr.data1 == nLink) + { + actor->SetOwner(actor2); + actor2->SetOwner(actor); + } + } + } + } + } validateLinks(); } -int CheckLink(DBloodActor *actor) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +int CheckLink(DBloodActor* actor) { - auto pSector = actor->spr.sector(); - auto aUpper = barrier_cast(pSector->upperLink); - auto aLower = barrier_cast(pSector->lowerLink); - if (aUpper) - { - int z; - if (aUpper->spr.type == kMarkerUpLink) - z = aUpper->spr.pos.Z; - else - z = getflorzofslopeptr(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y); - if (z <= actor->spr.pos.Z) - { - aLower = aUpper->GetOwner(); - assert(aLower); - assert(aLower->spr.insector()); - ChangeActorSect(actor, aLower->spr.sector()); - actor->spr.pos.X += aLower->spr.pos.X - aUpper->spr.pos.X; - actor->spr.pos.Y += aLower->spr.pos.Y - aUpper->spr.pos.Y; - int z2; - if (aLower->spr.type == kMarkerLowLink) - z2 = aLower->spr.pos.Z; - else - z2 = getceilzofslopeptr(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y); - actor->spr.pos.Z += z2-z; - actor->interpolated = false; - return aUpper->spr.type; - } - } - if (aLower) - { - int z; - if (aLower->spr.type == kMarkerLowLink) - z = aLower->spr.pos.Z; - else - z = getceilzofslopeptr(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y); - if (z >= actor->spr.pos.Z) - { - aUpper = aLower->GetOwner(); - assert(aUpper); - assert(aUpper->spr.insector()); - ChangeActorSect(actor, aUpper->spr.sector()); - actor->spr.pos.X += aUpper->spr.pos.X - aLower->spr.pos.X; - actor->spr.pos.Y += aUpper->spr.pos.Y - aLower->spr.pos.Y; - int z2; - if (aUpper->spr.type == kMarkerUpLink) - z2 = aUpper->spr.pos.Z; - else - z2 = getflorzofslopeptr(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y); - actor->spr.pos.Z += z2-z; - actor->interpolated = false; - return aLower->spr.type; - } - } - return 0; + auto pSector = actor->spr.sector(); + auto aUpper = barrier_cast(pSector->upperLink); + auto aLower = barrier_cast(pSector->lowerLink); + if (aUpper) + { + int z; + if (aUpper->spr.type == kMarkerUpLink) + z = aUpper->spr.pos.Z; + else + z = getflorzofslopeptr(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y); + if (z <= actor->spr.pos.Z) + { + aLower = aUpper->GetOwner(); + assert(aLower); + assert(aLower->spr.insector()); + ChangeActorSect(actor, aLower->spr.sector()); + actor->spr.pos.X += aLower->spr.pos.X - aUpper->spr.pos.X; + actor->spr.pos.Y += aLower->spr.pos.Y - aUpper->spr.pos.Y; + int z2; + if (aLower->spr.type == kMarkerLowLink) + z2 = aLower->spr.pos.Z; + else + z2 = getceilzofslopeptr(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y); + actor->spr.pos.Z += z2 - z; + actor->interpolated = false; + return aUpper->spr.type; + } + } + if (aLower) + { + int z; + if (aLower->spr.type == kMarkerLowLink) + z = aLower->spr.pos.Z; + else + z = getceilzofslopeptr(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y); + if (z >= actor->spr.pos.Z) + { + aUpper = aLower->GetOwner(); + assert(aUpper); + assert(aUpper->spr.insector()); + ChangeActorSect(actor, aUpper->spr.sector()); + actor->spr.pos.X += aUpper->spr.pos.X - aLower->spr.pos.X; + actor->spr.pos.Y += aUpper->spr.pos.Y - aLower->spr.pos.Y; + int z2; + if (aUpper->spr.type == kMarkerUpLink) + z2 = aUpper->spr.pos.Z; + else + z2 = getflorzofslopeptr(actor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y); + actor->spr.pos.Z += z2 - z; + actor->interpolated = false; + return aLower->spr.type; + } + } + return 0; } -int CheckLink(int *x, int *y, int *z, sectortype** pSector) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +int CheckLink(int* x, int* y, int* z, sectortype** pSector) { - auto aUpper = barrier_cast((*pSector)->upperLink); - auto aLower = barrier_cast((*pSector)->lowerLink); - if (aUpper) - { - int z1; - if (aUpper->spr.type == kMarkerUpLink) - z1 = aUpper->spr.pos.Z; - else - z1 = getflorzofslopeptr(*pSector, *x, *y); - if (z1 <= *z) - { - aLower = aUpper->GetOwner(); - assert(aLower); - assert(aLower->spr.insector()); - *pSector = aLower->spr.sector(); - *x += aLower->spr.pos.X - aUpper->spr.pos.X; - *y += aLower->spr.pos.Y - aUpper->spr.pos.Y; - int z2; - if (aUpper->spr.type == kMarkerLowLink) - z2 = aLower->spr.pos.Z; - else - z2 = getceilzofslopeptr(*pSector, *x, *y); - *z += z2-z1; - return aUpper->spr.type; - } - } - if (aLower) - { - int z1; - if (aLower->spr.type == kMarkerLowLink) - z1 = aLower->spr.pos.Z; - else - z1 = getceilzofslopeptr(*pSector, *x, *y); - if (z1 >= *z) - { - aUpper = aLower->GetOwner(); - assert(aUpper); - *pSector = aUpper->spr.sector(); - *x += aUpper->spr.pos.X - aLower->spr.pos.X; - *y += aUpper->spr.pos.Y - aLower->spr.pos.Y; - int z2; - if (aLower->spr.type == kMarkerUpLink) - z2 = aUpper->spr.pos.Z; - else - z2 = getflorzofslopeptr(*pSector, *x, *y); - *z += z2-z1; - return aLower->spr.type; - } - } - return 0; + auto aUpper = barrier_cast((*pSector)->upperLink); + auto aLower = barrier_cast((*pSector)->lowerLink); + if (aUpper) + { + int z1; + if (aUpper->spr.type == kMarkerUpLink) + z1 = aUpper->spr.pos.Z; + else + z1 = getflorzofslopeptr(*pSector, *x, *y); + if (z1 <= *z) + { + aLower = aUpper->GetOwner(); + assert(aLower); + assert(aLower->spr.insector()); + *pSector = aLower->spr.sector(); + *x += aLower->spr.pos.X - aUpper->spr.pos.X; + *y += aLower->spr.pos.Y - aUpper->spr.pos.Y; + int z2; + if (aUpper->spr.type == kMarkerLowLink) + z2 = aLower->spr.pos.Z; + else + z2 = getceilzofslopeptr(*pSector, *x, *y); + *z += z2 - z1; + return aUpper->spr.type; + } + } + if (aLower) + { + int z1; + if (aLower->spr.type == kMarkerLowLink) + z1 = aLower->spr.pos.Z; + else + z1 = getceilzofslopeptr(*pSector, *x, *y); + if (z1 >= *z) + { + aUpper = aLower->GetOwner(); + assert(aUpper); + *pSector = aUpper->spr.sector(); + *x += aUpper->spr.pos.X - aLower->spr.pos.X; + *y += aUpper->spr.pos.Y - aLower->spr.pos.Y; + int z2; + if (aLower->spr.type == kMarkerUpLink) + z2 = aUpper->spr.pos.Z; + else + z2 = getflorzofslopeptr(*pSector, *x, *y); + *z += z2 - z1; + return aLower->spr.type; + } + } + return 0; } //--------------------------------------------------------------------------- diff --git a/source/games/blood/src/weapon.cpp b/source/games/blood/src/weapon.cpp index 0a32e484d..8de5c144a 100644 --- a/source/games/blood/src/weapon.cpp +++ b/source/games/blood/src/weapon.cpp @@ -32,40 +32,40 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. BEGIN_BLD_NS -void FirePitchfork(int, PLAYER *pPlayer); -void FireSpray(int, PLAYER *pPlayer); -void ThrowCan(int, PLAYER *pPlayer); -void DropCan(int, PLAYER *pPlayer); -void ExplodeCan(int, PLAYER *pPlayer); -void ThrowBundle(int, PLAYER *pPlayer); -void DropBundle(int, PLAYER *pPlayer); -void ExplodeBundle(int, PLAYER *pPlayer); -void ThrowProx(int, PLAYER *pPlayer); -void DropProx(int, PLAYER *pPlayer); -void ThrowRemote(int, PLAYER *pPlayer); -void DropRemote(int, PLAYER *pPlayer); -void FireRemote(int, PLAYER *pPlayer); -void FireShotgun(int nTrigger, PLAYER *pPlayer); -void EjectShell(int, PLAYER *pPlayer); -void FireTommy(int nTrigger, PLAYER *pPlayer); -void FireSpread(int nTrigger, PLAYER *pPlayer); -void AltFireSpread(int nTrigger, PLAYER *pPlayer); -void AltFireSpread2(int nTrigger, PLAYER *pPlayer); -void FireFlare(int nTrigger, PLAYER *pPlayer); -void AltFireFlare(int nTrigger, PLAYER *pPlayer); -void FireVoodoo(int nTrigger, PLAYER *pPlayer); -void AltFireVoodoo(int nTrigger, PLAYER *pPlayer); -void DropVoodoo(int nTrigger, PLAYER *pPlayer); -void FireTesla(int nTrigger, PLAYER *pPlayer); -void AltFireTesla(int nTrigger, PLAYER *pPlayer); -void FireNapalm(int nTrigger, PLAYER *pPlayer); -void FireNapalm2(int nTrigger, PLAYER *pPlayer); -void AltFireNapalm(int nTrigger, PLAYER *pPlayer); -void FireLifeLeech(int nTrigger, PLAYER *pPlayer); -void AltFireLifeLeech(int nTrigger, PLAYER *pPlayer); -void FireBeast(int nTrigger, PLAYER * pPlayer); +void FirePitchfork(int, PLAYER* pPlayer); +void FireSpray(int, PLAYER* pPlayer); +void ThrowCan(int, PLAYER* pPlayer); +void DropCan(int, PLAYER* pPlayer); +void ExplodeCan(int, PLAYER* pPlayer); +void ThrowBundle(int, PLAYER* pPlayer); +void DropBundle(int, PLAYER* pPlayer); +void ExplodeBundle(int, PLAYER* pPlayer); +void ThrowProx(int, PLAYER* pPlayer); +void DropProx(int, PLAYER* pPlayer); +void ThrowRemote(int, PLAYER* pPlayer); +void DropRemote(int, PLAYER* pPlayer); +void FireRemote(int, PLAYER* pPlayer); +void FireShotgun(int nTrigger, PLAYER* pPlayer); +void EjectShell(int, PLAYER* pPlayer); +void FireTommy(int nTrigger, PLAYER* pPlayer); +void FireSpread(int nTrigger, PLAYER* pPlayer); +void AltFireSpread(int nTrigger, PLAYER* pPlayer); +void AltFireSpread2(int nTrigger, PLAYER* pPlayer); +void FireFlare(int nTrigger, PLAYER* pPlayer); +void AltFireFlare(int nTrigger, PLAYER* pPlayer); +void FireVoodoo(int nTrigger, PLAYER* pPlayer); +void AltFireVoodoo(int nTrigger, PLAYER* pPlayer); +void DropVoodoo(int nTrigger, PLAYER* pPlayer); +void FireTesla(int nTrigger, PLAYER* pPlayer); +void AltFireTesla(int nTrigger, PLAYER* pPlayer); +void FireNapalm(int nTrigger, PLAYER* pPlayer); +void FireNapalm2(int nTrigger, PLAYER* pPlayer); +void AltFireNapalm(int nTrigger, PLAYER* pPlayer); +void FireLifeLeech(int nTrigger, PLAYER* pPlayer); +void AltFireLifeLeech(int nTrigger, PLAYER* pPlayer); +void FireBeast(int nTrigger, PLAYER* pPlayer); -typedef void(*QAVTypeCast)(int, void *); +typedef void(*QAVTypeCast)(int, void*); void (*qavClientCallback[])(int, void*) = { @@ -105,2598 +105,2940 @@ void (*qavClientCallback[])(int, void*) = enum { - nClientFirePitchfork, - nClientFireSpray, - nClientThrowCan, - nClientDropCan, - nClientExplodeCan, - nClientThrowBundle, - nClientDropBundle, - nClientExplodeBundle, - nClientThrowProx, - nClientDropProx, - nClientThrowRemote, - nClientDropRemote, - nClientFireRemote, - nClientFireShotgun, - nClientEjectShell, - nClientFireTommy, - nClientAltFireSpread2, - nClientFireSpread, - nClientAltFireSpread, - nClientFireFlare, - nClientAltFireFlare, - nClientFireVoodoo, - nClientAltFireVoodoo, - nClientFireTesla, - nClientAltFireTesla, - nClientFireNapalm, - nClientFireNapalm2, - nClientFireLifeLeech, - nClientFireBeast, - nClientAltFireLifeLeech, - nClientDropVoodoo, - nClientAltFireNapalm, + nClientFirePitchfork, + nClientFireSpray, + nClientThrowCan, + nClientDropCan, + nClientExplodeCan, + nClientThrowBundle, + nClientDropBundle, + nClientExplodeBundle, + nClientThrowProx, + nClientDropProx, + nClientThrowRemote, + nClientDropRemote, + nClientFireRemote, + nClientFireShotgun, + nClientEjectShell, + nClientFireTommy, + nClientAltFireSpread2, + nClientFireSpread, + nClientAltFireSpread, + nClientFireFlare, + nClientAltFireFlare, + nClientFireVoodoo, + nClientAltFireVoodoo, + nClientFireTesla, + nClientAltFireTesla, + nClientFireNapalm, + nClientFireNapalm2, + nClientFireLifeLeech, + nClientFireBeast, + nClientAltFireLifeLeech, + nClientDropVoodoo, + nClientAltFireNapalm, }; -bool checkFired6or7(PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +bool checkFired6or7(PLAYER* pPlayer) { - switch (pPlayer->curWeapon) - { - case kWeapSpraycan: - switch (pPlayer->weaponState) - { - case 5: - case 6: - return 1; - case 7: - if (VanillaMode()) - return 0; - return 1; - } - break; - case kWeapDynamite: - switch (pPlayer->weaponState) - { - case 4: - case 5: - case 6: - return 1; - } - break; - } - return 0; + switch (pPlayer->curWeapon) + { + case kWeapSpraycan: + switch (pPlayer->weaponState) + { + case 5: + case 6: + return 1; + case 7: + if (VanillaMode()) + return 0; + return 1; + } + break; + case kWeapDynamite: + switch (pPlayer->weaponState) + { + case 4: + case 5: + case 6: + return 1; + } + break; + } + return 0; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + static bool BannedUnderwater(int nWeapon) { - return nWeapon == kWeapSpraycan || nWeapon == kWeapDynamite; + return nWeapon == kWeapSpraycan || nWeapon == kWeapDynamite; } -static bool CheckWeaponAmmo(PLAYER *pPlayer, int weapon, int ammotype, int count) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +static bool CheckWeaponAmmo(PLAYER* pPlayer, int weapon, int ammotype, int count) { - if (gInfiniteAmmo) - return 1; - if (ammotype == -1) - return 1; - if (weapon == kWeapRemote && pPlayer->weaponAmmo == 11 && pPlayer->weaponState == 11) - return 1; - if (weapon == kWeapLifeLeech && pPlayer->actor->xspr.health > 0) - return 1; - return pPlayer->ammoCount[ammotype] >= count; + if (gInfiniteAmmo) + return 1; + if (ammotype == -1) + return 1; + if (weapon == kWeapRemote && pPlayer->weaponAmmo == 11 && pPlayer->weaponState == 11) + return 1; + if (weapon == kWeapLifeLeech && pPlayer->actor->xspr.health > 0) + return 1; + return pPlayer->ammoCount[ammotype] >= count; } -static bool CheckAmmo(PLAYER *pPlayer, int ammotype, int count) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +static bool CheckAmmo(PLAYER* pPlayer, int ammotype, int count) { - if (gInfiniteAmmo) - return 1; - if (ammotype == -1) - return 1; - if (pPlayer->curWeapon == kWeapRemote && pPlayer->weaponAmmo == 11 && pPlayer->weaponState == 11) - return 1; - if (pPlayer->curWeapon == kWeapLifeLeech && pPlayer->actor->xspr.health >= unsigned(count<<4)) - return 1; - return pPlayer->ammoCount[ammotype] >= count; + if (gInfiniteAmmo) + return 1; + if (ammotype == -1) + return 1; + if (pPlayer->curWeapon == kWeapRemote && pPlayer->weaponAmmo == 11 && pPlayer->weaponState == 11) + return 1; + if (pPlayer->curWeapon == kWeapLifeLeech && pPlayer->actor->xspr.health >= unsigned(count << 4)) + return 1; + return pPlayer->ammoCount[ammotype] >= count; } -static bool checkAmmo2(const PLAYER *pPlayer, int ammotype, int amount) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +static bool checkAmmo2(const PLAYER* pPlayer, int ammotype, int amount) { - if (gInfiniteAmmo) - return 1; - if (ammotype == -1) - return 1; - return pPlayer->ammoCount[ammotype] >= amount; + if (gInfiniteAmmo) + return 1; + if (ammotype == -1) + return 1; + return pPlayer->ammoCount[ammotype] >= amount; } -void SpawnBulletEject(PLAYER *pPlayer, int a2, int a3) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void SpawnBulletEject(PLAYER* pPlayer, int a2, int a3) { - POSTURE *pPosture = &pPlayer->pPosture[pPlayer->lifeMode][pPlayer->posture]; - pPlayer->zView = pPlayer->actor->spr.pos.Z-pPosture->eyeAboveZ; - int dz = pPlayer->zWeapon-(pPlayer->zWeapon-pPlayer->zView)/2; - fxSpawnEjectingBrass(pPlayer->actor, dz, a2, a3); + POSTURE* pPosture = &pPlayer->pPosture[pPlayer->lifeMode][pPlayer->posture]; + pPlayer->zView = pPlayer->actor->spr.pos.Z - pPosture->eyeAboveZ; + int dz = pPlayer->zWeapon - (pPlayer->zWeapon - pPlayer->zView) / 2; + fxSpawnEjectingBrass(pPlayer->actor, dz, a2, a3); } -void SpawnShellEject(PLAYER *pPlayer, int a2, int a3) +void SpawnShellEject(PLAYER* pPlayer, int a2, int a3) { - POSTURE *pPosture = &pPlayer->pPosture[pPlayer->lifeMode][pPlayer->posture]; - pPlayer->zView = pPlayer->actor->spr.pos.Z-pPosture->eyeAboveZ; - int t = pPlayer->zWeapon - pPlayer->zView; - int dz = pPlayer->zWeapon-t+(t>>2); - fxSpawnEjectingShell(pPlayer->actor, dz, a2, a3); + POSTURE* pPosture = &pPlayer->pPosture[pPlayer->lifeMode][pPlayer->posture]; + pPlayer->zView = pPlayer->actor->spr.pos.Z - pPosture->eyeAboveZ; + int t = pPlayer->zWeapon - pPlayer->zView; + int dz = pPlayer->zWeapon - t + (t >> 2); + fxSpawnEjectingShell(pPlayer->actor, dz, a2, a3); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void WeaponInit(void) { - 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); - } - }; + 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); + } + }; - doInit(0); - doInit(10000); + doInit(0); + doInit(10000); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void WeaponPrecache() { - auto doPrecache = [](const int base) - { - for (int i = base; i < (kQAVEnd + base); i++) - { - auto pQAV = getQAV(i); - if (pQAV) - pQAV->Precache(); - } - }; + 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); + doPrecache(0); + doPrecache(10000); } -void WeaponDraw(PLAYER *pPlayer, int shade, double xpos, double ypos, int palnum) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void WeaponDraw(PLAYER* pPlayer, int shade, double xpos, double ypos, int palnum) { - assert(pPlayer != NULL); - if (pPlayer->weaponQav == kQAVNone) - return; - auto pQAV = getQAV(pPlayer->weaponQav); - int duration; - double smoothratio; + assert(pPlayer != NULL); + if (pPlayer->weaponQav == kQAVNone) + return; + auto pQAV = getQAV(pPlayer->weaponQav); + 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); - int flags = 2; - int nInv = powerupCheck(pPlayer, kPwUpShadowCloak); - if (nInv >= 120 * 8 || (nInv != 0 && (PlayClock & 32))) - { - shade = -128; - flags |= 1; - } - pQAV->Draw(xpos, ypos, duration, flags, shade, palnum, true, smoothratio); + pQAV->x = int(xpos); + pQAV->y = int(ypos); + int flags = 2; + int nInv = powerupCheck(pPlayer, kPwUpShadowCloak); + if (nInv >= 120 * 8 || (nInv != 0 && (PlayClock & 32))) + { + shade = -128; + flags |= 1; + } + pQAV->Draw(xpos, ypos, duration, flags, shade, palnum, true, smoothratio); } -void WeaponPlay(PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void WeaponPlay(PLAYER* pPlayer) { - assert(pPlayer != NULL); - if (pPlayer->weaponQav == kQAVNone) - return; - auto pQAV = getQAV(pPlayer->weaponQav); - int nTicks = pQAV->duration - pPlayer->weaponTimer; - pQAV->Play(nTicks-4, nTicks, pPlayer->qavCallback, pPlayer); + assert(pPlayer != NULL); + if (pPlayer->weaponQav == kQAVNone) + return; + auto pQAV = getQAV(pPlayer->weaponQav); + int nTicks = pQAV->duration - pPlayer->weaponTimer; + pQAV->Play(nTicks - 4, nTicks, pPlayer->qavCallback, pPlayer); } -static void StartQAV(PLAYER *pPlayer, int nWeaponQAV, int callback = -1, bool looped = false) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +static void StartQAV(PLAYER* pPlayer, int nWeaponQAV, int callback = -1, bool looped = false) { - assert(nWeaponQAV < kQAVEnd); - auto res_id = qavGetCorrectID(nWeaponQAV); - auto pQAV = getQAV(res_id); - pPlayer->weaponQav = res_id; - pPlayer->weaponTimer = pQAV->duration; - pPlayer->qavCallback = callback; - pPlayer->qavLoop = looped; - pPlayer->qavLastTick = I_GetTime(pQAV->ticrate); - pPlayer->qavTimer = pQAV->duration; - //pQAV->Preload(); - WeaponPlay(pPlayer); - pPlayer->weaponTimer -= 4; + assert(nWeaponQAV < kQAVEnd); + auto res_id = qavGetCorrectID(nWeaponQAV); + auto pQAV = getQAV(res_id); + pPlayer->weaponQav = res_id; + pPlayer->weaponTimer = pQAV->duration; + pPlayer->qavCallback = callback; + pPlayer->qavLoop = looped; + pPlayer->qavLastTick = I_GetTime(pQAV->ticrate); + pPlayer->qavTimer = pQAV->duration; + //pQAV->Preload(); + WeaponPlay(pPlayer); + pPlayer->weaponTimer -= 4; } -static void SetQAV(PLAYER *pPlayer, int nWeaponQAV) +static void SetQAV(PLAYER* pPlayer, int nWeaponQAV) { - assert(nWeaponQAV < kQAVEnd); - pPlayer->weaponQav = qavGetCorrectID(nWeaponQAV); - pPlayer->qavTimer = 0; - pPlayer->qavLastTick = 0; + assert(nWeaponQAV < kQAVEnd); + pPlayer->weaponQav = qavGetCorrectID(nWeaponQAV); + pPlayer->qavTimer = 0; + pPlayer->qavLastTick = 0; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + struct WEAPONTRACK { - int aimSpeedHorz; - int aimSpeedVert; - int angleRange; - int thingAngle; - int seeker; - bool bIsProjectile; + int aimSpeedHorz; + int aimSpeedVert; + int angleRange; + int thingAngle; + int seeker; + bool bIsProjectile; }; WEAPONTRACK gWeaponTrack[] = { - { 0, 0, 0, 0, 0, false }, - { 0x6000, 0x6000, 0x71, 0x55, 0x111111, false }, - { 0x8000, 0x8000, 0x71, 0x55, 0x2aaaaa, true }, - { 0x10000, 0x10000, 0x38, 0x1c, 0, false }, - { 0x6000, 0x8000, 0x38, 0x1c, 0, false }, - { 0x6000, 0x6000, 0x38, 0x1c, 0x2aaaaa, true }, - { 0x6000, 0x6000, 0x71, 0x55, 0, true }, - { 0x6000, 0x6000, 0x71, 0x38, 0, true }, - { 0x8000, 0x10000, 0x71, 0x55, 0x255555, true }, - { 0x10000, 0x10000, 0x71, 0, 0, true }, - { 0x10000, 0x10000, 0xaa, 0, 0, false }, - { 0x6000, 0x6000, 0x71, 0x55, 0, true }, - { 0x6000, 0x6000, 0x71, 0x55, 0, true }, - { 0x6000, 0x6000, 0x71, 0x55, 0, false }, + { 0, 0, 0, 0, 0, false }, + { 0x6000, 0x6000, 0x71, 0x55, 0x111111, false }, + { 0x8000, 0x8000, 0x71, 0x55, 0x2aaaaa, true }, + { 0x10000, 0x10000, 0x38, 0x1c, 0, false }, + { 0x6000, 0x8000, 0x38, 0x1c, 0, false }, + { 0x6000, 0x6000, 0x38, 0x1c, 0x2aaaaa, true }, + { 0x6000, 0x6000, 0x71, 0x55, 0, true }, + { 0x6000, 0x6000, 0x71, 0x38, 0, true }, + { 0x8000, 0x10000, 0x71, 0x55, 0x255555, true }, + { 0x10000, 0x10000, 0x71, 0, 0, true }, + { 0x10000, 0x10000, 0xaa, 0, 0, false }, + { 0x6000, 0x6000, 0x71, 0x55, 0, true }, + { 0x6000, 0x6000, 0x71, 0x55, 0, true }, + { 0x6000, 0x6000, 0x71, 0x55, 0, false }, }; -void UpdateAimVector(PLAYER * pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void UpdateAimVector(PLAYER* pPlayer) { - assert(pPlayer != NULL); - auto plActor = pPlayer->actor; - int x = plActor->spr.pos.X; - int y = plActor->spr.pos.Y; - int z = pPlayer->zWeapon; - Aim aim; - aim.dx = bcos(plActor->spr.ang); - aim.dy = bsin(plActor->spr.ang); - aim.dz = pPlayer->slope; - WEAPONTRACK *pWeaponTrack = &gWeaponTrack[pPlayer->curWeapon]; - DBloodActor* targetactor = nullptr; - pPlayer->aimTargetsCount = 0; - int autoaim = Autoaim(pPlayer->nPlayer); - if (autoaim == 1 || (autoaim == 2 && !pWeaponTrack->bIsProjectile) || pPlayer->curWeapon == kWeapVoodooDoll || pPlayer->curWeapon == kWeapLifeLeech) - { - int nClosest = 0x7fffffff; - BloodStatIterator it(kStatDude); - while (auto actor = it.Next()) - { - if (plActor == actor) - continue; - if (!gGameOptions.bFriendlyFire && IsTargetTeammate(pPlayer, actor)) - continue; - if (actor->spr.flags&32) - continue; - if (!(actor->spr.flags&8)) - continue; - int x2 = actor->spr.pos.X; - int y2 = actor->spr.pos.Y; - int z2 = actor->spr.pos.Z; - int nDist = approxDist(x2-x, y2-y); - if (nDist == 0 || nDist > 51200) - continue; - if (pWeaponTrack->seeker) - { - int t = DivScale(nDist, pWeaponTrack->seeker, 12); - x2 += (actor->xvel * t) >> 12; - y2 += (actor->yvel * t) >> 12; - z2 += (actor->zvel * t) >> 8; - } - int lx = x + MulScale(Cos(plActor->spr.ang), nDist, 30); - int ly = y + MulScale(Sin(plActor->spr.ang), nDist, 30); - int lz = z + MulScale(pPlayer->slope, nDist, 10); - int zRange = MulScale(9460, nDist, 10); - int top, bottom; - GetActorExtents(actor, &top, &bottom); - if (lz-zRange>bottom || lz+zRangespr.ang+1024)&2047)-1024) > pWeaponTrack->angleRange) - continue; - if (pPlayer->aimTargetsCount < 16 && cansee(x,y,z,plActor->spr.sector(),x2,y2,z2,actor->spr.sector())) - pPlayer->aimTargets[pPlayer->aimTargetsCount++] = actor; - // Inlined? - int dz = (lz-z2)>>8; - int dy = (ly-y2)>>4; - int dx = (lx-x2)>>4; - int nDist2 = ksqrt(dx*dx+dy*dy+dz*dz); - if (nDist2 >= nClosest) - continue; - DUDEINFO *pDudeInfo = getDudeInfo(actor->spr.type); - int center = (actor->spr.yrepeat*pDudeInfo->aimHeight)<<2; - int dzCenter = (z2-center)-z; - if (cansee(x, y, z, plActor->spr.sector(), x2, y2, z2, actor->spr.sector())) - { - nClosest = nDist2; - aim.dx = bcos(angle); - aim.dy = bsin(angle); - aim.dz = DivScale(dzCenter, nDist, 10); - targetactor = actor; - } - } - if (pWeaponTrack->thingAngle > 0) - { - BloodStatIterator itr(kStatThing); - while (auto actor = itr.Next()) - { - if (!gGameOptions.bFriendlyFire && IsTargetTeammate(pPlayer, actor)) - continue; - if (!(actor->spr.flags&8)) - continue; - int x2 = actor->spr.pos.X; - int y2 = actor->spr.pos.Y; - int z2 = actor->spr.pos.Z; - int dx = x2-x; - int dy = y2-y; - int dz = z2-z; - int nDist = approxDist(dx, dy); - if (nDist == 0 || nDist > 51200) - continue; - int lx = x + MulScale(Cos(plActor->spr.ang), nDist, 30); - int ly = y + MulScale(Sin(plActor->spr.ang), nDist, 30); - int lz = z + MulScale(pPlayer->slope, nDist, 10); - int zRange = MulScale(9460, nDist, 10); - int top, bottom; - GetActorExtents(actor, &top, &bottom); - if (lz-zRange>bottom || lz+zRangespr.ang+1024)&2047)-1024) > pWeaponTrack->thingAngle) - continue; - if (pPlayer->aimTargetsCount < 16 && cansee(x,y,z,plActor->spr.sector(),actor->spr.pos.X,actor->spr.pos.Y,actor->spr.pos.Z,actor->spr.sector())) - pPlayer->aimTargets[pPlayer->aimTargetsCount++] = actor; - // Inlined? - int dz2 = (lz-z2)>>8; - int dy2 = (ly-y2)>>4; - int dx2 = (lx-x2)>>4; - int nDist2 = ksqrt(dx2*dx2+dy2*dy2+dz2*dz2); - if (nDist2 >= nClosest) - continue; - if (cansee(x, y, z, plActor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z, actor->spr.sector())) - { - nClosest = nDist2; - aim.dx = bcos(angle); - aim.dy = bsin(angle); - aim.dz = DivScale(dz, nDist, 10); - targetactor = actor; - } - } - } - } - Aim aim2; - aim2 = aim; - RotateVector((int*)&aim2.dx, (int*)&aim2.dy, -plActor->spr.ang); - aim2.dz -= pPlayer->slope; - pPlayer->relAim.dx = interpolatedvalue(pPlayer->relAim.dx, aim2.dx, pWeaponTrack->aimSpeedHorz); - pPlayer->relAim.dy = interpolatedvalue(pPlayer->relAim.dy, aim2.dy, pWeaponTrack->aimSpeedHorz); - pPlayer->relAim.dz = interpolatedvalue(pPlayer->relAim.dz, aim2.dz, pWeaponTrack->aimSpeedVert); - pPlayer->aim = pPlayer->relAim; - RotateVector((int*)&pPlayer->aim.dx, (int*)&pPlayer->aim.dy, plActor->spr.ang); - pPlayer->aim.dz += pPlayer->slope; - pPlayer->aimTarget = targetactor; + assert(pPlayer != NULL); + auto plActor = pPlayer->actor; + int x = plActor->spr.pos.X; + int y = plActor->spr.pos.Y; + int z = pPlayer->zWeapon; + Aim aim; + aim.dx = bcos(plActor->spr.ang); + aim.dy = bsin(plActor->spr.ang); + aim.dz = pPlayer->slope; + WEAPONTRACK* pWeaponTrack = &gWeaponTrack[pPlayer->curWeapon]; + DBloodActor* targetactor = nullptr; + pPlayer->aimTargetsCount = 0; + int autoaim = Autoaim(pPlayer->nPlayer); + if (autoaim == 1 || (autoaim == 2 && !pWeaponTrack->bIsProjectile) || pPlayer->curWeapon == kWeapVoodooDoll || pPlayer->curWeapon == kWeapLifeLeech) + { + int nClosest = 0x7fffffff; + BloodStatIterator it(kStatDude); + while (auto actor = it.Next()) + { + if (plActor == actor) + continue; + if (!gGameOptions.bFriendlyFire && IsTargetTeammate(pPlayer, actor)) + continue; + if (actor->spr.flags & 32) + continue; + if (!(actor->spr.flags & 8)) + continue; + int x2 = actor->spr.pos.X; + int y2 = actor->spr.pos.Y; + int z2 = actor->spr.pos.Z; + int nDist = approxDist(x2 - x, y2 - y); + if (nDist == 0 || nDist > 51200) + continue; + if (pWeaponTrack->seeker) + { + int t = DivScale(nDist, pWeaponTrack->seeker, 12); + x2 += (actor->xvel * t) >> 12; + y2 += (actor->yvel * t) >> 12; + z2 += (actor->zvel * t) >> 8; + } + int lx = x + MulScale(Cos(plActor->spr.ang), nDist, 30); + int ly = y + MulScale(Sin(plActor->spr.ang), nDist, 30); + int lz = z + MulScale(pPlayer->slope, nDist, 10); + int zRange = MulScale(9460, nDist, 10); + int top, bottom; + GetActorExtents(actor, &top, &bottom); + if (lz - zRange > bottom || lz + zRange < top) + continue; + int angle = getangle(x2 - x, y2 - y); + if (abs(((angle - plActor->spr.ang + 1024) & 2047) - 1024) > pWeaponTrack->angleRange) + continue; + if (pPlayer->aimTargetsCount < 16 && cansee(x, y, z, plActor->spr.sector(), x2, y2, z2, actor->spr.sector())) + pPlayer->aimTargets[pPlayer->aimTargetsCount++] = actor; + // Inlined? + int dz = (lz - z2) >> 8; + int dy = (ly - y2) >> 4; + int dx = (lx - x2) >> 4; + int nDist2 = ksqrt(dx * dx + dy * dy + dz * dz); + if (nDist2 >= nClosest) + continue; + DUDEINFO* pDudeInfo = getDudeInfo(actor->spr.type); + int center = (actor->spr.yrepeat * pDudeInfo->aimHeight) << 2; + int dzCenter = (z2 - center) - z; + if (cansee(x, y, z, plActor->spr.sector(), x2, y2, z2, actor->spr.sector())) + { + nClosest = nDist2; + aim.dx = bcos(angle); + aim.dy = bsin(angle); + aim.dz = DivScale(dzCenter, nDist, 10); + targetactor = actor; + } + } + if (pWeaponTrack->thingAngle > 0) + { + BloodStatIterator itr(kStatThing); + while (auto actor = itr.Next()) + { + if (!gGameOptions.bFriendlyFire && IsTargetTeammate(pPlayer, actor)) + continue; + if (!(actor->spr.flags & 8)) + continue; + int x2 = actor->spr.pos.X; + int y2 = actor->spr.pos.Y; + int z2 = actor->spr.pos.Z; + int dx = x2 - x; + int dy = y2 - y; + int dz = z2 - z; + int nDist = approxDist(dx, dy); + if (nDist == 0 || nDist > 51200) + continue; + int lx = x + MulScale(Cos(plActor->spr.ang), nDist, 30); + int ly = y + MulScale(Sin(plActor->spr.ang), nDist, 30); + int lz = z + MulScale(pPlayer->slope, nDist, 10); + int zRange = MulScale(9460, nDist, 10); + int top, bottom; + GetActorExtents(actor, &top, &bottom); + if (lz - zRange > bottom || lz + zRange < top) + continue; + int angle = getangle(dx, dy); + if (abs(((angle - plActor->spr.ang + 1024) & 2047) - 1024) > pWeaponTrack->thingAngle) + continue; + if (pPlayer->aimTargetsCount < 16 && cansee(x, y, z, plActor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z, actor->spr.sector())) + pPlayer->aimTargets[pPlayer->aimTargetsCount++] = actor; + // Inlined? + int dz2 = (lz - z2) >> 8; + int dy2 = (ly - y2) >> 4; + int dx2 = (lx - x2) >> 4; + int nDist2 = ksqrt(dx2 * dx2 + dy2 * dy2 + dz2 * dz2); + if (nDist2 >= nClosest) + continue; + if (cansee(x, y, z, plActor->spr.sector(), actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z, actor->spr.sector())) + { + nClosest = nDist2; + aim.dx = bcos(angle); + aim.dy = bsin(angle); + aim.dz = DivScale(dz, nDist, 10); + targetactor = actor; + } + } + } + } + Aim aim2; + aim2 = aim; + RotateVector((int*)&aim2.dx, (int*)&aim2.dy, -plActor->spr.ang); + aim2.dz -= pPlayer->slope; + pPlayer->relAim.dx = interpolatedvalue(pPlayer->relAim.dx, aim2.dx, pWeaponTrack->aimSpeedHorz); + pPlayer->relAim.dy = interpolatedvalue(pPlayer->relAim.dy, aim2.dy, pWeaponTrack->aimSpeedHorz); + pPlayer->relAim.dz = interpolatedvalue(pPlayer->relAim.dz, aim2.dz, pWeaponTrack->aimSpeedVert); + pPlayer->aim = pPlayer->relAim; + RotateVector((int*)&pPlayer->aim.dx, (int*)&pPlayer->aim.dy, plActor->spr.ang); + pPlayer->aim.dz += pPlayer->slope; + pPlayer->aimTarget = targetactor; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + struct t_WeaponModes { - int update; - int ammoType; + int update; + int ammoType; }; t_WeaponModes weaponModes[] = { - { 0, -1 }, - { 1, -1 }, - { 1, 1 }, - { 1, 2 }, - { 1, 3 }, - { 1, 4 }, - { 1, 5 }, - { 1, 6 }, - { 1, 7 }, - { 1, 8 }, - { 1, 9 }, - { 1, 10 }, - { 1, 11 }, - { 0, -1 }, + { 0, -1 }, + { 1, -1 }, + { 1, 1 }, + { 1, 2 }, + { 1, 3 }, + { 1, 4 }, + { 1, 5 }, + { 1, 6 }, + { 1, 7 }, + { 1, 8 }, + { 1, 9 }, + { 1, 10 }, + { 1, 11 }, + { 0, -1 }, }; -void WeaponRaise(PLAYER *pPlayer) +void WeaponRaise(PLAYER* pPlayer) { - assert(pPlayer != NULL); - int prevWeapon = pPlayer->curWeapon; - pPlayer->curWeapon = pPlayer->newWeapon; - pPlayer->newWeapon = kWeapNone; - pPlayer->weaponAmmo = weaponModes[pPlayer->curWeapon].ammoType; - switch (pPlayer->curWeapon) - { - case kWeapPitchFork: - pPlayer->weaponState = 0; - StartQAV(pPlayer, kQAVFORKUP); - break; - case kWeapSpraycan: - if (pPlayer->weaponState == 2) - { - pPlayer->weaponState = 3; - StartQAV(pPlayer, kQAVCANPREF); - } - else - { - pPlayer->weaponState = 0; - StartQAV(pPlayer, kQAVLITEOPEN); - } - break; - case kWeapDynamite: - if (gInfiniteAmmo || checkAmmo2(pPlayer, 5, 1)) - { - pPlayer->weaponState = 3; - if (prevWeapon == kWeapSpraycan) - StartQAV(pPlayer, kQAVBUNUP); - else - StartQAV(pPlayer, kQAVBUNUP2); - } - break; - case kWeapProximity: - if (gInfiniteAmmo || checkAmmo2(pPlayer, 10, 1)) - { - pPlayer->weaponState = 7; - StartQAV(pPlayer, kQAVPROXUP); - } - break; - case kWeapRemote: - if (gInfiniteAmmo || checkAmmo2(pPlayer, 11, 1)) - { - pPlayer->weaponState = 10; - StartQAV(pPlayer, kQAVREMUP2); - } - else - { - StartQAV(pPlayer, kQAVREMUP3); - pPlayer->weaponState = 11; - } - break; - case kWeapShotgun: - if (powerupCheck(pPlayer, kPwUpTwoGuns)) - { - if (gInfiniteAmmo || pPlayer->ammoCount[2] >= 4) - StartQAV(pPlayer, kQAV2SHOTUP); - else - StartQAV(pPlayer, kQAVSHOTUP); - if (gInfiniteAmmo || pPlayer->ammoCount[2] >= 4) - pPlayer->weaponState = 7; - else if (pPlayer->ammoCount[2] > 1) - pPlayer->weaponState = 3; - else if (pPlayer->ammoCount[2] > 0) - pPlayer->weaponState = 2; - else - pPlayer->weaponState = 1; - } - else - { - if (gInfiniteAmmo || pPlayer->ammoCount[2] > 1) - pPlayer->weaponState = 3; - else if (pPlayer->ammoCount[2] > 0) - pPlayer->weaponState = 2; - else - pPlayer->weaponState = 1; - StartQAV(pPlayer, kQAVSHOTUP); - } - break; - case kWeapTommyGun: - if (powerupCheck(pPlayer, kPwUpTwoGuns) && checkAmmo2(pPlayer, 3, 2)) - { - pPlayer->weaponState = 1; - StartQAV(pPlayer, kQAV2TOMUP); - } - else - { - pPlayer->weaponState = 0; - StartQAV(pPlayer, kQAVTOMUP); - } - break; - case kWeapVoodooDoll: - if (gInfiniteAmmo || checkAmmo2(pPlayer, 9, 1)) - { - pPlayer->weaponState = 2; - StartQAV(pPlayer, kQAVVDUP); - } - break; - case kWeapFlareGun: - if (powerupCheck(pPlayer, kPwUpTwoGuns) && checkAmmo2(pPlayer, 1, 2)) - { - StartQAV(pPlayer, kQAVFLAR2UP); - pPlayer->weaponState = 3; - } - else - { - StartQAV(pPlayer, kQAVFLARUP); - pPlayer->weaponState = 2; - } - break; - case kWeapTeslaCannon: - if (checkAmmo2(pPlayer, 7, 1)) - { - pPlayer->weaponState = 2; - if (powerupCheck(pPlayer, kPwUpTwoGuns)) - StartQAV(pPlayer, kQAV2SGUNUP); - else - StartQAV(pPlayer, kQAVSGUNUP); - } - else - { - pPlayer->weaponState = 3; - StartQAV(pPlayer, kQAVSGUNUP); - } - break; - case kWeapNapalm: - if (powerupCheck(pPlayer, kPwUpTwoGuns)) - { - StartQAV(pPlayer, kQAV2NAPUP); - pPlayer->weaponState = 3; - } - else - { - StartQAV(pPlayer, kQAVNAPUP); - pPlayer->weaponState = 2; - } - break; - case kWeapLifeLeech: - pPlayer->weaponState = 2; - StartQAV(pPlayer, kQAVSTAFUP); - break; - case kWeapBeast: - pPlayer->weaponState = 2; - StartQAV(pPlayer, kQAVBSTUP); - break; - } + assert(pPlayer != NULL); + int prevWeapon = pPlayer->curWeapon; + pPlayer->curWeapon = pPlayer->newWeapon; + pPlayer->newWeapon = kWeapNone; + pPlayer->weaponAmmo = weaponModes[pPlayer->curWeapon].ammoType; + switch (pPlayer->curWeapon) + { + case kWeapPitchFork: + pPlayer->weaponState = 0; + StartQAV(pPlayer, kQAVFORKUP); + break; + case kWeapSpraycan: + if (pPlayer->weaponState == 2) + { + pPlayer->weaponState = 3; + StartQAV(pPlayer, kQAVCANPREF); + } + else + { + pPlayer->weaponState = 0; + StartQAV(pPlayer, kQAVLITEOPEN); + } + break; + case kWeapDynamite: + if (gInfiniteAmmo || checkAmmo2(pPlayer, 5, 1)) + { + pPlayer->weaponState = 3; + if (prevWeapon == kWeapSpraycan) + StartQAV(pPlayer, kQAVBUNUP); + else + StartQAV(pPlayer, kQAVBUNUP2); + } + break; + case kWeapProximity: + if (gInfiniteAmmo || checkAmmo2(pPlayer, 10, 1)) + { + pPlayer->weaponState = 7; + StartQAV(pPlayer, kQAVPROXUP); + } + break; + case kWeapRemote: + if (gInfiniteAmmo || checkAmmo2(pPlayer, 11, 1)) + { + pPlayer->weaponState = 10; + StartQAV(pPlayer, kQAVREMUP2); + } + else + { + StartQAV(pPlayer, kQAVREMUP3); + pPlayer->weaponState = 11; + } + break; + case kWeapShotgun: + if (powerupCheck(pPlayer, kPwUpTwoGuns)) + { + if (gInfiniteAmmo || pPlayer->ammoCount[2] >= 4) + StartQAV(pPlayer, kQAV2SHOTUP); + else + StartQAV(pPlayer, kQAVSHOTUP); + if (gInfiniteAmmo || pPlayer->ammoCount[2] >= 4) + pPlayer->weaponState = 7; + else if (pPlayer->ammoCount[2] > 1) + pPlayer->weaponState = 3; + else if (pPlayer->ammoCount[2] > 0) + pPlayer->weaponState = 2; + else + pPlayer->weaponState = 1; + } + else + { + if (gInfiniteAmmo || pPlayer->ammoCount[2] > 1) + pPlayer->weaponState = 3; + else if (pPlayer->ammoCount[2] > 0) + pPlayer->weaponState = 2; + else + pPlayer->weaponState = 1; + StartQAV(pPlayer, kQAVSHOTUP); + } + break; + case kWeapTommyGun: + if (powerupCheck(pPlayer, kPwUpTwoGuns) && checkAmmo2(pPlayer, 3, 2)) + { + pPlayer->weaponState = 1; + StartQAV(pPlayer, kQAV2TOMUP); + } + else + { + pPlayer->weaponState = 0; + StartQAV(pPlayer, kQAVTOMUP); + } + break; + case kWeapVoodooDoll: + if (gInfiniteAmmo || checkAmmo2(pPlayer, 9, 1)) + { + pPlayer->weaponState = 2; + StartQAV(pPlayer, kQAVVDUP); + } + break; + case kWeapFlareGun: + if (powerupCheck(pPlayer, kPwUpTwoGuns) && checkAmmo2(pPlayer, 1, 2)) + { + StartQAV(pPlayer, kQAVFLAR2UP); + pPlayer->weaponState = 3; + } + else + { + StartQAV(pPlayer, kQAVFLARUP); + pPlayer->weaponState = 2; + } + break; + case kWeapTeslaCannon: + if (checkAmmo2(pPlayer, 7, 1)) + { + pPlayer->weaponState = 2; + if (powerupCheck(pPlayer, kPwUpTwoGuns)) + StartQAV(pPlayer, kQAV2SGUNUP); + else + StartQAV(pPlayer, kQAVSGUNUP); + } + else + { + pPlayer->weaponState = 3; + StartQAV(pPlayer, kQAVSGUNUP); + } + break; + case kWeapNapalm: + if (powerupCheck(pPlayer, kPwUpTwoGuns)) + { + StartQAV(pPlayer, kQAV2NAPUP); + pPlayer->weaponState = 3; + } + else + { + StartQAV(pPlayer, kQAVNAPUP); + pPlayer->weaponState = 2; + } + break; + case kWeapLifeLeech: + pPlayer->weaponState = 2; + StartQAV(pPlayer, kQAVSTAFUP); + break; + case kWeapBeast: + pPlayer->weaponState = 2; + StartQAV(pPlayer, kQAVBSTUP); + break; + } } -void WeaponLower(PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void WeaponLower(PLAYER* pPlayer) { - assert(pPlayer != NULL); - if (checkFired6or7(pPlayer)) - return; - pPlayer->throwPower = 0; - int prevState = pPlayer->weaponState; - switch (pPlayer->curWeapon) - { - case kWeapPitchFork: - StartQAV(pPlayer, kQAVFORKDOWN); - break; - case kWeapSpraycan: - sfxKill3DSound(pPlayer->actor, -1, 441); - switch (prevState) - { - case 1: - if (VanillaMode()) - { - StartQAV(pPlayer, kQAVLITECLO2); - } - else - { - if (pPlayer->newWeapon == kWeapDynamite) // do not put away lighter if TNT was selected while throwing a spray can - { - pPlayer->weaponState = 2; - StartQAV(pPlayer, kQAVCANDOWN); - WeaponRaise(pPlayer); - return; - } - } - break; - case 2: - pPlayer->weaponState = 1; - WeaponRaise(pPlayer); - return; - case 4: - pPlayer->weaponState = 1; - StartQAV(pPlayer, kQAVCANDOWN); - if (VanillaMode()) - { - pPlayer->newWeapon = kWeapNone; - WeaponLower(pPlayer); - } - else - { - if (pPlayer->newWeapon == kWeapDynamite) - { - pPlayer->weaponState = 2; - StartQAV(pPlayer, kQAVCANDOWN); - return; - } - else - { - WeaponLower(pPlayer); - } - } - break; - case 3: - if (pPlayer->newWeapon == kWeapDynamite) - { - pPlayer->weaponState = 2; - StartQAV(pPlayer, kQAVCANDOWN); - return; - } - else if (pPlayer->newWeapon == kWeapSpraycan) - { - pPlayer->weaponState = 1; - StartQAV(pPlayer, kQAVCANDOWN); - pPlayer->newWeapon = kWeapNone; - WeaponLower(pPlayer); - } - else - { - pPlayer->weaponState = 1; - StartQAV(pPlayer, kQAVCANDOWN); - } - break; - case 7: // throwing ignited alt fire spray - if (VanillaMode() || (pPlayer->newWeapon != 0)) - break; - pPlayer->weaponState = 1; - StartQAV(pPlayer, kQAVCANDOWN); - break; - } - break; - case kWeapDynamite: - switch (prevState) - { - case 1: - if (VanillaMode()) - { - StartQAV(pPlayer, kQAVLITECLO2); - } - else - { - if (pPlayer->newWeapon == kWeapSpraycan) // do not put away lighter if TNT was selected while throwing a spray can - { - pPlayer->weaponState = 2; - StartQAV(pPlayer, kQAVCANDOWN); - WeaponRaise(pPlayer); - return; - } - } - break; - case 2: - WeaponRaise(pPlayer); - break; - case 3: - if (pPlayer->newWeapon == kWeapSpraycan) - { - pPlayer->weaponState = 2; - StartQAV(pPlayer, kQAVBUNDOWN); - } - else - { - StartQAV(pPlayer, kQAVBUNDOWN2); - } - break; - default: - break; - } - break; - case kWeapProximity: - switch (prevState) - { - case 7: - StartQAV(pPlayer, kQAVPROXDOWN); - break; - } - break; - case kWeapRemote: - switch (prevState) - { - case 10: - StartQAV(pPlayer, kQAVREMDOWN2); - break; - case 11: - StartQAV(pPlayer, kQAVREMDOWN3); - break; - } - break; - case kWeapShotgun: - if (powerupCheck(pPlayer, kPwUpTwoGuns)) - StartQAV(pPlayer, kQAV2SHOTDWN); - else - StartQAV(pPlayer, kQAVSHOTDOWN); - break; - case kWeapTommyGun: - if (powerupCheck(pPlayer, kPwUpTwoGuns) && pPlayer->weaponState == 1) - StartQAV(pPlayer, kQAV2TOMDOWN); - else - StartQAV(pPlayer, kQAVTOMDOWN); - break; - case kWeapFlareGun: - if (powerupCheck(pPlayer, kPwUpTwoGuns) && pPlayer->weaponState == 3) - StartQAV(pPlayer, kQAVFLAR2DWN); - else - StartQAV(pPlayer, kQAVFLARDOWN); - break; - case kWeapVoodooDoll: - StartQAV(pPlayer, kQAVVDDOWN); - break; - case kWeapTeslaCannon: - if (checkAmmo2(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns)) - StartQAV(pPlayer, kQAV2SGUNDWN); - else - StartQAV(pPlayer, kQAVSGUNDOWN); - break; - case kWeapNapalm: - if (powerupCheck(pPlayer, kPwUpTwoGuns)) - StartQAV(pPlayer, kQAV2NAPDOWN); - else - StartQAV(pPlayer, kQAVNAPDOWN); - break; - case kWeapLifeLeech: - StartQAV(pPlayer, kQAVSTAFDOWN); - break; - case kWeapBeast: - StartQAV(pPlayer, kQAVBSTDOWN); - break; - } - pPlayer->curWeapon = kWeapNone; - pPlayer->qavLoop = 0; + assert(pPlayer != NULL); + if (checkFired6or7(pPlayer)) + return; + pPlayer->throwPower = 0; + int prevState = pPlayer->weaponState; + switch (pPlayer->curWeapon) + { + case kWeapPitchFork: + StartQAV(pPlayer, kQAVFORKDOWN); + break; + case kWeapSpraycan: + sfxKill3DSound(pPlayer->actor, -1, 441); + switch (prevState) + { + case 1: + if (VanillaMode()) + { + StartQAV(pPlayer, kQAVLITECLO2); + } + else + { + if (pPlayer->newWeapon == kWeapDynamite) // do not put away lighter if TNT was selected while throwing a spray can + { + pPlayer->weaponState = 2; + StartQAV(pPlayer, kQAVCANDOWN); + WeaponRaise(pPlayer); + return; + } + } + break; + case 2: + pPlayer->weaponState = 1; + WeaponRaise(pPlayer); + return; + case 4: + pPlayer->weaponState = 1; + StartQAV(pPlayer, kQAVCANDOWN); + if (VanillaMode()) + { + pPlayer->newWeapon = kWeapNone; + WeaponLower(pPlayer); + } + else + { + if (pPlayer->newWeapon == kWeapDynamite) + { + pPlayer->weaponState = 2; + StartQAV(pPlayer, kQAVCANDOWN); + return; + } + else + { + WeaponLower(pPlayer); + } + } + break; + case 3: + if (pPlayer->newWeapon == kWeapDynamite) + { + pPlayer->weaponState = 2; + StartQAV(pPlayer, kQAVCANDOWN); + return; + } + else if (pPlayer->newWeapon == kWeapSpraycan) + { + pPlayer->weaponState = 1; + StartQAV(pPlayer, kQAVCANDOWN); + pPlayer->newWeapon = kWeapNone; + WeaponLower(pPlayer); + } + else + { + pPlayer->weaponState = 1; + StartQAV(pPlayer, kQAVCANDOWN); + } + break; + case 7: // throwing ignited alt fire spray + if (VanillaMode() || (pPlayer->newWeapon != 0)) + break; + pPlayer->weaponState = 1; + StartQAV(pPlayer, kQAVCANDOWN); + break; + } + break; + case kWeapDynamite: + switch (prevState) + { + case 1: + if (VanillaMode()) + { + StartQAV(pPlayer, kQAVLITECLO2); + } + else + { + if (pPlayer->newWeapon == kWeapSpraycan) // do not put away lighter if TNT was selected while throwing a spray can + { + pPlayer->weaponState = 2; + StartQAV(pPlayer, kQAVCANDOWN); + WeaponRaise(pPlayer); + return; + } + } + break; + case 2: + WeaponRaise(pPlayer); + break; + case 3: + if (pPlayer->newWeapon == kWeapSpraycan) + { + pPlayer->weaponState = 2; + StartQAV(pPlayer, kQAVBUNDOWN); + } + else + { + StartQAV(pPlayer, kQAVBUNDOWN2); + } + break; + default: + break; + } + break; + case kWeapProximity: + switch (prevState) + { + case 7: + StartQAV(pPlayer, kQAVPROXDOWN); + break; + } + break; + case kWeapRemote: + switch (prevState) + { + case 10: + StartQAV(pPlayer, kQAVREMDOWN2); + break; + case 11: + StartQAV(pPlayer, kQAVREMDOWN3); + break; + } + break; + case kWeapShotgun: + if (powerupCheck(pPlayer, kPwUpTwoGuns)) + StartQAV(pPlayer, kQAV2SHOTDWN); + else + StartQAV(pPlayer, kQAVSHOTDOWN); + break; + case kWeapTommyGun: + if (powerupCheck(pPlayer, kPwUpTwoGuns) && pPlayer->weaponState == 1) + StartQAV(pPlayer, kQAV2TOMDOWN); + else + StartQAV(pPlayer, kQAVTOMDOWN); + break; + case kWeapFlareGun: + if (powerupCheck(pPlayer, kPwUpTwoGuns) && pPlayer->weaponState == 3) + StartQAV(pPlayer, kQAVFLAR2DWN); + else + StartQAV(pPlayer, kQAVFLARDOWN); + break; + case kWeapVoodooDoll: + StartQAV(pPlayer, kQAVVDDOWN); + break; + case kWeapTeslaCannon: + if (checkAmmo2(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns)) + StartQAV(pPlayer, kQAV2SGUNDWN); + else + StartQAV(pPlayer, kQAVSGUNDOWN); + break; + case kWeapNapalm: + if (powerupCheck(pPlayer, kPwUpTwoGuns)) + StartQAV(pPlayer, kQAV2NAPDOWN); + else + StartQAV(pPlayer, kQAVNAPDOWN); + break; + case kWeapLifeLeech: + StartQAV(pPlayer, kQAVSTAFDOWN); + break; + case kWeapBeast: + StartQAV(pPlayer, kQAVBSTDOWN); + break; + } + pPlayer->curWeapon = kWeapNone; + pPlayer->qavLoop = 0; } -void WeaponUpdateState(PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void WeaponUpdateState(PLAYER* pPlayer) { - static int lastWeapon = 0; - static int lastState = 0; - int va = pPlayer->curWeapon; - int vb = pPlayer->weaponState; - if (va != lastWeapon || vb != lastState) - { - lastWeapon = va; - lastState = vb; - } - switch (lastWeapon) - { - case kWeapPitchFork: - SetQAV(pPlayer, kQAVFORKIDLE); - break; - case kWeapSpraycan: - switch (vb) - { - case 0: - pPlayer->weaponState = 1; - StartQAV(pPlayer, kQAVLITEFLAM); - break; - case 1: - if (CheckAmmo(pPlayer, 6, 1)) - { - pPlayer->weaponState = 3; - StartQAV(pPlayer, kQAVCANPREF); - } - else - SetQAV(pPlayer, kQAVLITEIDLE); - break; - case 3: - SetQAV(pPlayer, kQAVCANIDLE); - break; - case 4: - if (CheckAmmo(pPlayer, 6, 1)) - { - SetQAV(pPlayer, kQAVCANIDLE); - pPlayer->weaponState = 3; - } - else - { - pPlayer->weaponState = 1; - StartQAV(pPlayer, kQAVCANDOWN); - } - sfxKill3DSound(pPlayer->actor, -1, 441); - break; - } - break; - case kWeapDynamite: - switch (vb) - { - case 1: - if (pPlayer->weaponAmmo == 5 && CheckAmmo(pPlayer, 5, 1)) - { - pPlayer->weaponState = 3; - StartQAV(pPlayer, kQAVBUNUP); - } - break; - case 0: - pPlayer->weaponState = 1; - StartQAV(pPlayer, kQAVLITEFLAM); - break; - case 2: - if (pPlayer->ammoCount[5] > 0) - { - pPlayer->weaponState = 3; - StartQAV(pPlayer, kQAVBUNUP); - } - else - SetQAV(pPlayer, kQAVLITEIDLE); - break; - case 3: - SetQAV(pPlayer, kQAVBUNIDLE); - break; - } - break; - case kWeapProximity: - switch (vb) - { - case 7: - SetQAV(pPlayer, kQAVPROXIDLE); - break; - case 8: - pPlayer->weaponState = 7; - StartQAV(pPlayer, kQAVPROXUP); - break; - } - break; - case kWeapRemote: - switch (vb) - { - case 10: - SetQAV(pPlayer, kQAVREMIDLE1); - break; - case 11: - SetQAV(pPlayer, kQAVREMIDLE2); - break; - case 12: - if (pPlayer->ammoCount[11] > 0) - { - pPlayer->weaponState = 10; - StartQAV(pPlayer, kQAVREMUP2); - } - else - pPlayer->weaponState = -1; - break; - } - break; - case kWeapShotgun: - switch (vb) - { - case 6: - if (powerupCheck(pPlayer, kPwUpTwoGuns) && (gInfiniteAmmo || CheckAmmo(pPlayer, 2, 4))) - pPlayer->weaponState = 7; - else - pPlayer->weaponState = 1; - break; - case 7: - SetQAV(pPlayer, kQAV2SHOTI); - break; - case 1: - if (CheckAmmo(pPlayer, 2, 1)) - { - sfxPlay3DSound(pPlayer->actor, 410, 3, 2); - StartQAV(pPlayer, kQAVSHOTL1, nClientEjectShell); - if (gInfiniteAmmo || pPlayer->ammoCount[2] > 1) - pPlayer->weaponState = 3; - else - pPlayer->weaponState = 2; - } - else - SetQAV(pPlayer, kQAVSHOTI3); - break; - case 2: - SetQAV(pPlayer, kQAVSHOTI2); - break; - case 3: - SetQAV(pPlayer, kQAVSHOTI1); - break; - } - break; - case kWeapTommyGun: - if (powerupCheck(pPlayer, kPwUpTwoGuns) && checkAmmo2(pPlayer, 3, 2)) - { - SetQAV(pPlayer, kQAV2TOMIDLE); - pPlayer->weaponState = 1; - } - else - { - SetQAV(pPlayer, kQAVTOMIDLE); - pPlayer->weaponState = 0; - } - break; - case kWeapFlareGun: - if (powerupCheck(pPlayer, kPwUpTwoGuns)) - { - if (vb == 3 && checkAmmo2(pPlayer, 1, 2)) - SetQAV(pPlayer, kQAVFLAR2I); - else - { - SetQAV(pPlayer, kQAVFLARIDLE); - pPlayer->weaponState = 2; - } - } - else - SetQAV(pPlayer, kQAVFLARIDLE); - break; - case kWeapVoodooDoll: - if (pPlayer->actor->xspr.height < 256 && pPlayer->swayHeight != 0) - StartQAV(pPlayer, kQAVVDIDLE2); - else - SetQAV(pPlayer, kQAVVDIDLE1); - break; - case kWeapTeslaCannon: - switch (vb) - { - case 2: - if (checkAmmo2(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns)) - SetQAV(pPlayer, kQAV2SGUNIDL); - else - SetQAV(pPlayer, kQAVSGUNIDL1); - break; - case 3: - SetQAV(pPlayer, kQAVSGUNIDL2); - break; - } - break; - case kWeapNapalm: - switch (vb) - { - case 3: - if (powerupCheck(pPlayer, kPwUpTwoGuns) && (gInfiniteAmmo || CheckAmmo(pPlayer,4, 4))) - SetQAV(pPlayer, kQAV2NAPIDLE); - else - SetQAV(pPlayer, kQAVNAPIDLE); - break; - case 2: - SetQAV(pPlayer, kQAVNAPIDLE); - break; - } - break; - case kWeapLifeLeech: - switch (vb) - { - case 2: - SetQAV(pPlayer, kQAVSTAFIDL1); - break; - } - break; - case kWeapBeast: - SetQAV(pPlayer, kQAVBSTIDLE); - break; - } + static int lastWeapon = 0; + static int lastState = 0; + int va = pPlayer->curWeapon; + int vb = pPlayer->weaponState; + if (va != lastWeapon || vb != lastState) + { + lastWeapon = va; + lastState = vb; + } + switch (lastWeapon) + { + case kWeapPitchFork: + SetQAV(pPlayer, kQAVFORKIDLE); + break; + case kWeapSpraycan: + switch (vb) + { + case 0: + pPlayer->weaponState = 1; + StartQAV(pPlayer, kQAVLITEFLAM); + break; + case 1: + if (CheckAmmo(pPlayer, 6, 1)) + { + pPlayer->weaponState = 3; + StartQAV(pPlayer, kQAVCANPREF); + } + else + SetQAV(pPlayer, kQAVLITEIDLE); + break; + case 3: + SetQAV(pPlayer, kQAVCANIDLE); + break; + case 4: + if (CheckAmmo(pPlayer, 6, 1)) + { + SetQAV(pPlayer, kQAVCANIDLE); + pPlayer->weaponState = 3; + } + else + { + pPlayer->weaponState = 1; + StartQAV(pPlayer, kQAVCANDOWN); + } + sfxKill3DSound(pPlayer->actor, -1, 441); + break; + } + break; + case kWeapDynamite: + switch (vb) + { + case 1: + if (pPlayer->weaponAmmo == 5 && CheckAmmo(pPlayer, 5, 1)) + { + pPlayer->weaponState = 3; + StartQAV(pPlayer, kQAVBUNUP); + } + break; + case 0: + pPlayer->weaponState = 1; + StartQAV(pPlayer, kQAVLITEFLAM); + break; + case 2: + if (pPlayer->ammoCount[5] > 0) + { + pPlayer->weaponState = 3; + StartQAV(pPlayer, kQAVBUNUP); + } + else + SetQAV(pPlayer, kQAVLITEIDLE); + break; + case 3: + SetQAV(pPlayer, kQAVBUNIDLE); + break; + } + break; + case kWeapProximity: + switch (vb) + { + case 7: + SetQAV(pPlayer, kQAVPROXIDLE); + break; + case 8: + pPlayer->weaponState = 7; + StartQAV(pPlayer, kQAVPROXUP); + break; + } + break; + case kWeapRemote: + switch (vb) + { + case 10: + SetQAV(pPlayer, kQAVREMIDLE1); + break; + case 11: + SetQAV(pPlayer, kQAVREMIDLE2); + break; + case 12: + if (pPlayer->ammoCount[11] > 0) + { + pPlayer->weaponState = 10; + StartQAV(pPlayer, kQAVREMUP2); + } + else + pPlayer->weaponState = -1; + break; + } + break; + case kWeapShotgun: + switch (vb) + { + case 6: + if (powerupCheck(pPlayer, kPwUpTwoGuns) && (gInfiniteAmmo || CheckAmmo(pPlayer, 2, 4))) + pPlayer->weaponState = 7; + else + pPlayer->weaponState = 1; + break; + case 7: + SetQAV(pPlayer, kQAV2SHOTI); + break; + case 1: + if (CheckAmmo(pPlayer, 2, 1)) + { + sfxPlay3DSound(pPlayer->actor, 410, 3, 2); + StartQAV(pPlayer, kQAVSHOTL1, nClientEjectShell); + if (gInfiniteAmmo || pPlayer->ammoCount[2] > 1) + pPlayer->weaponState = 3; + else + pPlayer->weaponState = 2; + } + else + SetQAV(pPlayer, kQAVSHOTI3); + break; + case 2: + SetQAV(pPlayer, kQAVSHOTI2); + break; + case 3: + SetQAV(pPlayer, kQAVSHOTI1); + break; + } + break; + case kWeapTommyGun: + if (powerupCheck(pPlayer, kPwUpTwoGuns) && checkAmmo2(pPlayer, 3, 2)) + { + SetQAV(pPlayer, kQAV2TOMIDLE); + pPlayer->weaponState = 1; + } + else + { + SetQAV(pPlayer, kQAVTOMIDLE); + pPlayer->weaponState = 0; + } + break; + case kWeapFlareGun: + if (powerupCheck(pPlayer, kPwUpTwoGuns)) + { + if (vb == 3 && checkAmmo2(pPlayer, 1, 2)) + SetQAV(pPlayer, kQAVFLAR2I); + else + { + SetQAV(pPlayer, kQAVFLARIDLE); + pPlayer->weaponState = 2; + } + } + else + SetQAV(pPlayer, kQAVFLARIDLE); + break; + case kWeapVoodooDoll: + if (pPlayer->actor->xspr.height < 256 && pPlayer->swayHeight != 0) + StartQAV(pPlayer, kQAVVDIDLE2); + else + SetQAV(pPlayer, kQAVVDIDLE1); + break; + case kWeapTeslaCannon: + switch (vb) + { + case 2: + if (checkAmmo2(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns)) + SetQAV(pPlayer, kQAV2SGUNIDL); + else + SetQAV(pPlayer, kQAVSGUNIDL1); + break; + case 3: + SetQAV(pPlayer, kQAVSGUNIDL2); + break; + } + break; + case kWeapNapalm: + switch (vb) + { + case 3: + if (powerupCheck(pPlayer, kPwUpTwoGuns) && (gInfiniteAmmo || CheckAmmo(pPlayer, 4, 4))) + SetQAV(pPlayer, kQAV2NAPIDLE); + else + SetQAV(pPlayer, kQAVNAPIDLE); + break; + case 2: + SetQAV(pPlayer, kQAVNAPIDLE); + break; + } + break; + case kWeapLifeLeech: + switch (vb) + { + case 2: + SetQAV(pPlayer, kQAVSTAFIDL1); + break; + } + break; + case kWeapBeast: + SetQAV(pPlayer, kQAVBSTIDLE); + break; + } } -void FirePitchfork(int, PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void FirePitchfork(int, PLAYER* pPlayer) { - DBloodActor* actor = pPlayer->actor; - Aim *aim = &pPlayer->aim; - int r1 = Random2(2000); - int r2 = Random2(2000); - int r3 = Random2(2000); - for (int i = 0; i < 4; i++) - actFireVector(actor, (2*i-3)*40, pPlayer->zWeapon-pPlayer->actor->spr.pos.Z, aim->dx+r1, aim->dy+r2, aim->dz+r3, kVectorTine); + DBloodActor* actor = pPlayer->actor; + Aim* aim = &pPlayer->aim; + int r1 = Random2(2000); + int r2 = Random2(2000); + int r3 = Random2(2000); + for (int i = 0; i < 4; i++) + actFireVector(actor, (2 * i - 3) * 40, pPlayer->zWeapon - pPlayer->actor->spr.pos.Z, aim->dx + r1, aim->dy + r2, aim->dz + r3, kVectorTine); } -void FireSpray(int, PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void FireSpray(int, PLAYER* pPlayer) { - playerFireMissile(pPlayer, 0, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, kMissileFlameSpray); - UseAmmo(pPlayer, 6, 4); - if (CheckAmmo(pPlayer, 6, 1)) - sfxPlay3DSound(pPlayer->actor, 441, 1, 2); - else - sfxKill3DSound(pPlayer->actor, -1, 441); + playerFireMissile(pPlayer, 0, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, kMissileFlameSpray); + UseAmmo(pPlayer, 6, 4); + if (CheckAmmo(pPlayer, 6, 1)) + sfxPlay3DSound(pPlayer->actor, 441, 1, 2); + else + sfxKill3DSound(pPlayer->actor, -1, 441); } -void ThrowCan(int, PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void ThrowCan(int, PLAYER* pPlayer) { - sfxKill3DSound(pPlayer->actor, -1, 441); - int nSpeed = MulScale(pPlayer->throwPower, 0x177777, 16)+0x66666; - sfxPlay3DSound(pPlayer->actor, 455, 1, 0); - auto spawned = playerFireThing(pPlayer, 0, -9460, kThingArmedSpray, nSpeed); - if (spawned) - { - sfxPlay3DSound(spawned, 441, 0, 0); - evPostActor(spawned, pPlayer->fuseTime, kCmdOn); - spawned->xspr.Impact = 1; - UseAmmo(pPlayer, 6, gAmmoItemData[0].count); - pPlayer->throwPower = 0; - } + sfxKill3DSound(pPlayer->actor, -1, 441); + int nSpeed = MulScale(pPlayer->throwPower, 0x177777, 16) + 0x66666; + sfxPlay3DSound(pPlayer->actor, 455, 1, 0); + auto spawned = playerFireThing(pPlayer, 0, -9460, kThingArmedSpray, nSpeed); + if (spawned) + { + sfxPlay3DSound(spawned, 441, 0, 0); + evPostActor(spawned, pPlayer->fuseTime, kCmdOn); + spawned->xspr.Impact = 1; + UseAmmo(pPlayer, 6, gAmmoItemData[0].count); + pPlayer->throwPower = 0; + } } -void DropCan(int, PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void DropCan(int, PLAYER* pPlayer) { - sfxKill3DSound(pPlayer->actor, -1, 441); - auto spawned = playerFireThing(pPlayer, 0, 0, kThingArmedSpray, 0); - if (spawned) - { - evPostActor(spawned, pPlayer->fuseTime, kCmdOn); - UseAmmo(pPlayer, 6, gAmmoItemData[0].count); - } + sfxKill3DSound(pPlayer->actor, -1, 441); + auto spawned = playerFireThing(pPlayer, 0, 0, kThingArmedSpray, 0); + if (spawned) + { + evPostActor(spawned, pPlayer->fuseTime, kCmdOn); + UseAmmo(pPlayer, 6, gAmmoItemData[0].count); + } } -void ExplodeCan(int, PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void ExplodeCan(int, PLAYER* pPlayer) { - sfxKill3DSound(pPlayer->actor, -1, 441); - auto spawned = playerFireThing(pPlayer, 0, 0, kThingArmedSpray, 0); - if (spawned) - { - evPostActor(spawned, 0, kCmdOn); - UseAmmo(pPlayer, 6, gAmmoItemData[0].count); - StartQAV(pPlayer, kQAVCANBOOM); - pPlayer->curWeapon = kWeapNone; - pPlayer->throwPower = 0; - } + sfxKill3DSound(pPlayer->actor, -1, 441); + auto spawned = playerFireThing(pPlayer, 0, 0, kThingArmedSpray, 0); + if (spawned) + { + evPostActor(spawned, 0, kCmdOn); + UseAmmo(pPlayer, 6, gAmmoItemData[0].count); + StartQAV(pPlayer, kQAVCANBOOM); + pPlayer->curWeapon = kWeapNone; + pPlayer->throwPower = 0; + } } -void ThrowBundle(int, PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void ThrowBundle(int, PLAYER* pPlayer) { - sfxKill3DSound(pPlayer->actor, 16, -1); - int nSpeed = MulScale(pPlayer->throwPower, 0x177777, 16)+0x66666; - sfxPlay3DSound(pPlayer->actor, 455, 1, 0); - auto spawned = playerFireThing(pPlayer, 0, -9460, kThingArmedTNTBundle, nSpeed); - if (spawned) - { - if (pPlayer->fuseTime < 0) - spawned->xspr.Impact = 1; - else - evPostActor(spawned, pPlayer->fuseTime, kCmdOn); - UseAmmo(pPlayer, 5, 1); - pPlayer->throwPower = 0; - } + sfxKill3DSound(pPlayer->actor, 16, -1); + int nSpeed = MulScale(pPlayer->throwPower, 0x177777, 16) + 0x66666; + sfxPlay3DSound(pPlayer->actor, 455, 1, 0); + auto spawned = playerFireThing(pPlayer, 0, -9460, kThingArmedTNTBundle, nSpeed); + if (spawned) + { + if (pPlayer->fuseTime < 0) + spawned->xspr.Impact = 1; + else + evPostActor(spawned, pPlayer->fuseTime, kCmdOn); + UseAmmo(pPlayer, 5, 1); + pPlayer->throwPower = 0; + } } -void DropBundle(int, PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void DropBundle(int, PLAYER* pPlayer) { - sfxKill3DSound(pPlayer->actor, 16, -1); - auto spawned = playerFireThing(pPlayer, 0, 0, kThingArmedTNTBundle, 0); - if (spawned) - { - evPostActor(spawned, pPlayer->fuseTime, kCmdOn); - UseAmmo(pPlayer, 5, 1); - } + sfxKill3DSound(pPlayer->actor, 16, -1); + auto spawned = playerFireThing(pPlayer, 0, 0, kThingArmedTNTBundle, 0); + if (spawned) + { + evPostActor(spawned, pPlayer->fuseTime, kCmdOn); + UseAmmo(pPlayer, 5, 1); + } } -void ExplodeBundle(int, PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void ExplodeBundle(int, PLAYER* pPlayer) { - sfxKill3DSound(pPlayer->actor, 16, -1); - auto spawned = playerFireThing(pPlayer, 0, 0, kThingArmedTNTBundle, 0); - if (spawned) - { - evPostActor(spawned, 0, kCmdOn); - UseAmmo(pPlayer, 5, 1); - StartQAV(pPlayer, kQAVDYNEXPLO); - pPlayer->curWeapon = kWeapNone; - pPlayer->throwPower = 0; - } + sfxKill3DSound(pPlayer->actor, 16, -1); + auto spawned = playerFireThing(pPlayer, 0, 0, kThingArmedTNTBundle, 0); + if (spawned) + { + evPostActor(spawned, 0, kCmdOn); + UseAmmo(pPlayer, 5, 1); + StartQAV(pPlayer, kQAVDYNEXPLO); + pPlayer->curWeapon = kWeapNone; + pPlayer->throwPower = 0; + } } -void ThrowProx(int, PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void ThrowProx(int, PLAYER* pPlayer) { - int nSpeed = MulScale(pPlayer->throwPower, 0x177777, 16)+0x66666; - sfxPlay3DSound(pPlayer->actor, 455, 1, 0); - auto spawned = playerFireThing(pPlayer, 0, -9460, kThingArmedProxBomb, nSpeed); - if (spawned) - { - evPostActor(spawned, 240, kCmdOn); - UseAmmo(pPlayer, 10, 1); - pPlayer->throwPower = 0; - } + int nSpeed = MulScale(pPlayer->throwPower, 0x177777, 16) + 0x66666; + sfxPlay3DSound(pPlayer->actor, 455, 1, 0); + auto spawned = playerFireThing(pPlayer, 0, -9460, kThingArmedProxBomb, nSpeed); + if (spawned) + { + evPostActor(spawned, 240, kCmdOn); + UseAmmo(pPlayer, 10, 1); + pPlayer->throwPower = 0; + } } -void DropProx(int, PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void DropProx(int, PLAYER* pPlayer) { - auto spawned = playerFireThing(pPlayer, 0, 0, kThingArmedProxBomb, 0); - if (spawned) - { - evPostActor(spawned, 240, kCmdOn); - UseAmmo(pPlayer, 10, 1); - } + auto spawned = playerFireThing(pPlayer, 0, 0, kThingArmedProxBomb, 0); + if (spawned) + { + evPostActor(spawned, 240, kCmdOn); + UseAmmo(pPlayer, 10, 1); + } } -void ThrowRemote(int, PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void ThrowRemote(int, PLAYER* pPlayer) { - int nSpeed = MulScale(pPlayer->throwPower, 0x177777, 16)+0x66666; - sfxPlay3DSound(pPlayer->actor, 455, 1, 0); - auto spawned = playerFireThing(pPlayer, 0, -9460, kThingArmedRemoteBomb, nSpeed); - if (spawned) - { - spawned->xspr.rxID = 90 + (pPlayer->actor->spr.type - kDudePlayer1); - UseAmmo(pPlayer, 11, 1); - pPlayer->throwPower = 0; - } + int nSpeed = MulScale(pPlayer->throwPower, 0x177777, 16) + 0x66666; + sfxPlay3DSound(pPlayer->actor, 455, 1, 0); + auto spawned = playerFireThing(pPlayer, 0, -9460, kThingArmedRemoteBomb, nSpeed); + if (spawned) + { + spawned->xspr.rxID = 90 + (pPlayer->actor->spr.type - kDudePlayer1); + UseAmmo(pPlayer, 11, 1); + pPlayer->throwPower = 0; + } } -void DropRemote(int, PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void DropRemote(int, PLAYER* pPlayer) { - auto spawned = playerFireThing(pPlayer, 0, 0, kThingArmedRemoteBomb, 0); - if (spawned) - { - spawned->xspr.rxID = 90 + (pPlayer->actor->spr.type - kDudePlayer1); - UseAmmo(pPlayer, 11, 1); - } + auto spawned = playerFireThing(pPlayer, 0, 0, kThingArmedRemoteBomb, 0); + if (spawned) + { + spawned->xspr.rxID = 90 + (pPlayer->actor->spr.type - kDudePlayer1); + UseAmmo(pPlayer, 11, 1); + } } -void FireRemote(int, PLAYER *pPlayer) +void FireRemote(int, PLAYER* pPlayer) { - evSendGame(90+(pPlayer->actor->spr.type-kDudePlayer1), kCmdOn); + evSendGame(90 + (pPlayer->actor->spr.type - kDudePlayer1), kCmdOn); } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + enum { kMaxShotgunBarrels = 4 }; -void FireShotgun(int nTrigger, PLAYER *pPlayer) +void FireShotgun(int nTrigger, PLAYER* pPlayer) { - DBloodActor* actor = pPlayer->actor; - assert(nTrigger > 0 && nTrigger <= kMaxShotgunBarrels); - if (nTrigger == 1) - { - sfxPlay3DSound(pPlayer->actor, 411, 2, 0); - pPlayer->tiltEffect = 30; - pPlayer->visibility = 20; - } - else - { - sfxPlay3DSound(pPlayer->actor, 412, 2, 0); - pPlayer->tiltEffect = 50; - pPlayer->visibility = 40; - } - int n = nTrigger<<4; - for (int i = 0; i < n; i++) - { - int r1, r2, r3; - VECTOR_TYPE nType; - if (nTrigger == 1) - { - r1 = Random3(1500); - r2 = Random3(1500); - r3 = Random3(500); - nType = kVectorShell; - } - else - { - r1 = Random3(2500); - r2 = Random3(2500); - r3 = Random3(1500); - nType = kVectorShellAP; - } - actFireVector(actor, 0, pPlayer->zWeapon-pPlayer->actor->spr.pos.Z, pPlayer->aim.dx+r1, pPlayer->aim.dy+r2, pPlayer->aim.dz+r3, nType); - } - UseAmmo(pPlayer, pPlayer->weaponAmmo, nTrigger); - pPlayer->flashEffect = 1; + DBloodActor* actor = pPlayer->actor; + assert(nTrigger > 0 && nTrigger <= kMaxShotgunBarrels); + if (nTrigger == 1) + { + sfxPlay3DSound(pPlayer->actor, 411, 2, 0); + pPlayer->tiltEffect = 30; + pPlayer->visibility = 20; + } + else + { + sfxPlay3DSound(pPlayer->actor, 412, 2, 0); + pPlayer->tiltEffect = 50; + pPlayer->visibility = 40; + } + int n = nTrigger << 4; + for (int i = 0; i < n; i++) + { + int r1, r2, r3; + VECTOR_TYPE nType; + if (nTrigger == 1) + { + r1 = Random3(1500); + r2 = Random3(1500); + r3 = Random3(500); + nType = kVectorShell; + } + else + { + r1 = Random3(2500); + r2 = Random3(2500); + r3 = Random3(1500); + nType = kVectorShellAP; + } + actFireVector(actor, 0, pPlayer->zWeapon - pPlayer->actor->spr.pos.Z, pPlayer->aim.dx + r1, pPlayer->aim.dy + r2, pPlayer->aim.dz + r3, nType); + } + UseAmmo(pPlayer, pPlayer->weaponAmmo, nTrigger); + pPlayer->flashEffect = 1; } -void EjectShell(int, PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void EjectShell(int, PLAYER* pPlayer) { - SpawnShellEject(pPlayer, 25, 35); - SpawnShellEject(pPlayer, 48, 35); + SpawnShellEject(pPlayer, 25, 35); + SpawnShellEject(pPlayer, 48, 35); } -void FireTommy(int nTrigger, PLAYER *pPlayer) +void FireTommy(int nTrigger, PLAYER* pPlayer) { - DBloodActor* actor = pPlayer->actor; - Aim *aim = &pPlayer->aim; - sfxPlay3DSound(pPlayer->actor, 431, -1, 0); - switch (nTrigger) - { - case 1: - { - int r1 = Random3(400); - int r2 = Random3(1200); - int r3 = Random3(1200); - actFireVector(actor, 0, pPlayer->zWeapon-pPlayer->actor->spr.pos.Z, aim->dx+r3, aim->dy+r2, aim->dz+r1, kVectorTommyRegular); - SpawnBulletEject(pPlayer, -15, -45); - pPlayer->visibility = 20; - break; - } - case 2: - { - int r1 = Random3(400); - int r2 = Random3(1200); - int r3 = Random3(1200); - actFireVector(actor, -120, pPlayer->zWeapon-pPlayer->actor->spr.pos.Z, aim->dx+r3, aim->dy+r2, aim->dz+r1, kVectorTommyRegular); - SpawnBulletEject(pPlayer, -140, -45); - r1 = Random3(400); - r2 = Random3(1200); - r3 = Random3(1200); - actFireVector(actor, 120, pPlayer->zWeapon-pPlayer->actor->spr.pos.Z, aim->dx+r3, aim->dy+r2, aim->dz+r1, kVectorTommyRegular); - SpawnBulletEject(pPlayer, 140, 45); - pPlayer->visibility = 30; - break; - } - } - UseAmmo(pPlayer, pPlayer->weaponAmmo, nTrigger); - pPlayer->flashEffect = 1; + DBloodActor* actor = pPlayer->actor; + Aim* aim = &pPlayer->aim; + sfxPlay3DSound(pPlayer->actor, 431, -1, 0); + switch (nTrigger) + { + case 1: + { + int r1 = Random3(400); + int r2 = Random3(1200); + int r3 = Random3(1200); + actFireVector(actor, 0, pPlayer->zWeapon - pPlayer->actor->spr.pos.Z, aim->dx + r3, aim->dy + r2, aim->dz + r1, kVectorTommyRegular); + SpawnBulletEject(pPlayer, -15, -45); + pPlayer->visibility = 20; + break; + } + case 2: + { + int r1 = Random3(400); + int r2 = Random3(1200); + int r3 = Random3(1200); + actFireVector(actor, -120, pPlayer->zWeapon - pPlayer->actor->spr.pos.Z, aim->dx + r3, aim->dy + r2, aim->dz + r1, kVectorTommyRegular); + SpawnBulletEject(pPlayer, -140, -45); + r1 = Random3(400); + r2 = Random3(1200); + r3 = Random3(1200); + actFireVector(actor, 120, pPlayer->zWeapon - pPlayer->actor->spr.pos.Z, aim->dx + r3, aim->dy + r2, aim->dz + r1, kVectorTommyRegular); + SpawnBulletEject(pPlayer, 140, 45); + pPlayer->visibility = 30; + break; + } + } + UseAmmo(pPlayer, pPlayer->weaponAmmo, nTrigger); + pPlayer->flashEffect = 1; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + enum { kMaxSpread = 14 }; -void FireSpread(int nTrigger, PLAYER *pPlayer) +void FireSpread(int nTrigger, PLAYER* pPlayer) { - DBloodActor* actor = pPlayer->actor; - assert(nTrigger > 0 && nTrigger <= kMaxSpread); - Aim *aim = &pPlayer->aim; - int angle = (getangle(aim->dx, aim->dy)+((112*(nTrigger-1))/14-56))&2047; - int dx = bcos(angle); - int dy = bsin(angle); - sfxPlay3DSound(pPlayer->actor, 431, -1, 0); - int r1, r2, r3; - r1 = Random3(300); - r2 = Random3(600); - r3 = Random3(600); - actFireVector(actor, 0, pPlayer->zWeapon-pPlayer->actor->spr.pos.Z, dx+r3, dy+r2, aim->dz+r1, kVectorTommyAP); - r1 = Random2(90); - r2 = Random2(30); - SpawnBulletEject(pPlayer, r2, r1); - pPlayer->visibility = 20; - UseAmmo(pPlayer, pPlayer->weaponAmmo, 1); - pPlayer->flashEffect = 1; + DBloodActor* actor = pPlayer->actor; + assert(nTrigger > 0 && nTrigger <= kMaxSpread); + Aim* aim = &pPlayer->aim; + int angle = (getangle(aim->dx, aim->dy) + ((112 * (nTrigger - 1)) / 14 - 56)) & 2047; + int dx = bcos(angle); + int dy = bsin(angle); + sfxPlay3DSound(pPlayer->actor, 431, -1, 0); + int r1, r2, r3; + r1 = Random3(300); + r2 = Random3(600); + r3 = Random3(600); + actFireVector(actor, 0, pPlayer->zWeapon - pPlayer->actor->spr.pos.Z, dx + r3, dy + r2, aim->dz + r1, kVectorTommyAP); + r1 = Random2(90); + r2 = Random2(30); + SpawnBulletEject(pPlayer, r2, r1); + pPlayer->visibility = 20; + UseAmmo(pPlayer, pPlayer->weaponAmmo, 1); + pPlayer->flashEffect = 1; } -void AltFireSpread(int nTrigger, PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void AltFireSpread(int nTrigger, PLAYER* pPlayer) { - DBloodActor* actor = pPlayer->actor; - assert(nTrigger > 0 && nTrigger <= kMaxSpread); - Aim *aim = &pPlayer->aim; - int angle = (getangle(aim->dx, aim->dy)+((112*(nTrigger-1))/14-56))&2047; - int dx = bcos(angle); - int dy = bsin(angle); - sfxPlay3DSound(pPlayer->actor, 431, -1, 0); - int r1, r2, r3; - r1 = Random3(300); - r2 = Random3(600); - r3 = Random3(600); - actFireVector(actor, -120, pPlayer->zWeapon-pPlayer->actor->spr.pos.Z, dx+r3, dy+r2, aim->dz+r1, kVectorTommyAP); - r1 = Random2(45); - r2 = Random2(120); - SpawnBulletEject(pPlayer, r2, r1); - r1 = Random3(300); - r2 = Random3(600); - r3 = Random3(600); - actFireVector(actor, 120, pPlayer->zWeapon-pPlayer->actor->spr.pos.Z, dx+r3, dy+r2, aim->dz+r1, kVectorTommyAP); - r1 = Random2(-45); - r2 = Random2(-120); - SpawnBulletEject(pPlayer, r2, r1); - pPlayer->tiltEffect = 20; - pPlayer->visibility = 30; - UseAmmo(pPlayer, pPlayer->weaponAmmo, 2); - pPlayer->flashEffect = 1; + DBloodActor* actor = pPlayer->actor; + assert(nTrigger > 0 && nTrigger <= kMaxSpread); + Aim* aim = &pPlayer->aim; + int angle = (getangle(aim->dx, aim->dy) + ((112 * (nTrigger - 1)) / 14 - 56)) & 2047; + int dx = bcos(angle); + int dy = bsin(angle); + sfxPlay3DSound(pPlayer->actor, 431, -1, 0); + int r1, r2, r3; + r1 = Random3(300); + r2 = Random3(600); + r3 = Random3(600); + actFireVector(actor, -120, pPlayer->zWeapon - pPlayer->actor->spr.pos.Z, dx + r3, dy + r2, aim->dz + r1, kVectorTommyAP); + r1 = Random2(45); + r2 = Random2(120); + SpawnBulletEject(pPlayer, r2, r1); + r1 = Random3(300); + r2 = Random3(600); + r3 = Random3(600); + actFireVector(actor, 120, pPlayer->zWeapon - pPlayer->actor->spr.pos.Z, dx + r3, dy + r2, aim->dz + r1, kVectorTommyAP); + r1 = Random2(-45); + r2 = Random2(-120); + SpawnBulletEject(pPlayer, r2, r1); + pPlayer->tiltEffect = 20; + pPlayer->visibility = 30; + UseAmmo(pPlayer, pPlayer->weaponAmmo, 2); + pPlayer->flashEffect = 1; } -void AltFireSpread2(int nTrigger, PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void AltFireSpread2(int nTrigger, PLAYER* pPlayer) { - DBloodActor* actor = pPlayer->actor; - assert(nTrigger > 0 && nTrigger <= kMaxSpread); - Aim *aim = &pPlayer->aim; - int angle = (getangle(aim->dx, aim->dy)+((112*(nTrigger-1))/14-56))&2047; - int dx = bcos(angle); - int dy = bsin(angle); - sfxPlay3DSound(pPlayer->actor, 431, -1, 0); - if (powerupCheck(pPlayer, kPwUpTwoGuns) && checkAmmo2(pPlayer, 3, 2)) - { - int r1, r2, r3; - r1 = Random3(300); - r2 = Random3(600); - r3 = Random3(600); - actFireVector(actor, -120, pPlayer->zWeapon-pPlayer->actor->spr.pos.Z, dx+r3, dy+r2, aim->dz+r1, kVectorTommyAP); - r1 = Random2(45); - r2 = Random2(120); - SpawnBulletEject(pPlayer, r2, r1); - r1 = Random3(300); - r2 = Random3(600); - r3 = Random3(600); - actFireVector(actor, 120, pPlayer->zWeapon-pPlayer->actor->spr.pos.Z, dx+r3, dy+r2, aim->dz+r1, kVectorTommyAP); - r1 = Random2(-45); - r2 = Random2(-120); - SpawnBulletEject(pPlayer, r2, r1); - pPlayer->tiltEffect = 30; - pPlayer->visibility = 45; - UseAmmo(pPlayer, pPlayer->weaponAmmo, 2); - } - else - { - int r1, r2, r3; - r1 = Random3(300); - r2 = Random3(600); - r3 = Random3(600); - actFireVector(actor, 0, pPlayer->zWeapon-pPlayer->actor->spr.pos.Z, dx+r3, dy+r2, aim->dz+r1, kVectorTommyAP); - r1 = Random2(90); - r2 = Random2(30); - SpawnBulletEject(pPlayer, r2, r1); - pPlayer->tiltEffect = 20; - pPlayer->visibility = 30; - UseAmmo(pPlayer, pPlayer->weaponAmmo, 1); - } - pPlayer->flashEffect = 1; - if (!checkAmmo2(pPlayer, 3, 1)) - { - WeaponLower(pPlayer); - pPlayer->weaponState = -1; - } + DBloodActor* actor = pPlayer->actor; + assert(nTrigger > 0 && nTrigger <= kMaxSpread); + Aim* aim = &pPlayer->aim; + int angle = (getangle(aim->dx, aim->dy) + ((112 * (nTrigger - 1)) / 14 - 56)) & 2047; + int dx = bcos(angle); + int dy = bsin(angle); + sfxPlay3DSound(pPlayer->actor, 431, -1, 0); + if (powerupCheck(pPlayer, kPwUpTwoGuns) && checkAmmo2(pPlayer, 3, 2)) + { + int r1, r2, r3; + r1 = Random3(300); + r2 = Random3(600); + r3 = Random3(600); + actFireVector(actor, -120, pPlayer->zWeapon - pPlayer->actor->spr.pos.Z, dx + r3, dy + r2, aim->dz + r1, kVectorTommyAP); + r1 = Random2(45); + r2 = Random2(120); + SpawnBulletEject(pPlayer, r2, r1); + r1 = Random3(300); + r2 = Random3(600); + r3 = Random3(600); + actFireVector(actor, 120, pPlayer->zWeapon - pPlayer->actor->spr.pos.Z, dx + r3, dy + r2, aim->dz + r1, kVectorTommyAP); + r1 = Random2(-45); + r2 = Random2(-120); + SpawnBulletEject(pPlayer, r2, r1); + pPlayer->tiltEffect = 30; + pPlayer->visibility = 45; + UseAmmo(pPlayer, pPlayer->weaponAmmo, 2); + } + else + { + int r1, r2, r3; + r1 = Random3(300); + r2 = Random3(600); + r3 = Random3(600); + actFireVector(actor, 0, pPlayer->zWeapon - pPlayer->actor->spr.pos.Z, dx + r3, dy + r2, aim->dz + r1, kVectorTommyAP); + r1 = Random2(90); + r2 = Random2(30); + SpawnBulletEject(pPlayer, r2, r1); + pPlayer->tiltEffect = 20; + pPlayer->visibility = 30; + UseAmmo(pPlayer, pPlayer->weaponAmmo, 1); + } + pPlayer->flashEffect = 1; + if (!checkAmmo2(pPlayer, 3, 1)) + { + WeaponLower(pPlayer); + pPlayer->weaponState = -1; + } } -void FireFlare(int nTrigger, PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void FireFlare(int nTrigger, PLAYER* pPlayer) { - auto plActor = pPlayer->actor; - int offset = 0; - switch (nTrigger) - { - case 2: - offset = -120; - break; - case 3: - offset = 120; - break; - } - playerFireMissile(pPlayer, offset, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, kMissileFlareRegular); - UseAmmo(pPlayer, 1, 1); - sfxPlay3DSound(pPlayer->actor, 420, 2, 0); - pPlayer->visibility = 30; - pPlayer->flashEffect = 1; + auto plActor = pPlayer->actor; + int offset = 0; + switch (nTrigger) + { + case 2: + offset = -120; + break; + case 3: + offset = 120; + break; + } + playerFireMissile(pPlayer, offset, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, kMissileFlareRegular); + UseAmmo(pPlayer, 1, 1); + sfxPlay3DSound(pPlayer->actor, 420, 2, 0); + pPlayer->visibility = 30; + pPlayer->flashEffect = 1; } -void AltFireFlare(int nTrigger, PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void AltFireFlare(int nTrigger, PLAYER* pPlayer) { - auto plActor = pPlayer->actor; - int offset = 0; - switch (nTrigger) - { - case 2: - offset = -120; - break; - case 3: - offset = 120; - break; - } - playerFireMissile(pPlayer, offset, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, kMissileFlareAlt); - UseAmmo(pPlayer, 1, 8); - sfxPlay3DSound(pPlayer->actor, 420, 2, 0); - pPlayer->visibility = 45; - pPlayer->flashEffect = 1; + auto plActor = pPlayer->actor; + int offset = 0; + switch (nTrigger) + { + case 2: + offset = -120; + break; + case 3: + offset = 120; + break; + } + playerFireMissile(pPlayer, offset, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, kMissileFlareAlt); + UseAmmo(pPlayer, 1, 8); + sfxPlay3DSound(pPlayer->actor, 420, 2, 0); + pPlayer->visibility = 45; + pPlayer->flashEffect = 1; } -void FireVoodoo(int nTrigger, PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void FireVoodoo(int nTrigger, PLAYER* pPlayer) { - nTrigger--; - DBloodActor* actor = pPlayer->actor; - auto plActor = pPlayer->actor; - if (nTrigger == 4) - { - actDamageSprite(actor, actor, kDamageBullet, 1<<4); - return; - } - DBloodActor* targetactor = pPlayer->voodooTarget; - if (!targetactor) return; - if (!gGameOptions.bFriendlyFire && IsTargetTeammate(pPlayer, targetactor)) - return; - switch (nTrigger) - { - case 0: - { - sfxPlay3DSound(actor, 460, 2, 0); - fxSpawnBlood(targetactor, 17<<4); - int nDamage = actDamageSprite(actor, targetactor, kDamageSpirit, 17<<4); - UseAmmo(pPlayer, 9, nDamage/4); - break; - } - case 1: - { - sfxPlay3DSound(actor, 460, 2, 0); - fxSpawnBlood(targetactor, 17<<4); - int nDamage = actDamageSprite(actor, targetactor, kDamageSpirit, 9<<4); - if (targetactor->IsPlayerActor()) - WeaponLower(&gPlayer[targetactor->spr.type-kDudePlayer1]); - UseAmmo(pPlayer, 9, nDamage/4); - break; - } - case 3: - { - sfxPlay3DSound(actor, 463, 2, 0); - fxSpawnBlood(targetactor, 17<<4); - int nDamage = actDamageSprite(actor, targetactor, kDamageSpirit, 49<<4); - UseAmmo(pPlayer, 9, nDamage/4); - break; - } - case 2: - { - sfxPlay3DSound(actor, 460, 2, 0); - fxSpawnBlood(targetactor, 17<<4); - int nDamage = actDamageSprite(actor, targetactor, kDamageSpirit, 11<<4); - if (targetactor->IsPlayerActor()) - { - PLAYER *pOtherPlayer = &gPlayer[targetactor->spr.type - kDudePlayer1]; - pOtherPlayer->blindEffect = 128; - } - UseAmmo(pPlayer, 9, nDamage/4); - break; - } - } + nTrigger--; + DBloodActor* actor = pPlayer->actor; + auto plActor = pPlayer->actor; + if (nTrigger == 4) + { + actDamageSprite(actor, actor, kDamageBullet, 1 << 4); + return; + } + DBloodActor* targetactor = pPlayer->voodooTarget; + if (!targetactor) return; + if (!gGameOptions.bFriendlyFire && IsTargetTeammate(pPlayer, targetactor)) + return; + switch (nTrigger) + { + case 0: + { + sfxPlay3DSound(actor, 460, 2, 0); + fxSpawnBlood(targetactor, 17 << 4); + int nDamage = actDamageSprite(actor, targetactor, kDamageSpirit, 17 << 4); + UseAmmo(pPlayer, 9, nDamage / 4); + break; + } + case 1: + { + sfxPlay3DSound(actor, 460, 2, 0); + fxSpawnBlood(targetactor, 17 << 4); + int nDamage = actDamageSprite(actor, targetactor, kDamageSpirit, 9 << 4); + if (targetactor->IsPlayerActor()) + WeaponLower(&gPlayer[targetactor->spr.type - kDudePlayer1]); + UseAmmo(pPlayer, 9, nDamage / 4); + break; + } + case 3: + { + sfxPlay3DSound(actor, 463, 2, 0); + fxSpawnBlood(targetactor, 17 << 4); + int nDamage = actDamageSprite(actor, targetactor, kDamageSpirit, 49 << 4); + UseAmmo(pPlayer, 9, nDamage / 4); + break; + } + case 2: + { + sfxPlay3DSound(actor, 460, 2, 0); + fxSpawnBlood(targetactor, 17 << 4); + int nDamage = actDamageSprite(actor, targetactor, kDamageSpirit, 11 << 4); + if (targetactor->IsPlayerActor()) + { + PLAYER* pOtherPlayer = &gPlayer[targetactor->spr.type - kDudePlayer1]; + pOtherPlayer->blindEffect = 128; + } + UseAmmo(pPlayer, 9, nDamage / 4); + break; + } + } } -void AltFireVoodoo(int nTrigger, PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void AltFireVoodoo(int nTrigger, PLAYER* pPlayer) { - DBloodActor* actor = pPlayer->actor; - if (nTrigger == 2) { + DBloodActor* actor = pPlayer->actor; + if (nTrigger == 2) { - // by NoOne: trying to simulate v1.0x voodoo here. - // dunno how exactly it works, but at least it not spend all the ammo on alt fire - if (gGameOptions.weaponsV10x && !VanillaMode()) { - int nCount = ClipHigh(pPlayer->ammoCount[9], pPlayer->aimTargetsCount); - if (nCount > 0) - { - for (int i = 0; i < pPlayer->aimTargetsCount; i++) - { - DBloodActor* targetactor = pPlayer->aimTargets[i]; - if (!targetactor) continue; - if (!gGameOptions.bFriendlyFire && IsTargetTeammate(pPlayer, targetactor)) - continue; - int nDist = approxDist(targetactor->spr.pos.X - pPlayer->actor->spr.pos.X, targetactor->spr.pos.Y - pPlayer->actor->spr.pos.Y); - if (nDist > 0 && nDist < 51200) - { - int vc = pPlayer->ammoCount[9] >> 3; - int v8 = pPlayer->ammoCount[9] << 1; - int nDamage = (v8 + Random(vc)) << 4; - nDamage = (nDamage * ((51200 - nDist) + 1)) / 51200; - nDamage = actDamageSprite(actor, targetactor, kDamageSpirit, nDamage); + // by NoOne: trying to simulate v1.0x voodoo here. + // dunno how exactly it works, but at least it not spend all the ammo on alt fire + if (gGameOptions.weaponsV10x && !VanillaMode()) { + int nCount = ClipHigh(pPlayer->ammoCount[9], pPlayer->aimTargetsCount); + if (nCount > 0) + { + for (int i = 0; i < pPlayer->aimTargetsCount; i++) + { + DBloodActor* targetactor = pPlayer->aimTargets[i]; + if (!targetactor) continue; + if (!gGameOptions.bFriendlyFire && IsTargetTeammate(pPlayer, targetactor)) + continue; + int nDist = approxDist(targetactor->spr.pos.X - pPlayer->actor->spr.pos.X, targetactor->spr.pos.Y - pPlayer->actor->spr.pos.Y); + if (nDist > 0 && nDist < 51200) + { + int vc = pPlayer->ammoCount[9] >> 3; + int v8 = pPlayer->ammoCount[9] << 1; + int nDamage = (v8 + Random(vc)) << 4; + nDamage = (nDamage * ((51200 - nDist) + 1)) / 51200; + nDamage = actDamageSprite(actor, targetactor, kDamageSpirit, nDamage); - if (targetactor->IsPlayerActor()) - { - PLAYER* pOtherPlayer = &gPlayer[targetactor->spr.type - kDudePlayer1]; - if (!pOtherPlayer->godMode || !powerupCheck(pOtherPlayer, kPwUpDeathMask)) - powerupActivate(pOtherPlayer, kPwUpDeliriumShroom); - } - fxSpawnBlood(targetactor, 0); - } - } - } + if (targetactor->IsPlayerActor()) + { + PLAYER* pOtherPlayer = &gPlayer[targetactor->spr.type - kDudePlayer1]; + if (!pOtherPlayer->godMode || !powerupCheck(pOtherPlayer, kPwUpDeathMask)) + powerupActivate(pOtherPlayer, kPwUpDeliriumShroom); + } + fxSpawnBlood(targetactor, 0); + } + } + } - UseAmmo(pPlayer, 9, 20); - pPlayer->weaponState = 0; - return; - } + UseAmmo(pPlayer, 9, 20); + pPlayer->weaponState = 0; + return; + } - //int nAmmo = pPlayer->ammCount[9]; - int nCount = ClipHigh(pPlayer->ammoCount[9], pPlayer->aimTargetsCount); - if (nCount > 0) - { - int v4 = pPlayer->ammoCount[9] - (pPlayer->ammoCount[9] / nCount) * nCount; - for (int i = 0; i < pPlayer->aimTargetsCount; i++) - { - DBloodActor* targetactor = pPlayer->aimTargets[i]; - if (!targetactor) continue; - if (!gGameOptions.bFriendlyFire && IsTargetTeammate(pPlayer, targetactor)) - continue; - if (v4 > 0) - v4--; - int nDist = approxDist(targetactor->spr.pos.X - pPlayer->actor->spr.pos.X, targetactor->spr.pos.Y - pPlayer->actor->spr.pos.Y); - if (nDist > 0 && nDist < 51200) - { - int vc = pPlayer->ammoCount[9] >> 3; - int v8 = pPlayer->ammoCount[9] << 1; - int nDamage = (v8 + Random2(vc)) << 4; - nDamage = (nDamage * ((51200 - nDist) + 1)) / 51200; - nDamage = actDamageSprite(actor, targetactor, kDamageSpirit, nDamage); - UseAmmo(pPlayer, 9, nDamage); - if (targetactor->IsPlayerActor()) - { - PLAYER* pOtherPlayer = &gPlayer[targetactor->spr.type - kDudePlayer1]; - if (!pOtherPlayer->godMode || !powerupCheck(pOtherPlayer, kPwUpDeathMask)) - powerupActivate(pOtherPlayer, kPwUpDeliriumShroom); - } - fxSpawnBlood(targetactor, 0); - } - } - } - UseAmmo(pPlayer, 9, pPlayer->ammoCount[9]); - pPlayer->hasWeapon[10] = 0; - pPlayer->weaponState = -1; - } + //int nAmmo = pPlayer->ammCount[9]; + int nCount = ClipHigh(pPlayer->ammoCount[9], pPlayer->aimTargetsCount); + if (nCount > 0) + { + int v4 = pPlayer->ammoCount[9] - (pPlayer->ammoCount[9] / nCount) * nCount; + for (int i = 0; i < pPlayer->aimTargetsCount; i++) + { + DBloodActor* targetactor = pPlayer->aimTargets[i]; + if (!targetactor) continue; + if (!gGameOptions.bFriendlyFire && IsTargetTeammate(pPlayer, targetactor)) + continue; + if (v4 > 0) + v4--; + int nDist = approxDist(targetactor->spr.pos.X - pPlayer->actor->spr.pos.X, targetactor->spr.pos.Y - pPlayer->actor->spr.pos.Y); + if (nDist > 0 && nDist < 51200) + { + int vc = pPlayer->ammoCount[9] >> 3; + int v8 = pPlayer->ammoCount[9] << 1; + int nDamage = (v8 + Random2(vc)) << 4; + nDamage = (nDamage * ((51200 - nDist) + 1)) / 51200; + nDamage = actDamageSprite(actor, targetactor, kDamageSpirit, nDamage); + UseAmmo(pPlayer, 9, nDamage); + if (targetactor->IsPlayerActor()) + { + PLAYER* pOtherPlayer = &gPlayer[targetactor->spr.type - kDudePlayer1]; + if (!pOtherPlayer->godMode || !powerupCheck(pOtherPlayer, kPwUpDeathMask)) + powerupActivate(pOtherPlayer, kPwUpDeliriumShroom); + } + fxSpawnBlood(targetactor, 0); + } + } + } + UseAmmo(pPlayer, 9, pPlayer->ammoCount[9]); + pPlayer->hasWeapon[10] = 0; + pPlayer->weaponState = -1; + } } -void DropVoodoo(int , PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void DropVoodoo(int, PLAYER* pPlayer) { - sfxPlay3DSound(pPlayer->actor, 455, 2, 0); - auto spawned = playerFireThing(pPlayer, 0, -4730, kThingVoodooHead, 0xccccc); - if (spawned) - { - spawned->xspr.data1 = pPlayer->ammoCount[9]; - evPostActor(spawned, 90, kCallbackDropVoodoo); - UseAmmo(pPlayer, 6, gAmmoItemData[0].count); - UseAmmo(pPlayer, 9, pPlayer->ammoCount[9]); - pPlayer->hasWeapon[10] = 0; - } + sfxPlay3DSound(pPlayer->actor, 455, 2, 0); + auto spawned = playerFireThing(pPlayer, 0, -4730, kThingVoodooHead, 0xccccc); + if (spawned) + { + spawned->xspr.data1 = pPlayer->ammoCount[9]; + evPostActor(spawned, 90, kCallbackDropVoodoo); + UseAmmo(pPlayer, 6, gAmmoItemData[0].count); + UseAmmo(pPlayer, 9, pPlayer->ammoCount[9]); + pPlayer->hasWeapon[10] = 0; + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + struct TeslaMissile { - int offset; // offset - int id; // id - int ammouse; // ammo use - int sound; // sound - int light; // light - int flash; // weapon flash + int offset; // offset + int id; // id + int ammouse; // ammo use + int sound; // sound + int light; // light + int flash; // weapon flash }; -void FireTesla(int nTrigger, PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void FireTesla(int nTrigger, PLAYER* pPlayer) { - TeslaMissile teslaMissile[6] = - { - { 0, 306, 1, 470, 20, 1 }, - { -140, 306, 1, 470, 30, 1 }, - { 140, 306, 1, 470, 30, 1 }, - { 0, 302, 35, 471, 40, 1 }, - { -140, 302, 35, 471, 50, 1 }, - { 140, 302, 35, 471, 50, 1 }, - }; - if (nTrigger > 0 && nTrigger <= 6) - { - nTrigger--; - auto plActor = pPlayer->actor; - TeslaMissile *pMissile = &teslaMissile[nTrigger]; - if (!checkAmmo2(pPlayer, 7, pMissile->ammouse)) - { - pMissile = &teslaMissile[0]; - if (!checkAmmo2(pPlayer, 7, pMissile->ammouse)) - { - pPlayer->weaponState = -1; - SetQAV(pPlayer, kQAVSGUNIDL2); - pPlayer->flashEffect = 0; - return; - } - } - playerFireMissile(pPlayer, pMissile->offset, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, pMissile->id); - UseAmmo(pPlayer, 7, pMissile->ammouse); - sfxPlay3DSound(pPlayer->actor, pMissile->sound, 1, 0); - pPlayer->visibility = pMissile->light; - pPlayer->flashEffect = pMissile->flash; - } + TeslaMissile teslaMissile[6] = + { + { 0, 306, 1, 470, 20, 1 }, + { -140, 306, 1, 470, 30, 1 }, + { 140, 306, 1, 470, 30, 1 }, + { 0, 302, 35, 471, 40, 1 }, + { -140, 302, 35, 471, 50, 1 }, + { 140, 302, 35, 471, 50, 1 }, + }; + if (nTrigger > 0 && nTrigger <= 6) + { + nTrigger--; + auto plActor = pPlayer->actor; + TeslaMissile* pMissile = &teslaMissile[nTrigger]; + if (!checkAmmo2(pPlayer, 7, pMissile->ammouse)) + { + pMissile = &teslaMissile[0]; + if (!checkAmmo2(pPlayer, 7, pMissile->ammouse)) + { + pPlayer->weaponState = -1; + SetQAV(pPlayer, kQAVSGUNIDL2); + pPlayer->flashEffect = 0; + return; + } + } + playerFireMissile(pPlayer, pMissile->offset, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, pMissile->id); + UseAmmo(pPlayer, 7, pMissile->ammouse); + sfxPlay3DSound(pPlayer->actor, pMissile->sound, 1, 0); + pPlayer->visibility = pMissile->light; + pPlayer->flashEffect = pMissile->flash; + } } -void AltFireTesla(int , PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void AltFireTesla(int, PLAYER* pPlayer) { - auto plActor = pPlayer->actor; - playerFireMissile(pPlayer, 0, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, kMissileTeslaAlt); - UseAmmo(pPlayer, pPlayer->weaponAmmo, 35); - sfxPlay3DSound(pPlayer->actor, 471, 2, 0); - pPlayer->visibility = 40; - pPlayer->flashEffect = 1; + auto plActor = pPlayer->actor; + playerFireMissile(pPlayer, 0, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, kMissileTeslaAlt); + UseAmmo(pPlayer, pPlayer->weaponAmmo, 35); + sfxPlay3DSound(pPlayer->actor, 471, 2, 0); + pPlayer->visibility = 40; + pPlayer->flashEffect = 1; } -void FireNapalm(int nTrigger, PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void FireNapalm(int nTrigger, PLAYER* pPlayer) { - auto plActor = pPlayer->actor; - int offset = 0; - switch (nTrigger) - { - case 2: - offset = -50; - break; - case 3: - offset = 50; - break; - } - playerFireMissile(pPlayer, offset, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, kMissileFireballNapalm); - sfxPlay3DSound(pPlayer->actor, 480, 2, 0); - UseAmmo(pPlayer, 4, 1); - pPlayer->flashEffect = 1; + auto plActor = pPlayer->actor; + int offset = 0; + switch (nTrigger) + { + case 2: + offset = -50; + break; + case 3: + offset = 50; + break; + } + playerFireMissile(pPlayer, offset, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, kMissileFireballNapalm); + sfxPlay3DSound(pPlayer->actor, 480, 2, 0); + UseAmmo(pPlayer, 4, 1); + pPlayer->flashEffect = 1; } -void FireNapalm2(int , PLAYER *pPlayer) +void FireNapalm2(int, PLAYER* pPlayer) { - auto plActor = pPlayer->actor; - playerFireMissile(pPlayer, -120, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, kMissileFireballNapalm); - playerFireMissile(pPlayer, 120, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, kMissileFireballNapalm); - sfxPlay3DSound(pPlayer->actor, 480, 2, 0); - UseAmmo(pPlayer, 4, 2); - pPlayer->flashEffect = 1; + auto plActor = pPlayer->actor; + playerFireMissile(pPlayer, -120, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, kMissileFireballNapalm); + playerFireMissile(pPlayer, 120, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, kMissileFireballNapalm); + sfxPlay3DSound(pPlayer->actor, 480, 2, 0); + UseAmmo(pPlayer, 4, 2); + pPlayer->flashEffect = 1; } -void AltFireNapalm(int , PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void AltFireNapalm(int, PLAYER* pPlayer) { - int nSpeed = MulScale(0x8000, 0x177777, 16)+0x66666; - auto missile = playerFireThing(pPlayer, 0, -4730, kThingNapalmBall, nSpeed); - if (missile) - { - missile->xspr.data4 = ClipHigh(pPlayer->ammoCount[4], 12); - UseAmmo(pPlayer, 4, missile->xspr.data4); - seqSpawn(22, missile, -1); - actBurnSprite(pPlayer->actor, missile, 600); - evPostActor(missile, 0, kCallbackFXFlameLick); - sfxPlay3DSound(missile, 480, 2, 0); - pPlayer->visibility = 30; - pPlayer->flashEffect = 1; - } + int nSpeed = MulScale(0x8000, 0x177777, 16) + 0x66666; + auto missile = playerFireThing(pPlayer, 0, -4730, kThingNapalmBall, nSpeed); + if (missile) + { + missile->xspr.data4 = ClipHigh(pPlayer->ammoCount[4], 12); + UseAmmo(pPlayer, 4, missile->xspr.data4); + seqSpawn(22, missile, -1); + actBurnSprite(pPlayer->actor, missile, 600); + evPostActor(missile, 0, kCallbackFXFlameLick); + sfxPlay3DSound(missile, 480, 2, 0); + pPlayer->visibility = 30; + pPlayer->flashEffect = 1; + } } -void FireLifeLeech(int nTrigger, PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void FireLifeLeech(int nTrigger, PLAYER* pPlayer) { - if (!CheckAmmo(pPlayer, 8, 1)) - return; - int r1 = Random2(2000); - int r2 = Random2(2000); - int r3 = Random2(1000); - DBloodActor* actor = pPlayer->actor; - auto missileActor = playerFireMissile(pPlayer, 0, pPlayer->aim.dx+r1, pPlayer->aim.dy+r2, pPlayer->aim.dz+r3, 315); - if (missileActor) - { - missileActor->SetTarget(pPlayer->aimTarget); - missileActor->spr.ang = (nTrigger==2) ? 1024 : 0; - } - if (checkAmmo2(pPlayer, 8, 1)) - UseAmmo(pPlayer, 8, 1); - else - actDamageSprite(actor, actor, kDamageSpirit, 16); - pPlayer->visibility = ClipHigh(pPlayer->visibility+5, 50); + if (!CheckAmmo(pPlayer, 8, 1)) + return; + int r1 = Random2(2000); + int r2 = Random2(2000); + int r3 = Random2(1000); + DBloodActor* actor = pPlayer->actor; + auto missileActor = playerFireMissile(pPlayer, 0, pPlayer->aim.dx + r1, pPlayer->aim.dy + r2, pPlayer->aim.dz + r3, 315); + if (missileActor) + { + missileActor->SetTarget(pPlayer->aimTarget); + missileActor->spr.ang = (nTrigger == 2) ? 1024 : 0; + } + if (checkAmmo2(pPlayer, 8, 1)) + UseAmmo(pPlayer, 8, 1); + else + actDamageSprite(actor, actor, kDamageSpirit, 16); + pPlayer->visibility = ClipHigh(pPlayer->visibility + 5, 50); } -void AltFireLifeLeech(int , PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void AltFireLifeLeech(int, PLAYER* pPlayer) { - DBloodActor* actor = pPlayer->actor; - sfxPlay3DSound(pPlayer->actor, 455, 2, 0); - auto missile = playerFireThing(pPlayer, 0, -4730, kThingDroppedLifeLeech, 0x19999); - if (missile) - { - missile->spr.cstat |= CSTAT_SPRITE_BLOOD_BIT1; - missile->xspr.Push = 1; - missile->xspr.Proximity = 1; - missile->xspr.DudeLockout = 1; - missile->xspr.data4 = ClipHigh(pPlayer->ammoCount[4], 12); - missile->xspr.stateTimer = 1; - evPostActor(missile, 120, kCallbackLeechStateTimer); - if (gGameOptions.nGameType <= 1) - { - int nAmmo = pPlayer->ammoCount[8]; - if (nAmmo < 25 && pPlayer->actor->xspr.health > unsigned((25-nAmmo)<<4)) - { - actDamageSprite(actor, actor, kDamageSpirit, ((25-nAmmo)<<4)); - nAmmo = 25; - } - missile->xspr.data3 = nAmmo; - UseAmmo(pPlayer, 8, nAmmo); - } - else - { - missile->xspr.data3 = pPlayer->ammoCount[8]; - pPlayer->ammoCount[8] = 0; - } - pPlayer->hasWeapon[9] = 0; - } + DBloodActor* actor = pPlayer->actor; + sfxPlay3DSound(pPlayer->actor, 455, 2, 0); + auto missile = playerFireThing(pPlayer, 0, -4730, kThingDroppedLifeLeech, 0x19999); + if (missile) + { + missile->spr.cstat |= CSTAT_SPRITE_BLOOD_BIT1; + missile->xspr.Push = 1; + missile->xspr.Proximity = 1; + missile->xspr.DudeLockout = 1; + missile->xspr.data4 = ClipHigh(pPlayer->ammoCount[4], 12); + missile->xspr.stateTimer = 1; + evPostActor(missile, 120, kCallbackLeechStateTimer); + if (gGameOptions.nGameType <= 1) + { + int nAmmo = pPlayer->ammoCount[8]; + if (nAmmo < 25 && pPlayer->actor->xspr.health > unsigned((25 - nAmmo) << 4)) + { + actDamageSprite(actor, actor, kDamageSpirit, ((25 - nAmmo) << 4)); + nAmmo = 25; + } + missile->xspr.data3 = nAmmo; + UseAmmo(pPlayer, 8, nAmmo); + } + else + { + missile->xspr.data3 = pPlayer->ammoCount[8]; + pPlayer->ammoCount[8] = 0; + } + pPlayer->hasWeapon[9] = 0; + } } -void FireBeast(int , PLAYER * pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void FireBeast(int, PLAYER* pPlayer) { - DBloodActor* actor = pPlayer->actor; - int r1 = Random2(2000); - int r2 = Random2(2000); - int r3 = Random2(2000); - actFireVector(actor, 0, pPlayer->zWeapon-pPlayer->actor->spr.pos.Z, pPlayer->aim.dx+r1, pPlayer->aim.dy+r2, pPlayer->aim.dz+r3, kVectorBeastSlash); + DBloodActor* actor = pPlayer->actor; + int r1 = Random2(2000); + int r2 = Random2(2000); + int r3 = Random2(2000); + actFireVector(actor, 0, pPlayer->zWeapon - pPlayer->actor->spr.pos.Z, pPlayer->aim.dx + r1, pPlayer->aim.dy + r2, pPlayer->aim.dz + r3, kVectorBeastSlash); } -uint8_t gWeaponUpgrade[][13] = { - { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - { 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0 }, - { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +static const uint8_t gWeaponUpgrade[][13] = { + { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + { 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0 }, + { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, }; -int WeaponUpgrade(PLAYER *pPlayer, int newWeapon) +int WeaponUpgrade(PLAYER* pPlayer, int newWeapon) { - int weapon = pPlayer->curWeapon; - if (!checkFired6or7(pPlayer) && (cl_weaponswitch&1) && (gWeaponUpgrade[pPlayer->curWeapon][newWeapon] || (cl_weaponswitch&2))) - weapon = newWeapon; - return weapon; + int weapon = pPlayer->curWeapon; + if (!checkFired6or7(pPlayer) && (cl_weaponswitch & 1) && (gWeaponUpgrade[pPlayer->curWeapon][newWeapon] || (cl_weaponswitch & 2))) + weapon = newWeapon; + return weapon; } -int OrderNext[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 1 }; -int OrderPrev[] = { 12, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1 }; +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- -static int WeaponFindNext(PLAYER *pPlayer, int *a2, int bDir) +static const int OrderNext[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 1 }; +static const int OrderPrev[] = { 12, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1 }; + +static int WeaponFindNext(PLAYER* pPlayer, int* a2, int bDir) { - int weapon = pPlayer->curWeapon; - do - { - if (bDir) - weapon = OrderNext[weapon]; - else - weapon = OrderPrev[weapon]; - if (weaponModes[weapon].update && pPlayer->hasWeapon[weapon]) - { - if (weapon == kWeapLifeLeech) - { - if (CheckAmmo(pPlayer, weaponModes[weapon].ammoType, 1)) - break; - } - else - { - if (checkAmmo2(pPlayer, weaponModes[weapon].ammoType, 1)) - break; - } - } - } while (weapon != pPlayer->curWeapon); - if (weapon == pPlayer->curWeapon) - { - if (!weaponModes[weapon].update || !CheckAmmo(pPlayer, weaponModes[weapon].ammoType, 1)) - weapon = kWeapPitchFork; - } - if (a2) - *a2 = 0; - return weapon; + int weapon = pPlayer->curWeapon; + do + { + if (bDir) + weapon = OrderNext[weapon]; + else + weapon = OrderPrev[weapon]; + if (weaponModes[weapon].update && pPlayer->hasWeapon[weapon]) + { + if (weapon == kWeapLifeLeech) + { + if (CheckAmmo(pPlayer, weaponModes[weapon].ammoType, 1)) + break; + } + else + { + if (checkAmmo2(pPlayer, weaponModes[weapon].ammoType, 1)) + break; + } + } + } while (weapon != pPlayer->curWeapon); + if (weapon == pPlayer->curWeapon) + { + if (!weaponModes[weapon].update || !CheckAmmo(pPlayer, weaponModes[weapon].ammoType, 1)) + weapon = kWeapPitchFork; + } + if (a2) + *a2 = 0; + return weapon; } -static int WeaponFindLoaded(PLAYER *pPlayer, int *a2) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +static int WeaponFindLoaded(PLAYER* pPlayer, int* a2) { - int v4 = 1; - int v14 = 0; - if (weaponModes[pPlayer->curWeapon].update > 1) - { - for (int i = 0; i < weaponModes[pPlayer->curWeapon].update; i++) - { - if (CheckAmmo(pPlayer, weaponModes[pPlayer->curWeapon].ammoType, 1)) - { - v14 = i; - v4 = pPlayer->curWeapon; - break; - } - } - } - if (v4 == kWeapPitchFork) - { - int vc = 0; - for (int i = 0; i < 14; i++) - { - int weapon = pPlayer->weaponOrder[vc][i]; - if (pPlayer->hasWeapon[weapon]) - { - for (int j = 0; j < weaponModes[weapon].update; j++) - { - if (CheckWeaponAmmo(pPlayer, weapon, weaponModes[weapon].ammoType, 1)) - { - if (a2) - *a2 = j; - return weapon; - } - } - } - } - } - else if (a2) - *a2 = v14; - return v4; + int v4 = 1; + int v14 = 0; + if (weaponModes[pPlayer->curWeapon].update > 1) + { + for (int i = 0; i < weaponModes[pPlayer->curWeapon].update; i++) + { + if (CheckAmmo(pPlayer, weaponModes[pPlayer->curWeapon].ammoType, 1)) + { + v14 = i; + v4 = pPlayer->curWeapon; + break; + } + } + } + if (v4 == kWeapPitchFork) + { + int vc = 0; + for (int i = 0; i < 14; i++) + { + int weapon = pPlayer->weaponOrder[vc][i]; + if (pPlayer->hasWeapon[weapon]) + { + for (int j = 0; j < weaponModes[weapon].update; j++) + { + if (CheckWeaponAmmo(pPlayer, weapon, weaponModes[weapon].ammoType, 1)) + { + if (a2) + *a2 = j; + return weapon; + } + } + } + } + } + else if (a2) + *a2 = v14; + return v4; } -int processSprayCan(PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +int processSprayCan(PLAYER* pPlayer) { - switch (pPlayer->weaponState) - { - case 5: - if (!(pPlayer->input.actions & SB_ALTFIRE)) - pPlayer->weaponState = 6; - return 1; - case 6: - if (pPlayer->input.actions & SB_ALTFIRE) - { - pPlayer->weaponState = 3; - pPlayer->fuseTime = pPlayer->weaponTimer; - StartQAV(pPlayer, kQAVCANDROP, nClientDropCan); - } - else if (pPlayer->input.actions & SB_FIRE) - { - pPlayer->weaponState = 7; - pPlayer->fuseTime = 0; - pPlayer->throwTime = PlayClock; - } - return 1; - case 7: - { - pPlayer->throwPower = ClipHigh(DivScale(PlayClock-pPlayer->throwTime,240, 16), 65536); - if (!(pPlayer->input.actions & SB_FIRE)) - { - if (!pPlayer->fuseTime) - pPlayer->fuseTime = pPlayer->weaponTimer; - pPlayer->weaponState = 1; - StartQAV(pPlayer, kQAVCANTHRO, nClientThrowCan); - } - return 1; - } - } - return 0; + switch (pPlayer->weaponState) + { + case 5: + if (!(pPlayer->input.actions & SB_ALTFIRE)) + pPlayer->weaponState = 6; + return 1; + case 6: + if (pPlayer->input.actions & SB_ALTFIRE) + { + pPlayer->weaponState = 3; + pPlayer->fuseTime = pPlayer->weaponTimer; + StartQAV(pPlayer, kQAVCANDROP, nClientDropCan); + } + else if (pPlayer->input.actions & SB_FIRE) + { + pPlayer->weaponState = 7; + pPlayer->fuseTime = 0; + pPlayer->throwTime = PlayClock; + } + return 1; + case 7: + { + pPlayer->throwPower = ClipHigh(DivScale(PlayClock - pPlayer->throwTime, 240, 16), 65536); + if (!(pPlayer->input.actions & SB_FIRE)) + { + if (!pPlayer->fuseTime) + pPlayer->fuseTime = pPlayer->weaponTimer; + pPlayer->weaponState = 1; + StartQAV(pPlayer, kQAVCANTHRO, nClientThrowCan); + } + return 1; + } + } + return 0; } -static bool processTNT(PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +static bool processTNT(PLAYER* pPlayer) { - switch (pPlayer->weaponState) - { - case 4: - if (!(pPlayer->input.actions & SB_ALTFIRE)) - pPlayer->weaponState = 5; - return 1; - case 5: - if (pPlayer->input.actions & SB_ALTFIRE) - { - pPlayer->weaponState = 1; - pPlayer->fuseTime = pPlayer->weaponTimer; - StartQAV(pPlayer, kQAVBUNDROP, nClientDropBundle); - } - else if (pPlayer->input.actions & SB_FIRE) - { - pPlayer->weaponState = 6; - pPlayer->fuseTime = 0; - pPlayer->throwTime = PlayClock; - } - return 1; - case 6: - { - pPlayer->throwPower = ClipHigh(DivScale(PlayClock-pPlayer->throwTime,240, 16), 65536); - if (!(pPlayer->input.actions & SB_FIRE)) - { - if (!pPlayer->fuseTime) - pPlayer->fuseTime = pPlayer->weaponTimer; - pPlayer->weaponState = 1; - StartQAV(pPlayer, kQAVBUNTHRO, nClientThrowBundle); - } - return 1; - } - } - return 0; + switch (pPlayer->weaponState) + { + case 4: + if (!(pPlayer->input.actions & SB_ALTFIRE)) + pPlayer->weaponState = 5; + return 1; + case 5: + if (pPlayer->input.actions & SB_ALTFIRE) + { + pPlayer->weaponState = 1; + pPlayer->fuseTime = pPlayer->weaponTimer; + StartQAV(pPlayer, kQAVBUNDROP, nClientDropBundle); + } + else if (pPlayer->input.actions & SB_FIRE) + { + pPlayer->weaponState = 6; + pPlayer->fuseTime = 0; + pPlayer->throwTime = PlayClock; + } + return 1; + case 6: + { + pPlayer->throwPower = ClipHigh(DivScale(PlayClock - pPlayer->throwTime, 240, 16), 65536); + if (!(pPlayer->input.actions & SB_FIRE)) + { + if (!pPlayer->fuseTime) + pPlayer->fuseTime = pPlayer->weaponTimer; + pPlayer->weaponState = 1; + StartQAV(pPlayer, kQAVBUNTHRO, nClientThrowBundle); + } + return 1; + } + } + return 0; } -static bool processProxy(PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +static bool processProxy(PLAYER* pPlayer) { - switch (pPlayer->weaponState) - { - case 9: - pPlayer->throwPower = ClipHigh(DivScale(PlayClock-pPlayer->throwTime,240, 16), 65536); - pPlayer->weaponTimer = 0; - pPlayer->qavTimer = 0; - if (!(pPlayer->input.actions & SB_FIRE)) - { - pPlayer->weaponState = 8; - StartQAV(pPlayer, kQAVPROXTHRO, nClientThrowProx); - } - break; - } - return 0; + switch (pPlayer->weaponState) + { + case 9: + pPlayer->throwPower = ClipHigh(DivScale(PlayClock - pPlayer->throwTime, 240, 16), 65536); + pPlayer->weaponTimer = 0; + pPlayer->qavTimer = 0; + if (!(pPlayer->input.actions & SB_FIRE)) + { + pPlayer->weaponState = 8; + StartQAV(pPlayer, kQAVPROXTHRO, nClientThrowProx); + } + break; + } + return 0; } -static bool processRemote(PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +static bool processRemote(PLAYER* pPlayer) { - switch (pPlayer->weaponState) - { - case 13: - pPlayer->throwPower = ClipHigh(DivScale(PlayClock-pPlayer->throwTime,240, 16), 65536); - if (!(pPlayer->input.actions & SB_FIRE)) - { - pPlayer->weaponState = 11; - StartQAV(pPlayer, kQAVREMTHRO, nClientThrowRemote); - } - break; - } - return 0; + switch (pPlayer->weaponState) + { + case 13: + pPlayer->throwPower = ClipHigh(DivScale(PlayClock - pPlayer->throwTime, 240, 16), 65536); + if (!(pPlayer->input.actions & SB_FIRE)) + { + pPlayer->weaponState = 11; + StartQAV(pPlayer, kQAVREMTHRO, nClientThrowRemote); + } + break; + } + return 0; } -static bool processLeech(PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +static bool processLeech(PLAYER* pPlayer) { - switch (pPlayer->weaponState) - { - case 4: - pPlayer->weaponState = 6; - StartQAV(pPlayer, kQAVSTAFIRE1, nClientFireLifeLeech, 1); - return 1; - case 6: - if (!(pPlayer->input.actions & SB_ALTFIRE)) - { - pPlayer->weaponState = 2; - StartQAV(pPlayer, kQAVSTAFPOST); - return 1; - } - break; - case 8: - pPlayer->weaponState = 2; - StartQAV(pPlayer, kQAVSTAFPOST); - return 1; - } - return 0; + switch (pPlayer->weaponState) + { + case 4: + pPlayer->weaponState = 6; + StartQAV(pPlayer, kQAVSTAFIRE1, nClientFireLifeLeech, 1); + return 1; + case 6: + if (!(pPlayer->input.actions & SB_ALTFIRE)) + { + pPlayer->weaponState = 2; + StartQAV(pPlayer, kQAVSTAFPOST); + return 1; + } + break; + case 8: + pPlayer->weaponState = 2; + StartQAV(pPlayer, kQAVSTAFPOST); + return 1; + } + return 0; } -static bool processTesla(PLAYER *pPlayer) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +static bool processTesla(PLAYER* pPlayer) { - switch (pPlayer->weaponState) - { - case 4: - pPlayer->weaponState = 5; - if (checkAmmo2(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns)) - StartQAV(pPlayer, kQAV2SGUNFIR, nClientFireTesla, 1); - else - StartQAV(pPlayer, kQAVSGUNFIR1, nClientFireTesla, 1); - return 1; - case 5: - if (!(pPlayer->input.actions & SB_FIRE)) - { - pPlayer->weaponState = 2; - if (checkAmmo2(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns)) - StartQAV(pPlayer, kQAV2SGUNPST); - else - StartQAV(pPlayer, kQAVSGUNPOST); - return 1; - } - break; - case 7: - pPlayer->weaponState = 2; - if (checkAmmo2(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns)) - StartQAV(pPlayer, kQAV2SGUNPST); - else - StartQAV(pPlayer, kQAVSGUNPOST); - return 1; - } - return 0; + switch (pPlayer->weaponState) + { + case 4: + pPlayer->weaponState = 5; + if (checkAmmo2(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns)) + StartQAV(pPlayer, kQAV2SGUNFIR, nClientFireTesla, 1); + else + StartQAV(pPlayer, kQAVSGUNFIR1, nClientFireTesla, 1); + return 1; + case 5: + if (!(pPlayer->input.actions & SB_FIRE)) + { + pPlayer->weaponState = 2; + if (checkAmmo2(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns)) + StartQAV(pPlayer, kQAV2SGUNPST); + else + StartQAV(pPlayer, kQAVSGUNPOST); + return 1; + } + break; + case 7: + pPlayer->weaponState = 2; + if (checkAmmo2(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns)) + StartQAV(pPlayer, kQAV2SGUNPST); + else + StartQAV(pPlayer, kQAVSGUNPOST); + return 1; + } + return 0; } -void WeaponProcess(PLAYER *pPlayer) { +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- - pPlayer->flashEffect = ClipLow(pPlayer->flashEffect - 1, 0); - - #ifdef NOONE_EXTENSIONS - if (gPlayerCtrl[pPlayer->nPlayer].qavScene.initiator != nullptr && pPlayer->actor->xspr.health > 0) { - playerQavSceneProcess(pPlayer, &gPlayerCtrl[pPlayer->nPlayer].qavScene); - UpdateAimVector(pPlayer); - return; - } - #endif +void WeaponProcess(PLAYER* pPlayer) { - if (pPlayer->actor->xspr.health == 0) - { - pPlayer->qavLoop = 0; - sfxKill3DSound(pPlayer->actor, 1, -1); - } - if (pPlayer->isUnderwater && BannedUnderwater(pPlayer->curWeapon)) - { - if (checkFired6or7(pPlayer)) - { - if (pPlayer->curWeapon == kWeapSpraycan) - { - pPlayer->fuseTime = pPlayer->weaponTimer; - DropCan(1, pPlayer); - pPlayer->weaponState = 3; - } - else if (pPlayer->curWeapon == kWeapDynamite) - { - pPlayer->fuseTime = pPlayer->weaponTimer; - DropBundle(1, pPlayer); - pPlayer->weaponState = 1; - } - } - WeaponLower(pPlayer); - pPlayer->throwPower = 0; - } - WeaponPlay(pPlayer); - UpdateAimVector(pPlayer); - pPlayer->weaponTimer -= 4; - bool bShoot = pPlayer->input.actions & SB_FIRE; - bool bShoot2 = pPlayer->input.actions & SB_ALTFIRE; - 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->actor->xspr.health > 0) - { - if (bShoot && CheckAmmo(pPlayer, pPlayer->weaponAmmo, 1)) - { - auto pQAV = getQAV(pPlayer->weaponQav); - while (pPlayer->weaponTimer <= 0) - { - pPlayer->weaponTimer += pQAV->duration; - pPlayer->qavTimer += pQAV->duration; - } - } - else - { - pPlayer->weaponTimer = 0; - pPlayer->qavTimer = 0; - pPlayer->qavLoop = 0; - } - return; - } - pPlayer->weaponTimer = ClipLow(pPlayer->weaponTimer, 0); - switch (pPlayer->curWeapon) - { - case kWeapSpraycan: - if (processSprayCan(pPlayer)) - return; - break; - case kWeapDynamite: - if (processTNT(pPlayer)) - return; - break; - case kWeapProximity: - if (processProxy(pPlayer)) - return; - break; - case kWeapRemote: - if (processRemote(pPlayer)) - return; - break; - } - if (pPlayer->weaponTimer > 0) - return; - if (pPlayer->actor->xspr.health == 0 || pPlayer->curWeapon == kWeapNone) - pPlayer->weaponQav = kQAVNone; - switch (pPlayer->curWeapon) - { - case kWeapLifeLeech: - if (processLeech(pPlayer)) - return; - break; - case kWeapTeslaCannon: - if (processTesla(pPlayer)) - return; - break; - } - if (VanillaMode()) - { - if (pPlayer->nextWeapon) - { - sfxKill3DSound(pPlayer->actor, -1, 441); - pPlayer->weaponState = 0; - pPlayer->newWeapon = pPlayer->nextWeapon; - pPlayer->nextWeapon = kWeapNone; - } - } - if (pPlayer->input.getNewWeapon() == WeaponSel_Next) - { - pPlayer->input.setNewWeapon(kWeapNone); - if (VanillaMode()) - { - pPlayer->weaponState = 0; - } - pPlayer->nextWeapon = kWeapNone; - int t; - int weapon = WeaponFindNext(pPlayer, &t, 1); - pPlayer->weaponMode[weapon] = t; - if (VanillaMode()) - { - if (pPlayer->curWeapon) - { - WeaponLower(pPlayer); - pPlayer->nextWeapon = weapon; - return; - } - } - pPlayer->newWeapon = weapon; - } - else if (pPlayer->input.getNewWeapon() == WeaponSel_Prev) - { - pPlayer->input.setNewWeapon(kWeapNone); - if (VanillaMode()) - { - pPlayer->weaponState = 0; - } - pPlayer->nextWeapon = kWeapNone; - int t; - int weapon = WeaponFindNext(pPlayer, &t, 0); - pPlayer->weaponMode[weapon] = t; - if (VanillaMode()) - { - if (pPlayer->curWeapon) - { - WeaponLower(pPlayer); - pPlayer->nextWeapon = weapon; - return; - } - } - pPlayer->newWeapon = weapon; - } - else if (pPlayer->input.getNewWeapon() == WeaponSel_Alt) - { - int weapon; + pPlayer->flashEffect = ClipLow(pPlayer->flashEffect - 1, 0); - switch (pPlayer->curWeapon) - { - case kWeapDynamite: - weapon = kWeapProximity; - break; - case kWeapProximity: - weapon = kWeapRemote; - break; - case kWeapRemote: - weapon = kWeapDynamite; - break; - default: - return; - } - - pPlayer->input.setNewWeapon(kWeapNone); - pPlayer->weaponState = 0; - pPlayer->nextWeapon = kWeapNone; - int t = 0; - pPlayer->weaponMode[weapon] = t; - if (pPlayer->curWeapon) - { - WeaponLower(pPlayer); - pPlayer->nextWeapon = weapon; - return; - } - pPlayer->newWeapon = weapon; - } - if (!VanillaMode()) - { - if (pPlayer->nextWeapon) - { - sfxKill3DSound(pPlayer->actor, -1, 441); - pPlayer->newWeapon = pPlayer->nextWeapon; - pPlayer->nextWeapon = kWeapNone; - } - } - if (pPlayer->weaponState == -1) - { - pPlayer->weaponState = 0; - int t; - int weapon = WeaponFindLoaded(pPlayer, &t); - pPlayer->weaponMode[weapon] = t; - if (pPlayer->curWeapon) - { - WeaponLower(pPlayer); - pPlayer->nextWeapon = weapon; - return; - } - pPlayer->newWeapon = weapon; - } - if (pPlayer->newWeapon) - { - if (pPlayer->isUnderwater && BannedUnderwater(pPlayer->newWeapon) && !checkFired6or7(pPlayer) && !VanillaMode()) // skip banned weapons when underwater and using next/prev weapon key inputs - { - if (prevNewWeaponVal == WeaponSel_Next || prevNewWeaponVal == WeaponSel_Prev) // if player switched weapons - { - int saveweapon = pPlayer->curWeapon; - pPlayer->curWeapon = pPlayer->newWeapon; // set current banned weapon to curweapon so WeaponFindNext() can find the next weapon - for (int i = 0; i < 3; i++) // attempt twice to find a new weapon - { - pPlayer->curWeapon = WeaponFindNext(pPlayer, NULL, (char)(prevNewWeaponVal == WeaponSel_Next)); - if (!BannedUnderwater(pPlayer->curWeapon)) // if new weapon is not a banned weapon, set to new current weapon - { - pPlayer->newWeapon = pPlayer->curWeapon; - pPlayer->weaponMode[pPlayer->newWeapon] = 0; - break; - } - } - pPlayer->curWeapon = saveweapon; - } - } - if (pPlayer->newWeapon == kWeapDynamite) - { - if (pPlayer->curWeapon == kWeapDynamite) - { - if (checkAmmo2(pPlayer, 10, 1)) - pPlayer->newWeapon = kWeapProximity; - else if (checkAmmo2(pPlayer, 11, 1)) - pPlayer->newWeapon = kWeapRemote; - } - else if (pPlayer->curWeapon == kWeapProximity) - { - if (checkAmmo2(pPlayer, 11, 1)) - pPlayer->newWeapon = kWeapRemote; - else if (checkAmmo2(pPlayer, 5, 1) && pPlayer->isUnderwater == 0) - pPlayer->newWeapon = kWeapDynamite; - } - else if (pPlayer->curWeapon == kWeapRemote) - { - if (checkAmmo2(pPlayer, 5, 1) && pPlayer->isUnderwater == 0) - pPlayer->newWeapon = kWeapDynamite; - else if (checkAmmo2(pPlayer, 10, 1)) - pPlayer->newWeapon = kWeapProximity; - } - else - { - if (checkAmmo2(pPlayer, 5, 1) && pPlayer->isUnderwater == 0) - pPlayer->newWeapon = kWeapDynamite; - else if (checkAmmo2(pPlayer, 10, 1)) - pPlayer->newWeapon = kWeapProximity; - else if (checkAmmo2(pPlayer, 11, 1)) - pPlayer->newWeapon = kWeapRemote; - } - } - else if ((pPlayer->newWeapon == kWeapSpraycan) && !VanillaMode()) - { - if ((pPlayer->curWeapon == kWeapSpraycan) && (pPlayer->weaponState == 2)) // fix spray can state glitch when switching from spray to tnt and back quickly - { - pPlayer->weaponState = 1; - pPlayer->newWeapon = kWeapNone; - return; - } - } - if (pPlayer->actor->xspr.health == 0 || pPlayer->hasWeapon[pPlayer->newWeapon] == 0) - { - pPlayer->newWeapon = kWeapNone; - return; - } - if (pPlayer->isUnderwater && BannedUnderwater(pPlayer->newWeapon) && !checkFired6or7(pPlayer)) - { - pPlayer->newWeapon = kWeapNone; - return; - } - int nWeapon = pPlayer->newWeapon; - int v4c = weaponModes[nWeapon].update; - if (!pPlayer->curWeapon) - { - int nAmmoType = weaponModes[nWeapon].ammoType; - if (v4c > 1) - { - if (CheckAmmo(pPlayer, nAmmoType, 1) || nAmmoType == 11) - WeaponRaise(pPlayer); - pPlayer->newWeapon = kWeapNone; - } - else - { - if (CheckWeaponAmmo(pPlayer, nWeapon, nAmmoType, 1)) - WeaponRaise(pPlayer); - else - { - pPlayer->weaponState = 0; - int t; - int weapon = WeaponFindLoaded(pPlayer, &t); - pPlayer->weaponMode[weapon] = t; - if (pPlayer->curWeapon) - { - WeaponLower(pPlayer); - pPlayer->nextWeapon = weapon; - return; - } - pPlayer->newWeapon = weapon; - } - } - return; - } - if (nWeapon == pPlayer->curWeapon && v4c <= 1) - { - pPlayer->newWeapon = kWeapNone; - return; - } - int i = 0; - if (nWeapon == pPlayer->curWeapon) - i = 1; - for (; i <= v4c; i++) - { - int v6c = (pPlayer->weaponMode[nWeapon]+i)%v4c; - if (CheckWeaponAmmo(pPlayer, nWeapon, weaponModes[nWeapon].ammoType, 1)) - { - WeaponLower(pPlayer); - pPlayer->weaponMode[nWeapon] = v6c; - return; - } - } - pPlayer->newWeapon = kWeapNone; - return; - } - if (pPlayer->curWeapon && !CheckAmmo(pPlayer, pPlayer->weaponAmmo, 1) && pPlayer->weaponAmmo != 11) - { - pPlayer->weaponState = -1; - return; - } - if (bShoot) - { - switch (pPlayer->curWeapon) - { - case kWeapPitchFork: - StartQAV(pPlayer, kQAVPFORK, nClientFirePitchfork); - return; - case kWeapSpraycan: - switch (pPlayer->weaponState) - { - case 3: - pPlayer->weaponState = 4; - StartQAV(pPlayer, kQAVCANFIRE, nClientFireSpray, 1); - return; - } - break; - case kWeapDynamite: - switch (pPlayer->weaponState) - { - case 3: - pPlayer->weaponState = 6; - pPlayer->fuseTime = -1; - pPlayer->throwTime = PlayClock; - StartQAV(pPlayer, kQAVBUNFUSE, nClientExplodeBundle); - return; - } - break; - case kWeapProximity: - switch (pPlayer->weaponState) - { - case 7: - SetQAV(pPlayer, kQAVPROXIDLE); - pPlayer->weaponState = 9; - pPlayer->throwTime = PlayClock; - return; - } - break; - case kWeapRemote: - switch (pPlayer->weaponState) - { - case 10: - SetQAV(pPlayer, kQAVREMIDLE1); - pPlayer->weaponState = 13; - pPlayer->throwTime = PlayClock; - return; - case 11: - pPlayer->weaponState = 12; - StartQAV(pPlayer, kQAVREMFIRE, nClientFireRemote); - return; - } - break; - case kWeapShotgun: - switch (pPlayer->weaponState) - { - case 7: - pPlayer->weaponState = 6; - StartQAV(pPlayer, kQAV2SHOTF2, nClientFireShotgun); - return; - case 3: - pPlayer->weaponState = 2; - StartQAV(pPlayer, kQAVSHOTF1, nClientFireShotgun); - return; - case 2: - pPlayer->weaponState = 1; - StartQAV(pPlayer, kQAVSHOTF2, nClientFireShotgun); - return; - } - break; - case kWeapTommyGun: - if (powerupCheck(pPlayer, kPwUpTwoGuns) && checkAmmo2(pPlayer, 3, 2)) - StartQAV(pPlayer, kQAV2TOMFIRE, nClientFireTommy, 1); - else - StartQAV(pPlayer, kQAVTOMFIRE, nClientFireTommy, 1); - return; - case kWeapFlareGun: - if (powerupCheck(pPlayer, kPwUpTwoGuns) && checkAmmo2(pPlayer, 1, 2)) - StartQAV(pPlayer, kQAVFLAR2FIR, nClientFireFlare); - else - StartQAV(pPlayer, kQAVFLARFIR2, nClientFireFlare); - return; - case kWeapVoodooDoll: - { - static int nChance[] = { 0xa000, 0xc000, 0xe000, 0x10000 }; - int nRand = wrand()*2; - int i; - for (i = 0; nChance[i] < nRand; i++) - { - } - pPlayer->voodooTarget = pPlayer->aimTarget; - if (pPlayer->voodooTarget == nullptr || pPlayer->voodooTarget->spr.statnum != kStatDude) - i = 4; - StartQAV(pPlayer,kQAVVDFIRE1 + i, nClientFireVoodoo); - return; - } - case kWeapTeslaCannon: - switch (pPlayer->weaponState) - { - case 2: - pPlayer->weaponState = 4; - if (checkAmmo2(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns)) - StartQAV(pPlayer, kQAV2SGUNFIR, nClientFireTesla); - else - StartQAV(pPlayer, kQAVSGUNFIR1, nClientFireTesla); - return; - case 5: - if (checkAmmo2(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns)) - StartQAV(pPlayer, kQAV2SGUNFIR, nClientFireTesla); - else - StartQAV(pPlayer, kQAVSGUNFIR1, nClientFireTesla); - return; - } - break; - case kWeapNapalm: - if (powerupCheck(pPlayer, kPwUpTwoGuns)) - StartQAV(pPlayer, kQAV2NAPFIRE, nClientFireNapalm); - else - StartQAV(pPlayer, kQAVNAPFIRE, nClientFireNapalm); - return; - case kWeapLifeLeech: - sfxPlay3DSound(pPlayer->actor, 494, 2, 0); - StartQAV(pPlayer, kQAVSTAFIRE4, nClientFireLifeLeech); - return; - case kWeapBeast: - StartQAV(pPlayer, kQAVBSTATAK1 + Random(4), nClientFireBeast); - return; - } - } - if (bShoot2) - { - switch (pPlayer->curWeapon) - { - case kWeapPitchFork: - StartQAV(pPlayer, kQAVPFORK, nClientFirePitchfork); - return; - case kWeapSpraycan: - switch (pPlayer->weaponState) - { - case 3: - pPlayer->weaponState = 5; - StartQAV(pPlayer, kQAVCANFIRE2, nClientExplodeCan); - return; - } - break; - case kWeapDynamite: - switch (pPlayer->weaponState) - { - case 3: - pPlayer->weaponState = 4; - StartQAV(pPlayer, kQAVBUNFUSE, nClientExplodeBundle); - return; - case 7: - pPlayer->weaponState = 8; - StartQAV(pPlayer, kQAVPROXDROP, nClientDropProx); - return; - case 10: - pPlayer->weaponState = 11; - StartQAV(pPlayer, kQAVREMDROP, nClientDropRemote); - return; - case 11: - if (pPlayer->ammoCount[11] > 0) - { - pPlayer->weaponState = 10; - StartQAV(pPlayer, kQAVREMUP1); - } - return; - } - break; - case kWeapProximity: - switch (pPlayer->weaponState) - { - case 7: - pPlayer->weaponState = 8; - StartQAV(pPlayer, kQAVPROXDROP, nClientDropProx); - return; - } - break; - case kWeapRemote: - switch (pPlayer->weaponState) - { - case 10: - pPlayer->weaponState = 11; - StartQAV(pPlayer, kQAVREMDROP, nClientDropRemote); - return; - case 11: - if (pPlayer->ammoCount[11] > 0) - { - pPlayer->weaponState = 10; - StartQAV(pPlayer, kQAVREMUP1); - } - return; - } - break; - case kWeapShotgun: - switch (pPlayer->weaponState) - { - case 7: - pPlayer->weaponState = 6; - StartQAV(pPlayer, kQAV2SHOTFIR, nClientFireShotgun); - return; - case 3: - pPlayer->weaponState = 1; - StartQAV(pPlayer, kQAVSHOTF3, nClientFireShotgun); - return; - case 2: - pPlayer->weaponState = 1; - StartQAV(pPlayer, kQAVSHOTF2, nClientFireShotgun); - return; - } - break; - case kWeapTommyGun: - if (powerupCheck(pPlayer, kPwUpTwoGuns) && checkAmmo2(pPlayer, 3, 2)) - StartQAV(pPlayer, kQAV2TOMALT, nClientAltFireSpread2); - else - StartQAV(pPlayer, kQAVTOMSPRED, nClientAltFireSpread2); - return; - case kWeapVoodooDoll: - sfxPlay3DSound(pPlayer->actor, 461, 2, 0); - StartQAV(pPlayer, kQAVVDSPEL1, nClientAltFireVoodoo); - return; -#if 0 - case kWeapFlareGun: - if (powerupCheck(pPlayer, kPwUpTwoGuns) && checkAmmo2(pPlayer, 1, 2)) - StartQAV(pPlayer, kQAVFLAR2FIR, nClientFireFlare, 0); - else - StartQAV(pPlayer, kQAVFLARFIR2, nClientFireFlare, 0); - return; +#ifdef NOONE_EXTENSIONS + if (gPlayerCtrl[pPlayer->nPlayer].qavScene.initiator != nullptr && pPlayer->actor->xspr.health > 0) { + playerQavSceneProcess(pPlayer, &gPlayerCtrl[pPlayer->nPlayer].qavScene); + UpdateAimVector(pPlayer); + return; + } #endif - case kWeapTeslaCannon: - if (checkAmmo2(pPlayer, 7, 35)) - { - if (checkAmmo2(pPlayer, 7, 70) && powerupCheck(pPlayer, kPwUpTwoGuns)) - StartQAV(pPlayer, kQAV2SGUNALT, nClientFireTesla); - else - StartQAV(pPlayer, kQAVSGUNFIR4, nClientFireTesla); - } - else - { - if (checkAmmo2(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns)) - StartQAV(pPlayer, kQAV2SGUNFIR, nClientFireTesla); - else - StartQAV(pPlayer, kQAVSGUNFIR1, nClientFireTesla); - } - return; - case kWeapNapalm: - if (powerupCheck(pPlayer, kPwUpTwoGuns)) - // by NoOne: allow napalm launcher alt fire act like in v1.0x versions - if (gGameOptions.weaponsV10x && !VanillaMode()) StartQAV(pPlayer, kQAV2NAPFIR2, nClientFireNapalm2); - else StartQAV(pPlayer, kQAV2NAPFIRE, nClientAltFireNapalm); - else - StartQAV(pPlayer, kQAVNAPFIRE, (gGameOptions.weaponsV10x && !VanillaMode()) ? nClientFireNapalm : nClientAltFireNapalm); - return; - case kWeapFlareGun: - if (CheckAmmo(pPlayer, 1, 8)) - { - if (powerupCheck(pPlayer, kPwUpTwoGuns) && checkAmmo2(pPlayer, 1, 16)) - StartQAV(pPlayer, kQAVFLAR2FIR, nClientAltFireFlare); - else - StartQAV(pPlayer, kQAVFLARFIR2, nClientAltFireFlare); - } - else - { - if (powerupCheck(pPlayer, kPwUpTwoGuns) && checkAmmo2(pPlayer, 1, 2)) - StartQAV(pPlayer, kQAVFLAR2FIR, nClientFireFlare); - else - StartQAV(pPlayer, kQAVFLARFIR2, nClientFireFlare); - } - return; - case kWeapLifeLeech: - if (gGameOptions.nGameType <= 1 && !checkAmmo2(pPlayer, 8, 1) && pPlayer->actor->xspr.health < (25 << 4)) - { - sfxPlay3DSound(pPlayer->actor, 494, 2, 0); - StartQAV(pPlayer, kQAVSTAFIRE4, nClientFireLifeLeech); - } - else - { - StartQAV(pPlayer, kQAVSTAFDOWN); - AltFireLifeLeech(1, pPlayer); - pPlayer->weaponState = -1; - } - return; - } - } - WeaponUpdateState(pPlayer); + + if (pPlayer->actor->xspr.health == 0) + { + pPlayer->qavLoop = 0; + sfxKill3DSound(pPlayer->actor, 1, -1); + } + if (pPlayer->isUnderwater && BannedUnderwater(pPlayer->curWeapon)) + { + if (checkFired6or7(pPlayer)) + { + if (pPlayer->curWeapon == kWeapSpraycan) + { + pPlayer->fuseTime = pPlayer->weaponTimer; + DropCan(1, pPlayer); + pPlayer->weaponState = 3; + } + else if (pPlayer->curWeapon == kWeapDynamite) + { + pPlayer->fuseTime = pPlayer->weaponTimer; + DropBundle(1, pPlayer); + pPlayer->weaponState = 1; + } + } + WeaponLower(pPlayer); + pPlayer->throwPower = 0; + } + WeaponPlay(pPlayer); + UpdateAimVector(pPlayer); + pPlayer->weaponTimer -= 4; + bool bShoot = pPlayer->input.actions & SB_FIRE; + bool bShoot2 = pPlayer->input.actions & SB_ALTFIRE; + 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->actor->xspr.health > 0) + { + if (bShoot && CheckAmmo(pPlayer, pPlayer->weaponAmmo, 1)) + { + auto pQAV = getQAV(pPlayer->weaponQav); + while (pPlayer->weaponTimer <= 0) + { + pPlayer->weaponTimer += pQAV->duration; + pPlayer->qavTimer += pQAV->duration; + } + } + else + { + pPlayer->weaponTimer = 0; + pPlayer->qavTimer = 0; + pPlayer->qavLoop = 0; + } + return; + } + pPlayer->weaponTimer = ClipLow(pPlayer->weaponTimer, 0); + switch (pPlayer->curWeapon) + { + case kWeapSpraycan: + if (processSprayCan(pPlayer)) + return; + break; + case kWeapDynamite: + if (processTNT(pPlayer)) + return; + break; + case kWeapProximity: + if (processProxy(pPlayer)) + return; + break; + case kWeapRemote: + if (processRemote(pPlayer)) + return; + break; + } + if (pPlayer->weaponTimer > 0) + return; + if (pPlayer->actor->xspr.health == 0 || pPlayer->curWeapon == kWeapNone) + pPlayer->weaponQav = kQAVNone; + switch (pPlayer->curWeapon) + { + case kWeapLifeLeech: + if (processLeech(pPlayer)) + return; + break; + case kWeapTeslaCannon: + if (processTesla(pPlayer)) + return; + break; + } + if (VanillaMode()) + { + if (pPlayer->nextWeapon) + { + sfxKill3DSound(pPlayer->actor, -1, 441); + pPlayer->weaponState = 0; + pPlayer->newWeapon = pPlayer->nextWeapon; + pPlayer->nextWeapon = kWeapNone; + } + } + if (pPlayer->input.getNewWeapon() == WeaponSel_Next) + { + pPlayer->input.setNewWeapon(kWeapNone); + if (VanillaMode()) + { + pPlayer->weaponState = 0; + } + pPlayer->nextWeapon = kWeapNone; + int t; + int weapon = WeaponFindNext(pPlayer, &t, 1); + pPlayer->weaponMode[weapon] = t; + if (VanillaMode()) + { + if (pPlayer->curWeapon) + { + WeaponLower(pPlayer); + pPlayer->nextWeapon = weapon; + return; + } + } + pPlayer->newWeapon = weapon; + } + else if (pPlayer->input.getNewWeapon() == WeaponSel_Prev) + { + pPlayer->input.setNewWeapon(kWeapNone); + if (VanillaMode()) + { + pPlayer->weaponState = 0; + } + pPlayer->nextWeapon = kWeapNone; + int t; + int weapon = WeaponFindNext(pPlayer, &t, 0); + pPlayer->weaponMode[weapon] = t; + if (VanillaMode()) + { + if (pPlayer->curWeapon) + { + WeaponLower(pPlayer); + pPlayer->nextWeapon = weapon; + return; + } + } + pPlayer->newWeapon = weapon; + } + else if (pPlayer->input.getNewWeapon() == WeaponSel_Alt) + { + int weapon; + + switch (pPlayer->curWeapon) + { + case kWeapDynamite: + weapon = kWeapProximity; + break; + case kWeapProximity: + weapon = kWeapRemote; + break; + case kWeapRemote: + weapon = kWeapDynamite; + break; + default: + return; + } + + pPlayer->input.setNewWeapon(kWeapNone); + pPlayer->weaponState = 0; + pPlayer->nextWeapon = kWeapNone; + int t = 0; + pPlayer->weaponMode[weapon] = t; + if (pPlayer->curWeapon) + { + WeaponLower(pPlayer); + pPlayer->nextWeapon = weapon; + return; + } + pPlayer->newWeapon = weapon; + } + if (!VanillaMode()) + { + if (pPlayer->nextWeapon) + { + sfxKill3DSound(pPlayer->actor, -1, 441); + pPlayer->newWeapon = pPlayer->nextWeapon; + pPlayer->nextWeapon = kWeapNone; + } + } + if (pPlayer->weaponState == -1) + { + pPlayer->weaponState = 0; + int t; + int weapon = WeaponFindLoaded(pPlayer, &t); + pPlayer->weaponMode[weapon] = t; + if (pPlayer->curWeapon) + { + WeaponLower(pPlayer); + pPlayer->nextWeapon = weapon; + return; + } + pPlayer->newWeapon = weapon; + } + if (pPlayer->newWeapon) + { + if (pPlayer->isUnderwater && BannedUnderwater(pPlayer->newWeapon) && !checkFired6or7(pPlayer) && !VanillaMode()) // skip banned weapons when underwater and using next/prev weapon key inputs + { + if (prevNewWeaponVal == WeaponSel_Next || prevNewWeaponVal == WeaponSel_Prev) // if player switched weapons + { + int saveweapon = pPlayer->curWeapon; + pPlayer->curWeapon = pPlayer->newWeapon; // set current banned weapon to curweapon so WeaponFindNext() can find the next weapon + for (int i = 0; i < 3; i++) // attempt twice to find a new weapon + { + pPlayer->curWeapon = WeaponFindNext(pPlayer, NULL, (char)(prevNewWeaponVal == WeaponSel_Next)); + if (!BannedUnderwater(pPlayer->curWeapon)) // if new weapon is not a banned weapon, set to new current weapon + { + pPlayer->newWeapon = pPlayer->curWeapon; + pPlayer->weaponMode[pPlayer->newWeapon] = 0; + break; + } + } + pPlayer->curWeapon = saveweapon; + } + } + if (pPlayer->newWeapon == kWeapDynamite) + { + if (pPlayer->curWeapon == kWeapDynamite) + { + if (checkAmmo2(pPlayer, 10, 1)) + pPlayer->newWeapon = kWeapProximity; + else if (checkAmmo2(pPlayer, 11, 1)) + pPlayer->newWeapon = kWeapRemote; + } + else if (pPlayer->curWeapon == kWeapProximity) + { + if (checkAmmo2(pPlayer, 11, 1)) + pPlayer->newWeapon = kWeapRemote; + else if (checkAmmo2(pPlayer, 5, 1) && pPlayer->isUnderwater == 0) + pPlayer->newWeapon = kWeapDynamite; + } + else if (pPlayer->curWeapon == kWeapRemote) + { + if (checkAmmo2(pPlayer, 5, 1) && pPlayer->isUnderwater == 0) + pPlayer->newWeapon = kWeapDynamite; + else if (checkAmmo2(pPlayer, 10, 1)) + pPlayer->newWeapon = kWeapProximity; + } + else + { + if (checkAmmo2(pPlayer, 5, 1) && pPlayer->isUnderwater == 0) + pPlayer->newWeapon = kWeapDynamite; + else if (checkAmmo2(pPlayer, 10, 1)) + pPlayer->newWeapon = kWeapProximity; + else if (checkAmmo2(pPlayer, 11, 1)) + pPlayer->newWeapon = kWeapRemote; + } + } + else if ((pPlayer->newWeapon == kWeapSpraycan) && !VanillaMode()) + { + if ((pPlayer->curWeapon == kWeapSpraycan) && (pPlayer->weaponState == 2)) // fix spray can state glitch when switching from spray to tnt and back quickly + { + pPlayer->weaponState = 1; + pPlayer->newWeapon = kWeapNone; + return; + } + } + if (pPlayer->actor->xspr.health == 0 || pPlayer->hasWeapon[pPlayer->newWeapon] == 0) + { + pPlayer->newWeapon = kWeapNone; + return; + } + if (pPlayer->isUnderwater && BannedUnderwater(pPlayer->newWeapon) && !checkFired6or7(pPlayer)) + { + pPlayer->newWeapon = kWeapNone; + return; + } + int nWeapon = pPlayer->newWeapon; + int v4c = weaponModes[nWeapon].update; + if (!pPlayer->curWeapon) + { + int nAmmoType = weaponModes[nWeapon].ammoType; + if (v4c > 1) + { + if (CheckAmmo(pPlayer, nAmmoType, 1) || nAmmoType == 11) + WeaponRaise(pPlayer); + pPlayer->newWeapon = kWeapNone; + } + else + { + if (CheckWeaponAmmo(pPlayer, nWeapon, nAmmoType, 1)) + WeaponRaise(pPlayer); + else + { + pPlayer->weaponState = 0; + int t; + int weapon = WeaponFindLoaded(pPlayer, &t); + pPlayer->weaponMode[weapon] = t; + if (pPlayer->curWeapon) + { + WeaponLower(pPlayer); + pPlayer->nextWeapon = weapon; + return; + } + pPlayer->newWeapon = weapon; + } + } + return; + } + if (nWeapon == pPlayer->curWeapon && v4c <= 1) + { + pPlayer->newWeapon = kWeapNone; + return; + } + int i = 0; + if (nWeapon == pPlayer->curWeapon) + i = 1; + for (; i <= v4c; i++) + { + int v6c = (pPlayer->weaponMode[nWeapon] + i) % v4c; + if (CheckWeaponAmmo(pPlayer, nWeapon, weaponModes[nWeapon].ammoType, 1)) + { + WeaponLower(pPlayer); + pPlayer->weaponMode[nWeapon] = v6c; + return; + } + } + pPlayer->newWeapon = kWeapNone; + return; + } + if (pPlayer->curWeapon && !CheckAmmo(pPlayer, pPlayer->weaponAmmo, 1) && pPlayer->weaponAmmo != 11) + { + pPlayer->weaponState = -1; + return; + } + if (bShoot) + { + switch (pPlayer->curWeapon) + { + case kWeapPitchFork: + StartQAV(pPlayer, kQAVPFORK, nClientFirePitchfork); + return; + case kWeapSpraycan: + switch (pPlayer->weaponState) + { + case 3: + pPlayer->weaponState = 4; + StartQAV(pPlayer, kQAVCANFIRE, nClientFireSpray, 1); + return; + } + break; + case kWeapDynamite: + switch (pPlayer->weaponState) + { + case 3: + pPlayer->weaponState = 6; + pPlayer->fuseTime = -1; + pPlayer->throwTime = PlayClock; + StartQAV(pPlayer, kQAVBUNFUSE, nClientExplodeBundle); + return; + } + break; + case kWeapProximity: + switch (pPlayer->weaponState) + { + case 7: + SetQAV(pPlayer, kQAVPROXIDLE); + pPlayer->weaponState = 9; + pPlayer->throwTime = PlayClock; + return; + } + break; + case kWeapRemote: + switch (pPlayer->weaponState) + { + case 10: + SetQAV(pPlayer, kQAVREMIDLE1); + pPlayer->weaponState = 13; + pPlayer->throwTime = PlayClock; + return; + case 11: + pPlayer->weaponState = 12; + StartQAV(pPlayer, kQAVREMFIRE, nClientFireRemote); + return; + } + break; + case kWeapShotgun: + switch (pPlayer->weaponState) + { + case 7: + pPlayer->weaponState = 6; + StartQAV(pPlayer, kQAV2SHOTF2, nClientFireShotgun); + return; + case 3: + pPlayer->weaponState = 2; + StartQAV(pPlayer, kQAVSHOTF1, nClientFireShotgun); + return; + case 2: + pPlayer->weaponState = 1; + StartQAV(pPlayer, kQAVSHOTF2, nClientFireShotgun); + return; + } + break; + case kWeapTommyGun: + if (powerupCheck(pPlayer, kPwUpTwoGuns) && checkAmmo2(pPlayer, 3, 2)) + StartQAV(pPlayer, kQAV2TOMFIRE, nClientFireTommy, 1); + else + StartQAV(pPlayer, kQAVTOMFIRE, nClientFireTommy, 1); + return; + case kWeapFlareGun: + if (powerupCheck(pPlayer, kPwUpTwoGuns) && checkAmmo2(pPlayer, 1, 2)) + StartQAV(pPlayer, kQAVFLAR2FIR, nClientFireFlare); + else + StartQAV(pPlayer, kQAVFLARFIR2, nClientFireFlare); + return; + case kWeapVoodooDoll: + { + static int nChance[] = { 0xa000, 0xc000, 0xe000, 0x10000 }; + int nRand = wrand() * 2; + int i; + for (i = 0; nChance[i] < nRand; i++) + { + } + pPlayer->voodooTarget = pPlayer->aimTarget; + if (pPlayer->voodooTarget == nullptr || pPlayer->voodooTarget->spr.statnum != kStatDude) + i = 4; + StartQAV(pPlayer, kQAVVDFIRE1 + i, nClientFireVoodoo); + return; + } + case kWeapTeslaCannon: + switch (pPlayer->weaponState) + { + case 2: + pPlayer->weaponState = 4; + if (checkAmmo2(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns)) + StartQAV(pPlayer, kQAV2SGUNFIR, nClientFireTesla); + else + StartQAV(pPlayer, kQAVSGUNFIR1, nClientFireTesla); + return; + case 5: + if (checkAmmo2(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns)) + StartQAV(pPlayer, kQAV2SGUNFIR, nClientFireTesla); + else + StartQAV(pPlayer, kQAVSGUNFIR1, nClientFireTesla); + return; + } + break; + case kWeapNapalm: + if (powerupCheck(pPlayer, kPwUpTwoGuns)) + StartQAV(pPlayer, kQAV2NAPFIRE, nClientFireNapalm); + else + StartQAV(pPlayer, kQAVNAPFIRE, nClientFireNapalm); + return; + case kWeapLifeLeech: + sfxPlay3DSound(pPlayer->actor, 494, 2, 0); + StartQAV(pPlayer, kQAVSTAFIRE4, nClientFireLifeLeech); + return; + case kWeapBeast: + StartQAV(pPlayer, kQAVBSTATAK1 + Random(4), nClientFireBeast); + return; + } + } + if (bShoot2) + { + switch (pPlayer->curWeapon) + { + case kWeapPitchFork: + StartQAV(pPlayer, kQAVPFORK, nClientFirePitchfork); + return; + case kWeapSpraycan: + switch (pPlayer->weaponState) + { + case 3: + pPlayer->weaponState = 5; + StartQAV(pPlayer, kQAVCANFIRE2, nClientExplodeCan); + return; + } + break; + case kWeapDynamite: + switch (pPlayer->weaponState) + { + case 3: + pPlayer->weaponState = 4; + StartQAV(pPlayer, kQAVBUNFUSE, nClientExplodeBundle); + return; + case 7: + pPlayer->weaponState = 8; + StartQAV(pPlayer, kQAVPROXDROP, nClientDropProx); + return; + case 10: + pPlayer->weaponState = 11; + StartQAV(pPlayer, kQAVREMDROP, nClientDropRemote); + return; + case 11: + if (pPlayer->ammoCount[11] > 0) + { + pPlayer->weaponState = 10; + StartQAV(pPlayer, kQAVREMUP1); + } + return; + } + break; + case kWeapProximity: + switch (pPlayer->weaponState) + { + case 7: + pPlayer->weaponState = 8; + StartQAV(pPlayer, kQAVPROXDROP, nClientDropProx); + return; + } + break; + case kWeapRemote: + switch (pPlayer->weaponState) + { + case 10: + pPlayer->weaponState = 11; + StartQAV(pPlayer, kQAVREMDROP, nClientDropRemote); + return; + case 11: + if (pPlayer->ammoCount[11] > 0) + { + pPlayer->weaponState = 10; + StartQAV(pPlayer, kQAVREMUP1); + } + return; + } + break; + case kWeapShotgun: + switch (pPlayer->weaponState) + { + case 7: + pPlayer->weaponState = 6; + StartQAV(pPlayer, kQAV2SHOTFIR, nClientFireShotgun); + return; + case 3: + pPlayer->weaponState = 1; + StartQAV(pPlayer, kQAVSHOTF3, nClientFireShotgun); + return; + case 2: + pPlayer->weaponState = 1; + StartQAV(pPlayer, kQAVSHOTF2, nClientFireShotgun); + return; + } + break; + case kWeapTommyGun: + if (powerupCheck(pPlayer, kPwUpTwoGuns) && checkAmmo2(pPlayer, 3, 2)) + StartQAV(pPlayer, kQAV2TOMALT, nClientAltFireSpread2); + else + StartQAV(pPlayer, kQAVTOMSPRED, nClientAltFireSpread2); + return; + case kWeapVoodooDoll: + sfxPlay3DSound(pPlayer->actor, 461, 2, 0); + StartQAV(pPlayer, kQAVVDSPEL1, nClientAltFireVoodoo); + return; +#if 0 + case kWeapFlareGun: + if (powerupCheck(pPlayer, kPwUpTwoGuns) && checkAmmo2(pPlayer, 1, 2)) + StartQAV(pPlayer, kQAVFLAR2FIR, nClientFireFlare, 0); + else + StartQAV(pPlayer, kQAVFLARFIR2, nClientFireFlare, 0); + return; +#endif + case kWeapTeslaCannon: + if (checkAmmo2(pPlayer, 7, 35)) + { + if (checkAmmo2(pPlayer, 7, 70) && powerupCheck(pPlayer, kPwUpTwoGuns)) + StartQAV(pPlayer, kQAV2SGUNALT, nClientFireTesla); + else + StartQAV(pPlayer, kQAVSGUNFIR4, nClientFireTesla); + } + else + { + if (checkAmmo2(pPlayer, 7, 10) && powerupCheck(pPlayer, kPwUpTwoGuns)) + StartQAV(pPlayer, kQAV2SGUNFIR, nClientFireTesla); + else + StartQAV(pPlayer, kQAVSGUNFIR1, nClientFireTesla); + } + return; + case kWeapNapalm: + if (powerupCheck(pPlayer, kPwUpTwoGuns)) + // by NoOne: allow napalm launcher alt fire act like in v1.0x versions + if (gGameOptions.weaponsV10x && !VanillaMode()) StartQAV(pPlayer, kQAV2NAPFIR2, nClientFireNapalm2); + else StartQAV(pPlayer, kQAV2NAPFIRE, nClientAltFireNapalm); + else + StartQAV(pPlayer, kQAVNAPFIRE, (gGameOptions.weaponsV10x && !VanillaMode()) ? nClientFireNapalm : nClientAltFireNapalm); + return; + case kWeapFlareGun: + if (CheckAmmo(pPlayer, 1, 8)) + { + if (powerupCheck(pPlayer, kPwUpTwoGuns) && checkAmmo2(pPlayer, 1, 16)) + StartQAV(pPlayer, kQAVFLAR2FIR, nClientAltFireFlare); + else + StartQAV(pPlayer, kQAVFLARFIR2, nClientAltFireFlare); + } + else + { + if (powerupCheck(pPlayer, kPwUpTwoGuns) && checkAmmo2(pPlayer, 1, 2)) + StartQAV(pPlayer, kQAVFLAR2FIR, nClientFireFlare); + else + StartQAV(pPlayer, kQAVFLARFIR2, nClientFireFlare); + } + return; + case kWeapLifeLeech: + if (gGameOptions.nGameType <= 1 && !checkAmmo2(pPlayer, 8, 1) && pPlayer->actor->xspr.health < (25 << 4)) + { + sfxPlay3DSound(pPlayer->actor, 494, 2, 0); + StartQAV(pPlayer, kQAVSTAFIRE4, nClientFireLifeLeech); + } + else + { + StartQAV(pPlayer, kQAVSTAFDOWN); + AltFireLifeLeech(1, pPlayer); + pPlayer->weaponState = -1; + } + return; + } + } + WeaponUpdateState(pPlayer); } -void teslaHit(DBloodActor *missileactor, int a2) +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void teslaHit(DBloodActor* missileactor, int a2) { - int x = missileactor->spr.pos.X; - int y = missileactor->spr.pos.Y; - int z = missileactor->spr.pos.Z; - int nDist = 300; - auto pSector = missileactor->spr.sector(); - auto owneractor = missileactor->GetOwner(); - const bool newSectCheckMethod = !cl_bloodvanillaexplosions && !VanillaMode(); // use new sector checking logic - auto sectorMap = GetClosestSpriteSectors(pSector, x, y, nDist, nullptr, newSectCheckMethod); - bool v4 = true; - DBloodActor* actor = nullptr; - actHitcodeToData(a2, &gHitInfo, &actor); - if (a2 == 3 && actor && actor->spr.statnum == kStatDude) - v4 = false; - BloodStatIterator it(kStatDude); - while (auto hitactor = it.Next()) - { - if (hitactor != owneractor || v4) - { - if (hitactor->spr.flags&32) - continue; - if (CheckSector(sectorMap, hitactor) && CheckProximity(hitactor, x, y, z, pSector, nDist)) - { - int dx = missileactor->spr.pos.X - hitactor->spr.pos.X; - int dy = missileactor->spr.pos.Y - hitactor->spr.pos.Y; - int nDamage = ClipLow((nDist-(ksqrt(dx*dx+dy*dy)>>4)+20)>>1, 10); - if (hitactor == owneractor) - nDamage /= 2; - actDamageSprite(owneractor, hitactor, kDamageTesla, nDamage<<4); - } - } - } - it.Reset(kStatThing); - while (auto hitactor = it.Next()) - { - if (hitactor->spr.flags&32) - continue; - if (CheckSector(sectorMap, hitactor) && CheckProximity(hitactor, x, y, z, pSector, nDist)) - { - if (!hitactor->xspr.locked) - { - int dx = missileactor->spr.pos.X - hitactor->spr.pos.X; - int dy = missileactor->spr.pos.Y - hitactor->spr.pos.Y; - int nDamage = ClipLow(nDist-(ksqrt(dx*dx+dy*dy)>>4)+20, 20); - actDamageSprite(owneractor, hitactor, kDamageTesla, nDamage << 4); - } - } - } + int x = missileactor->spr.pos.X; + int y = missileactor->spr.pos.Y; + int z = missileactor->spr.pos.Z; + int nDist = 300; + auto pSector = missileactor->spr.sector(); + auto owneractor = missileactor->GetOwner(); + const bool newSectCheckMethod = !cl_bloodvanillaexplosions && !VanillaMode(); // use new sector checking logic + auto sectorMap = GetClosestSpriteSectors(pSector, x, y, nDist, nullptr, newSectCheckMethod); + bool v4 = true; + DBloodActor* actor = nullptr; + actHitcodeToData(a2, &gHitInfo, &actor); + if (a2 == 3 && actor && actor->spr.statnum == kStatDude) + v4 = false; + BloodStatIterator it(kStatDude); + while (auto hitactor = it.Next()) + { + if (hitactor != owneractor || v4) + { + if (hitactor->spr.flags & 32) + continue; + if (CheckSector(sectorMap, hitactor) && CheckProximity(hitactor, x, y, z, pSector, nDist)) + { + int dx = missileactor->spr.pos.X - hitactor->spr.pos.X; + int dy = missileactor->spr.pos.Y - hitactor->spr.pos.Y; + int nDamage = ClipLow((nDist - (ksqrt(dx * dx + dy * dy) >> 4) + 20) >> 1, 10); + if (hitactor == owneractor) + nDamage /= 2; + actDamageSprite(owneractor, hitactor, kDamageTesla, nDamage << 4); + } + } + } + it.Reset(kStatThing); + while (auto hitactor = it.Next()) + { + if (hitactor->spr.flags & 32) + continue; + if (CheckSector(sectorMap, hitactor) && CheckProximity(hitactor, x, y, z, pSector, nDist)) + { + if (!hitactor->xspr.locked) + { + int dx = missileactor->spr.pos.X - hitactor->spr.pos.X; + int dy = missileactor->spr.pos.Y - hitactor->spr.pos.Y; + int nDamage = ClipLow(nDist - (ksqrt(dx * dx + dy * dy) >> 4) + 20, 20); + actDamageSprite(owneractor, hitactor, kDamageTesla, nDamage << 4); + } + } + } } END_BLD_NS