From f2b52f620b64c6a9164f7bd3ae84bb7ee9e4659a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 23 Nov 2024 19:49:53 +0100 Subject: [PATCH 01/30] move game-specific CVAR out of low level system code. --- src/common/audio/sound/i_sound.cpp | 3 --- src/playsim/p_user.cpp | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/common/audio/sound/i_sound.cpp b/src/common/audio/sound/i_sound.cpp index 4ca119b0b..dda757e8d 100644 --- a/src/common/audio/sound/i_sound.cpp +++ b/src/common/audio/sound/i_sound.cpp @@ -62,9 +62,6 @@ CUSTOM_CVAR(Int, snd_samplerate, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Int, snd_buffersize, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Int, snd_hrtf, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -CVAR(Float, snd_footstepvolume, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) - - #if !defined(NO_OPENAL) #define DEF_BACKEND "openal" #else diff --git a/src/playsim/p_user.cpp b/src/playsim/p_user.cpp index 4ed0c0bfd..4dfab3d6c 100644 --- a/src/playsim/p_user.cpp +++ b/src/playsim/p_user.cpp @@ -99,6 +99,7 @@ static FRandom pr_skullpop ("SkullPop"); // [SP] Allows respawn in single player CVAR(Bool, sv_singleplayerrespawn, false, CVAR_SERVERINFO | CVAR_CHEAT) +CVAR(Float, snd_footstepvolume, 1.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // Variables for prediction CVAR(Bool, cl_predict_specials, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) From 2dcd0fcda49192720b1587770e634e57807dd14f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 23 Nov 2024 19:54:35 +0100 Subject: [PATCH 02/30] moved another declaration out of a global header. --- src/common/engine/serializer.h | 1 - src/serializer_doom.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/engine/serializer.h b/src/common/engine/serializer.h index 902d4226c..fb906aee8 100644 --- a/src/common/engine/serializer.h +++ b/src/common/engine/serializer.h @@ -253,7 +253,6 @@ FSerializer &Serialize(FSerializer &arc, const char *key, struct AnimModelOverri FSerializer &Serialize(FSerializer &arc, const char *key, ModelAnim &ao, ModelAnim *def); FSerializer &Serialize(FSerializer &arc, const char *key, ModelAnimFrame &ao, ModelAnimFrame *def); FSerializer &Serialize(FSerializer& arc, const char* key, FTranslationID& value, FTranslationID* defval); -FSerializer &Serialize(FSerializer& arc, const char* key, struct FStandaloneAnimation& value, struct FStandaloneAnimation* defval); void SerializeFunctionPointer(FSerializer &arc, const char *key, FunctionPointerValue *&p); diff --git a/src/serializer_doom.h b/src/serializer_doom.h index b399568c2..40b6710a1 100644 --- a/src/serializer_doom.h +++ b/src/serializer_doom.h @@ -42,6 +42,7 @@ FSerializer& Serialize(FSerializer& arc, const char* key, char& value, char* def FSerializer &Serialize(FSerializer &arc, const char *key, ticcmd_t &sid, ticcmd_t *def); FSerializer &Serialize(FSerializer &arc, const char *key, usercmd_t &cmd, usercmd_t *def); FSerializer &Serialize(FSerializer &arc, const char *key, FInterpolator &rs, FInterpolator *def); +FSerializer& Serialize(FSerializer& arc, const char* key, struct FStandaloneAnimation& value, struct FStandaloneAnimation* defval); template<> FSerializer &Serialize(FSerializer &arc, const char *key, FPolyObj *&value, FPolyObj **defval); template<> FSerializer &Serialize(FSerializer &arc, const char *key, sector_t *&value, sector_t **defval); From ca3b0737ea3cc2b11c7e1e2670dd56073cb4a096 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 23 Nov 2024 20:09:50 +0100 Subject: [PATCH 03/30] contain the statnum hack for visual thinkers on the game side. This got used from precisely one place, which can easily handle it itself. --- src/common/objects/dobjtype.cpp | 10 +--------- src/common/objects/dobjtype.h | 2 +- src/g_levellocals.h | 8 +++++++- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/common/objects/dobjtype.cpp b/src/common/objects/dobjtype.cpp index a3172c5e5..0d1bfdf9a 100644 --- a/src/common/objects/dobjtype.cpp +++ b/src/common/objects/dobjtype.cpp @@ -46,8 +46,6 @@ #include "symbols.h" #include "types.h" -#include "p_visualthinker.h" - // MACROS ------------------------------------------------------------------ // TYPES ------------------------------------------------------------------- @@ -423,7 +421,7 @@ PClass *PClass::FindClass (FName zaname) // //========================================================================== -DObject *PClass::CreateNew(int *statnum) +DObject *PClass::CreateNew() { uint8_t *mem = (uint8_t *)M_Malloc (Size); assert (mem != nullptr); @@ -446,12 +444,6 @@ DObject *PClass::CreateNew(int *statnum) ((DObject *)mem)->SetClass (const_cast(this)); InitializeSpecials(mem, Defaults, &PClass::SpecialInits); - - if(statnum && ((DObject *)mem)->IsKindOf(RUNTIME_CLASS(DVisualThinker))) - { - *statnum = STAT_VISUALTHINKER; - } - return (DObject *)mem; } diff --git a/src/common/objects/dobjtype.h b/src/common/objects/dobjtype.h index 17ad29862..62e6f5ccc 100644 --- a/src/common/objects/dobjtype.h +++ b/src/common/objects/dobjtype.h @@ -90,7 +90,7 @@ public: PClass(); ~PClass(); void InsertIntoHash(bool native); - DObject *CreateNew(int *statnum = nullptr); + DObject *CreateNew(); PClass *CreateDerivedClass(FName name, unsigned int size, bool *newlycreated = nullptr, int fileno = 0); void InitializeActorInfo(); diff --git a/src/g_levellocals.h b/src/g_levellocals.h index c02a6bd01..af2d6bb28 100644 --- a/src/g_levellocals.h +++ b/src/g_levellocals.h @@ -56,6 +56,7 @@ #include "r_data/r_interpolate.h" #include "doom_aabbtree.h" #include "doom_levelmesh.h" +#include "p_visualthinker.h" //============================================================================ // @@ -425,7 +426,12 @@ public: DThinker *CreateThinker(PClass *cls, int statnum = STAT_DEFAULT) { - DThinker *thinker = static_cast(cls->CreateNew(&statnum)); + DThinker *thinker = static_cast(cls->CreateNew()); + if (statnum && thinker->IsKindOf(RUNTIME_CLASS(DVisualThinker))) + { + statnum = STAT_VISUALTHINKER; + } + assert(thinker->IsKindOf(RUNTIME_CLASS(DThinker))); thinker->ObjectFlags |= OF_JustSpawned; Thinkers.Link(thinker, statnum); From e0778e23eb3115e623bac212366981680c6c051c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 23 Nov 2024 20:26:06 +0100 Subject: [PATCH 04/30] M_SaveDefaults is also not part of the common engine backend. --- src/common/scripting/interface/vmnatives.cpp | 12 ------------ src/m_misc.cpp | 12 ++++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/common/scripting/interface/vmnatives.cpp b/src/common/scripting/interface/vmnatives.cpp index c778364ed..2b57ceb25 100644 --- a/src/common/scripting/interface/vmnatives.cpp +++ b/src/common/scripting/interface/vmnatives.cpp @@ -41,7 +41,6 @@ #include "c_cvars.h" #include "c_bind.h" #include "c_dispatch.h" -#include "m_misc.h" #include "menu.h" #include "vm.h" @@ -1033,17 +1032,6 @@ DEFINE_ACTION_FUNCTION(_CVar, FindCVar) ACTION_RETURN_POINTER(FindCVar(name.GetChars(), nullptr)); } -static int SaveConfig() -{ - return M_SaveDefaults(nullptr); -} - -DEFINE_ACTION_FUNCTION_NATIVE(_CVar, SaveConfig, SaveConfig) -{ - PARAM_PROLOGUE; - ACTION_RETURN_INT(M_SaveDefaults(nullptr)); -} - //============================================================================= // // diff --git a/src/m_misc.cpp b/src/m_misc.cpp index 1b451486b..f8bafabad 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -66,6 +66,7 @@ #include "gameconfigfile.h" #include "gstrings.h" +#include "vm.h" FGameConfigFile *GameConfig; @@ -691,3 +692,14 @@ CCMD(openscreenshots) I_OpenShellFolder(autoname.GetChars()); } +static int SaveConfig() +{ + return M_SaveDefaults(nullptr); +} + +DEFINE_ACTION_FUNCTION_NATIVE(_CVar, SaveConfig, SaveConfig) +{ + PARAM_PROLOGUE; + ACTION_RETURN_INT(M_SaveDefaults(nullptr)); +} + From 9b623796452e5b4965d8c90991876833a384e431 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 23 Nov 2024 21:10:11 +0100 Subject: [PATCH 05/30] removed -hashfiles after finding out it had been broken for an extended time period. this is a strong indicator that nobody was using it - and I do not feel like fixing such an invasive feature with little utility. --- src/common/filesystem/include/fs_filesystem.h | 4 +- src/common/filesystem/source/filesystem.cpp | 47 ++----------------- src/d_main.cpp | 36 +------------- 3 files changed, 7 insertions(+), 80 deletions(-) diff --git a/src/common/filesystem/include/fs_filesystem.h b/src/common/filesystem/include/fs_filesystem.h index 858b74837..e817bc12d 100644 --- a/src/common/filesystem/include/fs_filesystem.h +++ b/src/common/filesystem/include/fs_filesystem.h @@ -42,8 +42,8 @@ public: void SetMaxIwadNum(int x) { MaxIwadIndex = x; } bool InitSingleFile(const char *filename, FileSystemMessageFunc Printf = nullptr); - bool InitMultipleFiles (std::vector& filenames, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, bool allowduplicates = false, FILE* hashfile = nullptr); - void AddFile (const char *filename, FileReader *wadinfo, LumpFilterInfo* filter, FileSystemMessageFunc Printf, FILE* hashfile); + bool InitMultipleFiles (std::vector& filenames, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, bool allowduplicates = false); + void AddFile (const char *filename, FileReader *wadinfo, LumpFilterInfo* filter, FileSystemMessageFunc Printf); int CheckIfResourceFileLoaded (const char *name) noexcept; void AddAdditionalFile(const char* filename, FileReader* wadinfo = NULL) {} diff --git a/src/common/filesystem/source/filesystem.cpp b/src/common/filesystem/source/filesystem.cpp index fee5f1011..0bc0dd5fe 100644 --- a/src/common/filesystem/source/filesystem.cpp +++ b/src/common/filesystem/source/filesystem.cpp @@ -238,7 +238,7 @@ bool FileSystem::InitSingleFile(const char* filename, FileSystemMessageFunc Prin return InitMultipleFiles(filenames, nullptr, Printf); } -bool FileSystem::InitMultipleFiles (std::vector& filenames, LumpFilterInfo* filter, FileSystemMessageFunc Printf, bool allowduplicates, FILE* hashfile) +bool FileSystem::InitMultipleFiles (std::vector& filenames, LumpFilterInfo* filter, FileSystemMessageFunc Printf, bool allowduplicates) { int numfiles; @@ -269,7 +269,7 @@ bool FileSystem::InitMultipleFiles (std::vector& filenames, LumpFil for(size_t i=0;igetName(i); auto embedded = resfile->GetEntryReader(i, READER_CACHED); - AddFile(path.c_str(), &embedded, filter, Printf, hashfile); + AddFile(path.c_str(), &embedded, filter, Printf); } } - if (hashfile) - { - uint8_t cksum[16]; - char cksumout[33]; - memset(cksumout, 0, sizeof(cksumout)); - - if (filereader.isOpen()) - { - filereader.Seek(0, FileReader::SeekSet); - md5Hash(filereader, cksum); - - for (size_t j = 0; j < sizeof(cksum); ++j) - { - snprintf(cksumout + (j * 2), 3, "%02X", cksum[j]); - } - - fprintf(hashfile, "file: %s, hash: %s, size: %td\n", filename, cksumout, filereader.GetLength()); - } - - else - fprintf(hashfile, "file: %s, Directory structure\n", filename); - - for (int i = 0; i < resfile->EntryCount(); i++) - { - int flags = resfile->GetEntryFlags(i); - if (!(flags & RESFF_EMBEDDED)) - { - auto reader = resfile->GetEntryReader(i, READER_SHARED, 0); - md5Hash(filereader, cksum); - - for (size_t j = 0; j < sizeof(cksum); ++j) - { - snprintf(cksumout + (j * 2), 3, "%02X", cksum[j]); - } - - fprintf(hashfile, "file: %s, lump: %s, hash: %s, size: %zu\n", filename, resfile->getName(i), cksumout, (uint64_t)resfile->Length(i)); - } - } - } return; } } diff --git a/src/d_main.cpp b/src/d_main.cpp index c00f2231c..0971c48d1 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -3028,39 +3028,6 @@ static void System_HudScaleChanged() bool CheckSkipGameOptionBlock(const char* str); -//========================================================================== -// -// -// -//========================================================================== - -static FILE* D_GetHashFile() -{ - FILE *hashfile = nullptr; - - if (Args->CheckParm("-hashfiles")) - { - const char *filename = "fileinfo.txt"; - Printf("Hashing loaded content to: %s\n", filename); - hashfile = fopen(filename, "w"); - if (hashfile) - { - Printf("Notice: File hashing is incredibly verbose. Expect loading files to take much longer than usual.\n"); - fprintf(hashfile, "%s version %s (%s)\n", GAMENAME, GetVersionString(), GetGitHash()); -#ifdef __VERSION__ - fprintf(hashfile, "Compiler version: %s\n", __VERSION__); -#endif - fprintf(hashfile, "Command line:"); - for (int i = 0; i < Args->NumArgs(); ++i) - { - fprintf(hashfile, " %s", Args->GetArg(i)); - } - fprintf(hashfile, "\n"); - } - } - return hashfile; -} - // checks if a file within a directory is allowed to be added to the file system. static bool FileNameCheck(const char* base, const char* path) { @@ -3217,8 +3184,7 @@ static int D_InitGame(const FIWADInfo* iwad_info, std::vector& allw ); bool allowduplicates = Args->CheckParm("-allowduplicates"); - auto hashfile = D_GetHashFile(); - if (!fileSystem.InitMultipleFiles(allwads, &lfi, FileSystemPrintf, allowduplicates, hashfile)) + if (!fileSystem.InitMultipleFiles(allwads, &lfi, FileSystemPrintf, allowduplicates)) { I_FatalError("FileSystem: no files found"); } From 941f9502e944f95ba6bb10895f7b4924807ac8e4 Mon Sep 17 00:00:00 2001 From: Boondorl <59555366+Boondorl@users.noreply.github.com> Date: Sun, 24 Nov 2024 09:44:47 -0500 Subject: [PATCH 06/30] Improved "respawn where died" functionality (#2831) Now uses a "last safe position" system instead. This: -Prevents players from slipping into places they shouldn't via their dead body and then respawning there -No longer sends players back to spawn if they fall into kill pits -Adds a safety feature where the kill command always resets back to spawn should a player ever get stuck somewhere --- src/g_game.cpp | 1 + src/gamedata/r_defs.h | 2 ++ src/playsim/d_player.h | 2 ++ src/playsim/p_mobj.cpp | 15 ++++++--------- src/playsim/p_sectors.cpp | 22 ++++++++++++++++++++++ src/playsim/p_user.cpp | 11 ++++++++++- 6 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/g_game.cpp b/src/g_game.cpp index 42ce6e99a..f43642813 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1438,6 +1438,7 @@ void FLevelLocals::PlayerReborn (int player) p->cheats |= chasecam; p->Bot = Bot; //Added by MC: p->settings_controller = settings_controller; + p->LastSafePos = p->mo->Pos(); p->oldbuttons = ~0, p->attackdown = true; p->usedown = true; // don't do anything immediately p->original_oldbuttons = ~0; diff --git a/src/gamedata/r_defs.h b/src/gamedata/r_defs.h index bf0f6be4b..a6f4c2c4f 100644 --- a/src/gamedata/r_defs.h +++ b/src/gamedata/r_defs.h @@ -805,6 +805,8 @@ public: void RemoveForceField(); int Index() const { return sectornum; } + bool IsDangerous(const DVector3& pos, double height) const; + void AdjustFloorClip () const; void SetColor(PalEntry pe, int desat); void SetFade(PalEntry pe); diff --git a/src/playsim/d_player.h b/src/playsim/d_player.h index a717bb42c..2a2fd3334 100644 --- a/src/playsim/d_player.h +++ b/src/playsim/d_player.h @@ -435,6 +435,8 @@ public: DAngle ConversationNPCAngle = nullAngle; bool ConversationFaceTalker = false; + DVector3 LastSafePos = {}; // Mark the last known safe location the player was standing. + double GetDeltaViewHeight() const { return (mo->FloatVar(NAME_ViewHeight) + crouchviewdelta - viewheight) / 8; diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index d896db678..acc18902a 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -5594,16 +5594,13 @@ AActor *FLevelLocals::SpawnPlayer (FPlayerStart *mthing, int playernum, int flag PlayerSpawnPickClass(playernum); - if (( dmflags2 & DF2_SAME_SPAWN_SPOT ) && - ( p->playerstate == PST_REBORN ) && - ( deathmatch == false ) && - ( gameaction != ga_worlddone ) && - ( p->mo != NULL ) && - ( !(p->mo->Sector->Flags & SECF_NORESPAWN) ) && - ( NULL != p->attacker ) && // don't respawn on damaging floors - ( p->mo->Sector->damageamount < TELEFRAG_DAMAGE )) // this really should be a bit smarter... + if ((dmflags2 & DF2_SAME_SPAWN_SPOT) && !deathmatch + && p->mo != nullptr && p->playerstate == PST_REBORN + && gameaction != ga_worlddone + && !(p->mo->Sector->Flags & SECF_NORESPAWN) + && p->LastDamageType != NAME_Suicide) { - spawn = p->mo->Pos(); + spawn = p->LastSafePos; SpawnAngle = p->mo->Angles.Yaw; } else diff --git a/src/playsim/p_sectors.cpp b/src/playsim/p_sectors.cpp index a9014c2ce..581a5350a 100644 --- a/src/playsim/p_sectors.cpp +++ b/src/playsim/p_sectors.cpp @@ -129,6 +129,28 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Sector, NextSpecialSector, P_NextSpecialSector) ACTION_RETURN_POINTER(P_NextSpecialSector(self, type, nogood)); } +bool sector_t::IsDangerous(const DVector3& pos, double height) const +{ + if (damageamount > 0) + return true; + + auto cl = dyn_cast(ceilingdata.Get()); + if (cl != nullptr && cl->getCrush() > 0) + return true; + + for (auto rover : e->XFloor.ffloors) + { + if ((rover->flags & FF_EXISTS) && rover->model->damageamount > 0 + && pos.Z <= rover->top.plane->ZatPoint(pos) + && pos.Z + height >= rover->bottom.plane->ZatPoint(pos)) + { + return true; + } + } + + return false; +} + // // P_FindLowestFloorSurrounding() // FIND LOWEST FLOOR HEIGHT IN SURROUNDING SECTORS diff --git a/src/playsim/p_user.cpp b/src/playsim/p_user.cpp index 4dfab3d6c..652d533ca 100644 --- a/src/playsim/p_user.cpp +++ b/src/playsim/p_user.cpp @@ -361,6 +361,7 @@ void player_t::CopyFrom(player_t &p, bool copyPSP) MUSINFOactor = p.MUSINFOactor; MUSINFOtics = p.MUSINFOtics; SoundClass = p.SoundClass; + LastSafePos = p.LastSafePos; angleOffsetTargets = p.angleOffsetTargets; if (copyPSP) { @@ -1291,6 +1292,13 @@ void P_PlayerThink (player_t *player) player->SubtitleCounter--; } + if (player->playerstate == PST_LIVE + && player->mo->Z() <= player->mo->floorz + && !player->mo->Sector->IsDangerous(player->mo->Pos(), player->mo->Height)) + { + player->LastSafePos = player->mo->Pos(); + } + // Bots do not think in freeze mode. if (player->mo->Level->isFrozen() && player->Bot != nullptr) { @@ -1779,7 +1787,8 @@ void player_t::Serialize(FSerializer &arc) ("onground", onground) ("musinfoactor", MUSINFOactor) ("musinfotics", MUSINFOtics) - ("soundclass", SoundClass); + ("soundclass", SoundClass) + ("lastsafepos", LastSafePos); if (arc.isWriting ()) { From 27c6d34537eb196524c3861c9f0659bb09df7351 Mon Sep 17 00:00:00 2001 From: BinarryCode <53833277+BinarryCode@users.noreply.github.com> Date: Thu, 3 Oct 2024 09:18:19 -0700 Subject: [PATCH 07/30] Add new SBARINFO top level "AppendStatusBar", allowing for extra SBARINFO code to be added to custom SBARINFO definitions. --- src/g_statusbar/sbarinfo.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/g_statusbar/sbarinfo.cpp b/src/g_statusbar/sbarinfo.cpp index 6bb27d179..cb2ddcd0e 100644 --- a/src/g_statusbar/sbarinfo.cpp +++ b/src/g_statusbar/sbarinfo.cpp @@ -381,6 +381,7 @@ enum //Key words SBARINFO_MUGSHOT, SBARINFO_CREATEPOPUP, SBARINFO_PROTRUSION, + SBARINFO_APPENDSTATUSBAR, }; enum //Bar types @@ -410,6 +411,7 @@ static const char *SBarInfoTopLevel[] = "mugshot", "createpopup", "protrusion", + "appendstatusbar", NULL }; @@ -629,6 +631,7 @@ void SBarInfo::ParseSBarInfo(int lump) sc.MustGetToken(';'); break; case SBARINFO_STATUSBAR: + case SBARINFO_APPENDSTATUSBAR: { if(!baseSet) //If the user didn't explicitly define a base, do so now. gameType = GAME_Any; @@ -638,11 +641,16 @@ void SBarInfo::ParseSBarInfo(int lump) sc.MustGetToken(TK_Identifier); barNum = sc.MustMatchString(StatusBars); } - if (this->huds[barNum] != NULL) + // SBARINFO_APPENDSTATUSBAR shouldn't delete the old HUD if it exists. + const bool append = (sc.MustMatchString(SBarInfoTopLevel) == SBARINFO_APPENDSTATUSBAR); + if (!append) { - delete this->huds[barNum]; + if (this->huds[barNum] != NULL) + { + delete this->huds[barNum]; + } + this->huds[barNum] = new SBarInfoMainBlock(this); } - this->huds[barNum] = new SBarInfoMainBlock(this); if(barNum == STBAR_AUTOMAP) { automapbar = true; From aa5ae5759a9a53a0d4a3f6c8e3d7ee3f26d558db Mon Sep 17 00:00:00 2001 From: BinarryCode <53833277+BinarryCode@users.noreply.github.com> Date: Fri, 4 Oct 2024 16:48:28 -0700 Subject: [PATCH 08/30] Fix Pull Request Review 2346387627 --- src/g_statusbar/sbarinfo.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/g_statusbar/sbarinfo.cpp b/src/g_statusbar/sbarinfo.cpp index cb2ddcd0e..13d77dbe6 100644 --- a/src/g_statusbar/sbarinfo.cpp +++ b/src/g_statusbar/sbarinfo.cpp @@ -490,6 +490,11 @@ void SBarInfo::ParseSBarInfo(int lump) continue; } int baselump = -2; + FString SBarInfoTopLevelString; + if(sc.GetString(SBarInfoTopLevelString)) + { // Store the string if the next token is a string, and revert scanner state afterwards + sc.UnGet(); + } switch(sc.MustMatchString(SBarInfoTopLevel)) { case SBARINFO_BASE: @@ -642,7 +647,7 @@ void SBarInfo::ParseSBarInfo(int lump) barNum = sc.MustMatchString(StatusBars); } // SBARINFO_APPENDSTATUSBAR shouldn't delete the old HUD if it exists. - const bool append = (sc.MustMatchString(SBarInfoTopLevel) == SBARINFO_APPENDSTATUSBAR); + const bool append = (SBarInfoTopLevelString.CompareNoCase("appendstatusbar") == 0); if (!append) { if (this->huds[barNum] != NULL) From aec8691c062ab46c818d10d7e1e7c17fd4810f13 Mon Sep 17 00:00:00 2001 From: BinarryCode <53833277+BinarryCode@users.noreply.github.com> Date: Mon, 18 Nov 2024 09:30:57 -0800 Subject: [PATCH 09/30] Update sbarinfo.cpp Update code to be consistent with patch for Zandronum --- src/g_statusbar/sbarinfo.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/g_statusbar/sbarinfo.cpp b/src/g_statusbar/sbarinfo.cpp index 13d77dbe6..e626efbd8 100644 --- a/src/g_statusbar/sbarinfo.cpp +++ b/src/g_statusbar/sbarinfo.cpp @@ -490,12 +490,9 @@ void SBarInfo::ParseSBarInfo(int lump) continue; } int baselump = -2; - FString SBarInfoTopLevelString; - if(sc.GetString(SBarInfoTopLevelString)) - { // Store the string if the next token is a string, and revert scanner state afterwards - sc.UnGet(); - } - switch(sc.MustMatchString(SBarInfoTopLevel)) + // Store the command, used for the switch statement and case SBARINFO_APPENDSTATUSBAR. + const int command = sc.MustMatchString(SBarInfoTopLevel); + switch(command) { case SBARINFO_BASE: baseSet = true; @@ -647,8 +644,7 @@ void SBarInfo::ParseSBarInfo(int lump) barNum = sc.MustMatchString(StatusBars); } // SBARINFO_APPENDSTATUSBAR shouldn't delete the old HUD if it exists. - const bool append = (SBarInfoTopLevelString.CompareNoCase("appendstatusbar") == 0); - if (!append) + if (command != SBARINFO_APPENDSTATUSBAR) { if (this->huds[barNum] != NULL) { @@ -656,6 +652,10 @@ void SBarInfo::ParseSBarInfo(int lump) } this->huds[barNum] = new SBarInfoMainBlock(this); } + else if (this->huds[barNum] == NULL) + { + sc.ScriptError( "AppendStatusBar can't be used on a HUD that doesn't exist yet." ); + } if(barNum == STBAR_AUTOMAP) { automapbar = true; From bea4659c081c07a90126bbefd47434b0edf3f5ec Mon Sep 17 00:00:00 2001 From: BinarryCode <53833277+BinarryCode@users.noreply.github.com> Date: Sat, 23 Nov 2024 08:25:05 -0800 Subject: [PATCH 10/30] tweak error message --- src/g_statusbar/sbarinfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_statusbar/sbarinfo.cpp b/src/g_statusbar/sbarinfo.cpp index e626efbd8..f84440ac9 100644 --- a/src/g_statusbar/sbarinfo.cpp +++ b/src/g_statusbar/sbarinfo.cpp @@ -654,7 +654,7 @@ void SBarInfo::ParseSBarInfo(int lump) } else if (this->huds[barNum] == NULL) { - sc.ScriptError( "AppendStatusBar can't be used on a HUD that doesn't exist yet." ); + sc.ScriptError("Status bar '%s' has not been created and cannot be appended to. Use 'StatusBar' instead.", StatusBars[barNum]); } if(barNum == STBAR_AUTOMAP) { From ed4ef14d3196dced952d047117e4374c9cd249e2 Mon Sep 17 00:00:00 2001 From: BinarryCode <53833277+BinarryCode@users.noreply.github.com> Date: Sun, 24 Nov 2024 13:10:21 -0800 Subject: [PATCH 11/30] make if-checks for AppendStatusBar consistent with Zandronum implementation --- src/g_statusbar/sbarinfo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/g_statusbar/sbarinfo.cpp b/src/g_statusbar/sbarinfo.cpp index f84440ac9..82aba4263 100644 --- a/src/g_statusbar/sbarinfo.cpp +++ b/src/g_statusbar/sbarinfo.cpp @@ -644,7 +644,7 @@ void SBarInfo::ParseSBarInfo(int lump) barNum = sc.MustMatchString(StatusBars); } // SBARINFO_APPENDSTATUSBAR shouldn't delete the old HUD if it exists. - if (command != SBARINFO_APPENDSTATUSBAR) + if(command != SBARINFO_APPENDSTATUSBAR) { if (this->huds[barNum] != NULL) { @@ -652,7 +652,7 @@ void SBarInfo::ParseSBarInfo(int lump) } this->huds[barNum] = new SBarInfoMainBlock(this); } - else if (this->huds[barNum] == NULL) + else if(this->huds[barNum] == NULL) { sc.ScriptError("Status bar '%s' has not been created and cannot be appended to. Use 'StatusBar' instead.", StatusBars[barNum]); } From 488d4f0c71f63be16823fa014dbd0ddada216928 Mon Sep 17 00:00:00 2001 From: Boondorl <59555366+Boondorl@users.noreply.github.com> Date: Tue, 26 Nov 2024 03:43:09 -0500 Subject: [PATCH 12/30] Fixed bouncing on 3D floors (#2835) --- src/playsim/actor.h | 2 +- src/playsim/p_map.cpp | 11 ++++++++--- src/playsim/p_mobj.cpp | 28 ++++++++++++++++++--------- src/scripting/vmthunks_actors.cpp | 3 ++- wadsrc/static/zscript/actors/actor.zs | 2 +- 5 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 326a6f186..f516b79f1 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -873,7 +873,7 @@ public: void PlayPushSound(); // Called when an actor with MF_MISSILE and MF2_FLOORBOUNCE hits the floor - bool FloorBounceMissile (secplane_t &plane); + bool FloorBounceMissile (secplane_t &plane, bool is3DFloor); // Called by RoughBlockCheck bool IsOkayToAttack (AActor *target); diff --git a/src/playsim/p_map.cpp b/src/playsim/p_map.cpp index f8b23a811..84accbe76 100644 --- a/src/playsim/p_map.cpp +++ b/src/playsim/p_map.cpp @@ -2486,7 +2486,9 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, // If it's a bouncer, let it bounce off its new floor, too. if (thing->BounceFlags & BOUNCE_Floors) { - thing->FloorBounceMissile(tm.floorsector->floorplane); + F3DFloor* ff = nullptr; + NextLowestFloorAt(tm.sector, tm.pos.X, tm.pos.Y, tm.pos.Z, 0, thing->MaxStepHeight, nullptr, &ff); + thing->FloorBounceMissile(ff != nullptr ? *ff->top.plane : tm.floorsector->floorplane, ff != nullptr); } else { @@ -3603,14 +3605,17 @@ bool FSlide::BounceWall(AActor *mo) { // Could not find a wall, so bounce off the floor/ceiling instead. double floordist = mo->Z() - mo->floorz; double ceildist = mo->ceilingz - mo->Z(); + F3DFloor* ff = nullptr; if (floordist <= ceildist) { - mo->FloorBounceMissile(mo->Sector->floorplane); + NextLowestFloorAt(mo->Sector, mo->X(), mo->Y(), mo->Z(), 0, mo->MaxStepHeight, nullptr, &ff); + mo->FloorBounceMissile(ff != nullptr ? *ff->top.plane : mo->floorsector->floorplane, ff != nullptr); return true; } else { - mo->FloorBounceMissile(mo->Sector->ceilingplane); + NextHighestCeilingAt(mo->Sector, mo->X(), mo->Y(), mo->Z(), mo->Top(), 0, nullptr, &ff); + mo->FloorBounceMissile(ff != nullptr ? *ff->bottom.plane : mo->ceilingsector->ceilingplane, ff != nullptr); return true; } } diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index acc18902a..e25545f80 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -1732,7 +1732,7 @@ void AActor::PlayBounceSound(bool onfloor) // Returns true if the missile was destroyed //---------------------------------------------------------------------------- -bool AActor::FloorBounceMissile (secplane_t &plane) +bool AActor::FloorBounceMissile (secplane_t &plane, bool is3DFloor) { if (flags & MF_MISSILE) { @@ -1808,11 +1808,15 @@ bool AActor::FloorBounceMissile (secplane_t &plane) return true; } - double dot = (Vel | plane.Normal()) * 2; + DVector3 norm = plane.Normal(); + if (is3DFloor) + norm = -norm; + + double dot = (Vel | norm) * 2; if (BounceFlags & (BOUNCE_HereticType | BOUNCE_MBF)) { - Vel -= plane.Normal() * dot; + Vel -= norm * dot; AngleFromVel(); if (!(BounceFlags & BOUNCE_MBF)) // Heretic projectiles die, MBF projectiles don't. { @@ -1826,7 +1830,7 @@ bool AActor::FloorBounceMissile (secplane_t &plane) else // Don't run through this for MBF-style bounces { // The reflected velocity keeps only about 70% of its original speed - Vel = (Vel - plane.Normal() * dot) * bouncefactor; + Vel = (Vel - norm * dot) * bouncefactor; AngleFromVel(); } @@ -1850,10 +1854,10 @@ bool AActor::FloorBounceMissile (secplane_t &plane) } else if (BounceFlags & (BOUNCE_AutoOff|BOUNCE_AutoOffFloorOnly)) { - if (plane.fC() > 0 || (BounceFlags & BOUNCE_AutoOff)) + if (norm.Z > 0 || (BounceFlags & BOUNCE_AutoOff)) { // AutoOff only works when bouncing off a floor, not a ceiling (or in compatibility mode.) - if (!(flags & MF_NOGRAVITY) && (Vel.Z < 3)) + if (!(flags & MF_NOGRAVITY) && ((Vel | norm) < 3)) BounceFlags &= ~BOUNCE_TypeMask; } } @@ -2646,7 +2650,9 @@ static void P_ZMovement (AActor *mo, double oldfloorz) mo->SetZ(mo->floorz); if (mo->BounceFlags & BOUNCE_Floors) { - mo->FloorBounceMissile (mo->floorsector->floorplane); + F3DFloor* ff = nullptr; + NextLowestFloorAt(mo->Sector, mo->X(), mo->Y(), mo->Z(), 0, mo->MaxStepHeight, nullptr, &ff); + mo->FloorBounceMissile (ff != nullptr ? *ff->top.plane : mo->floorsector->floorplane, ff != nullptr); /* if (!CanJump(mo)) */ return; } else if (mo->flags3 & MF3_NOEXPLODEFLOOR) @@ -2682,7 +2688,9 @@ static void P_ZMovement (AActor *mo, double oldfloorz) } else if (mo->BounceFlags & BOUNCE_MBF && mo->Vel.Z) // check for MBF-like bounce on non-missiles { - mo->FloorBounceMissile(mo->floorsector->floorplane); + F3DFloor* ff = nullptr; + NextLowestFloorAt(mo->Sector, mo->X(), mo->Y(), mo->Z(), 0, mo->MaxStepHeight, nullptr, &ff); + mo->FloorBounceMissile(ff != nullptr ? *ff->top.plane : mo->floorsector->floorplane, ff != nullptr); } if (mo->flags3 & MF3_ISMONSTER) // Blasted mobj falling { @@ -2753,7 +2761,9 @@ static void P_ZMovement (AActor *mo, double oldfloorz) mo->SetZ(mo->ceilingz - mo->Height); if (mo->BounceFlags & BOUNCE_Ceilings) { // ceiling bounce - mo->FloorBounceMissile (mo->ceilingsector->ceilingplane); + F3DFloor* ff = nullptr; + NextHighestCeilingAt(mo->Sector, mo->X(), mo->Y(), mo->Z(), mo->Top(), 0, nullptr, &ff); + mo->FloorBounceMissile(ff != nullptr ? *ff->bottom.plane : mo->ceilingsector->ceilingplane, ff != nullptr); /* if (!CanJump(mo)) */ return; } if (mo->flags & MF_SKULLFLY) diff --git a/src/scripting/vmthunks_actors.cpp b/src/scripting/vmthunks_actors.cpp index 18cd8aa32..2cf04fd80 100644 --- a/src/scripting/vmthunks_actors.cpp +++ b/src/scripting/vmthunks_actors.cpp @@ -1851,8 +1851,9 @@ DEFINE_ACTION_FUNCTION(AActor, BouncePlane) { PARAM_SELF_PROLOGUE(AActor); PARAM_POINTER(plane, secplane_t); + PARAM_BOOL(is3DFloor); - ACTION_RETURN_BOOL(self->FloorBounceMissile(*plane)); + ACTION_RETURN_BOOL(self->FloorBounceMissile(*plane, is3DFloor)); } DEFINE_ACTION_FUNCTION(AActor, PlayBounceSound) diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index 37b36e9e7..e0633d599 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -866,7 +866,7 @@ class Actor : Thinker native native void PlayPushSound(); native bool BounceActor(Actor blocking, bool onTop); native bool BounceWall(Line l = null); - native bool BouncePlane(readonly plane); + native bool BouncePlane(readonly plane, bool is3DFloor = false); native void PlayBounceSound(bool onFloor); native bool ReflectOffActor(Actor blocking); From 79a419174233545483c76e9d2dd95858523e8744 Mon Sep 17 00:00:00 2001 From: Boondorl Date: Tue, 26 Nov 2024 03:18:40 -0500 Subject: [PATCH 13/30] Bandaid fix for 3D floor collision detection in traces Correctly evaluate if a 3D floor starts above the ceiling/below the ground when testing against them, that way they won't be ignored on line hit. This fixes a lot of edge cases with ramps in particular. --- src/playsim/p_trace.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/playsim/p_trace.cpp b/src/playsim/p_trace.cpp index ed37d5e34..ca4f430a9 100644 --- a/src/playsim/p_trace.cpp +++ b/src/playsim/p_trace.cpp @@ -496,6 +496,10 @@ bool FTraceInfo::LineCheck(intercept_t *in, double dist, DVector3 hit, bool spec entersector = &DummySector[sectorsel]; sectorsel ^= 1; + // We need to make sure that 3D floors clipping underneath the ground/above the ceiling don't + // accidentally get ignored. + bool setFloor = false, setCeiling = false; + for (auto rover : entersector->e->XFloor.ffloors) { int entershootthrough = !!(rover->flags&FF_SHOOTTHROUGH); @@ -508,8 +512,8 @@ bool FTraceInfo::LineCheck(intercept_t *in, double dist, DVector3 hit, bool spec // clip to the part of the sector we are in if (hit.Z > ff_top) { - // 3D floor height is the same as the floor height. We need to test a second spot to see if it is above or below - if (fabs(bf - ff_top) < EQUAL_EPSILON) + // 3D floor height is the same as the floor height or underground. We need to test a second spot to see if it is above or below + if ((ff_top < bf && !setFloor) || fabs(bf - ff_top) < EQUAL_EPSILON) { double cf = entersector->floorplane.ZatPoint(entersector->centerspot); double ffc = rover->top.plane->ZatPoint(entersector->centerspot); @@ -522,6 +526,7 @@ bool FTraceInfo::LineCheck(intercept_t *in, double dist, DVector3 hit, bool spec // above if (bf < ff_top) { + setFloor = true; entersector->floorplane = *rover->top.plane; entersector->SetTexture(sector_t::floor, *rover->top.texture, false); entersector->ClearPortal(sector_t::floor); @@ -530,8 +535,8 @@ bool FTraceInfo::LineCheck(intercept_t *in, double dist, DVector3 hit, bool spec } else if (hit.Z < ff_bottom) { - // 3D floor height is the same as the ceiling height. We need to test a second spot to see if it is above or below - if (fabs(bc - ff_bottom) < EQUAL_EPSILON) + // 3D floor height is the same as the ceiling height or above it. We need to test a second spot to see if it is above or below + if ((ff_bottom > bc && !setCeiling) || fabs(bc - ff_bottom) < EQUAL_EPSILON) { double cc = entersector->ceilingplane.ZatPoint(entersector->centerspot); double fcc = rover->bottom.plane->ZatPoint(entersector->centerspot); @@ -544,6 +549,7 @@ bool FTraceInfo::LineCheck(intercept_t *in, double dist, DVector3 hit, bool spec //below if (bc > ff_bottom) { + setCeiling = true; entersector->ceilingplane = *rover->bottom.plane; entersector->SetTexture(sector_t::ceiling, *rover->bottom.texture, false); entersector->ClearPortal(sector_t::ceiling); From b56190d2c4f84c4ed6b127527ea39e3e648f68b6 Mon Sep 17 00:00:00 2001 From: Boondorl <59555366+Boondorl@users.noreply.github.com> Date: Tue, 26 Nov 2024 05:59:20 -0500 Subject: [PATCH 14/30] Fixed incorrect autooff behavior on ceiling bounce (#2837) * Fixed incorrect autooff behavior on ceiling bounce * Fixed incorrect Actor bouncing behavior --- src/playsim/p_map.cpp | 10 +++++++--- src/playsim/p_mobj.cpp | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/playsim/p_map.cpp b/src/playsim/p_map.cpp index 84accbe76..ba9984051 100644 --- a/src/playsim/p_map.cpp +++ b/src/playsim/p_map.cpp @@ -3792,7 +3792,8 @@ bool P_BounceActor(AActor *mo, AActor *BlockingMobj, bool ontop) else // Don't run through this for MBF-style bounces { // The reflected velocity keeps only about 70% of its original speed - mo->Vel.Z = (mo->Vel.Z - 2. * dot) * mo->bouncefactor; + mo->Vel.Z -= 2. * dot; + mo->Vel *= mo->bouncefactor; } mo->PlayBounceSound(true); @@ -3803,8 +3804,11 @@ bool P_BounceActor(AActor *mo, AActor *BlockingMobj, bool ontop) } else if (mo->BounceFlags & (BOUNCE_AutoOff | BOUNCE_AutoOffFloorOnly)) { - if (!(mo->flags & MF_NOGRAVITY) && (mo->Vel.Z < 3.)) - mo->BounceFlags &= ~BOUNCE_TypeMask; + if (mo->Vel.Z >= 0 || (mo->BounceFlags & BOUNCE_AutoOff)) + { + if (!(mo->flags & MF_NOGRAVITY) && (mo->Vel.Z < 3.)) + mo->BounceFlags &= ~BOUNCE_TypeMask; + } } } if (mo->BounceFlags & BOUNCE_UseBounceState) diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index e25545f80..ad95f8ac6 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -1857,7 +1857,7 @@ bool AActor::FloorBounceMissile (secplane_t &plane, bool is3DFloor) if (norm.Z > 0 || (BounceFlags & BOUNCE_AutoOff)) { // AutoOff only works when bouncing off a floor, not a ceiling (or in compatibility mode.) - if (!(flags & MF_NOGRAVITY) && ((Vel | norm) < 3)) + if (!(flags & MF_NOGRAVITY) && (norm.Z < 0 || ((Vel | norm) < 3))) BounceFlags &= ~BOUNCE_TypeMask; } } From fe2a95c6ff7726350b19ffee7234dea1547a9cf0 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 21 Nov 2024 01:56:44 +0600 Subject: [PATCH 15/30] Add WorldRailgunPreFired for railgun attacks Add AttackLineFlags for WorldHitscanPreFired Indentation fixes in event.zs --- src/events.cpp | 57 +++++++++++++++++++++++++++++++-- src/events.h | 6 ++++ src/playsim/p_map.cpp | 2 +- wadsrc/static/zscript/events.zs | 21 ++++++------ 4 files changed, 74 insertions(+), 12 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 2f7b12091..88f0a2f82 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -719,6 +719,27 @@ bool EventManager::WorldHitscanPreFired(AActor* actor, DAngle angle, double dist return ret; } +bool EventManager::WorldRailgunPreFired(FName damageType, PClassActor* pufftype, FRailParams* param) +{ + auto actor = param->source; + + // don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever. + if (actor->ObjectFlags & OF_EuthanizeMe) + return false; + + bool ret = false; + + if (ShouldCallStatic(true)) ret = staticEventManager.WorldRailgunPreFired(damageType, pufftype, param); + + if (!ret) + { + for (DStaticEventHandler* handler = FirstEventHandler; handler && ret == false; handler = handler->next) + ret = handler->WorldRailgunPreFired(damageType, pufftype, param); + } + + return ret; +} + void EventManager::WorldHitscanFired(AActor* actor, const DVector3& AttackPos, const DVector3& DamagePosition, AActor* Inflictor, int flags) { // don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever. @@ -1064,6 +1085,8 @@ DEFINE_FIELD_X(WorldEvent, FWorldEvent, AttackOffsetForward); DEFINE_FIELD_X(WorldEvent, FWorldEvent, AttackOffsetSide); DEFINE_FIELD_X(WorldEvent, FWorldEvent, AttackZ); DEFINE_FIELD_X(WorldEvent, FWorldEvent, AttackPuffType); +DEFINE_FIELD_X(WorldEvent, FWorldEvent, RailParams); +DEFINE_FIELD_X(WorldEvent, FWorldEvent, AttackLineFlags); DEFINE_FIELD_X(PlayerEvent, FPlayerEvent, PlayerNumber); DEFINE_FIELD_X(PlayerEvent, FPlayerEvent, IsReturn); @@ -1784,7 +1807,37 @@ bool DStaticEventHandler::WorldHitscanPreFired(AActor* actor, DAngle angle, doub e.AttackOffsetForward = offsetforward; e.AttackOffsetSide = offsetside; e.AttackZ = sz; - e.DamageFlags = flags; + e.AttackLineFlags = flags; + int processed; + VMReturn results[1] = { &processed }; + VMValue params[2] = { (DStaticEventHandler*)this, &e }; + VMCall(func, params, 2, results, 1); + return !!processed; + } + + return false; +} + +bool DStaticEventHandler::WorldRailgunPreFired(FName damageType, PClassActor* pufftype, FRailParams* param) +{ + IFVIRTUAL(DStaticEventHandler, WorldRailgunPreFired) + { + // don't create excessive DObjects if not going to be processed anyway + if (isEmpty(func)) return false; + FWorldEvent e = owner->SetupWorldEvent(); + e.Thing = param->source; + e.AttackPuffType = pufftype; + e.DamageType = damageType; + e.Damage = param->damage; + e.AttackOffsetForward = 0; + e.AttackOffsetSide = param->offset_xy; + e.AttackDistance = param->distance; + e.AttackZ = param->offset_z; + e.AttackAngle = e.Thing->Angles.Yaw + param->angleoffset; + e.AttackPitch = e.Thing->Angles.Pitch + param->pitchoffset; + e.RailParams = *param; + e.RailParams.puff = pufftype; + int processed; VMReturn results[1] = { &processed }; VMValue params[2] = { (DStaticEventHandler*)this, &e }; @@ -1806,7 +1859,7 @@ void DStaticEventHandler::WorldHitscanFired(AActor* actor, const DVector3& Attac e.AttackPos = AttackPos; e.DamagePosition = DamagePosition; e.Inflictor = Inflictor; - e.DamageFlags = flags; + e.AttackLineFlags = flags; VMValue params[2] = { (DStaticEventHandler*)this, &e }; VMCall(func, params, 2, nullptr, 0); } diff --git a/src/events.h b/src/events.h index c3d05d485..8a30bdfed 100644 --- a/src/events.h +++ b/src/events.h @@ -4,6 +4,7 @@ #include "dobject.h" #include "serializer.h" #include "d_event.h" +#include "p_local.h" #include "sbar.h" #include "info.h" #include "vm.h" @@ -312,6 +313,7 @@ public: void WorldThingDamaged(AActor* actor, AActor* inflictor, AActor* source, int damage, FName mod, int flags, DAngle angle); void WorldThingDestroyed(AActor* actor); bool WorldHitscanPreFired(AActor* actor, DAngle angle, double distance, DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags, double sz, double offsetforward, double offsetside); + bool WorldRailgunPreFired(FName damageType, PClassActor* pufftype, FRailParams* param); void WorldHitscanFired(AActor* actor, const DVector3& AttackPos, const DVector3& DamagePosition, AActor* Inflictor, int flags); void WorldLinePreActivated(line_t* line, AActor* actor, int activationType, bool* shouldactivate); void WorldLineActivated(line_t* line, AActor* actor, int activationType); @@ -403,6 +405,8 @@ struct FWorldEvent double AttackOffsetSide = 0; double AttackZ = 0; PClassActor* AttackPuffType = nullptr; + FRailParams RailParams; + int AttackLineFlags = 0; }; struct FPlayerEvent @@ -481,6 +485,8 @@ struct EventManager bool WorldHitscanPreFired(AActor* actor, DAngle angle, double distance, DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags, double sz, double offsetforward, double offsetside); // called when a hitscan attack has been fired void WorldHitscanFired(AActor* actor, const DVector3& AttackPos, const DVector3& DamagePosition, AActor* Inflictor, int flags); + // called when a railgun attack has been fired (can be overridden to block it) + bool WorldRailgunPreFired(FName damageType, PClassActor* pufftype, FRailParams* param); // called inside AActor::Grind just before the corpse is destroyed void WorldThingGround(AActor* actor, FState* st); // called after AActor::Revive. diff --git a/src/playsim/p_map.cpp b/src/playsim/p_map.cpp index ba9984051..177c27876 100644 --- a/src/playsim/p_map.cpp +++ b/src/playsim/p_map.cpp @@ -5478,7 +5478,7 @@ void P_RailAttack(FRailParams *p) // disabled because not complete yet. flags = (puffDefaults->flags6 & MF6_NOTRIGGER) ? TRACE_ReportPortals : TRACE_PCross | TRACE_Impact | TRACE_ReportPortals; - if (source->Level->localEventManager->WorldHitscanPreFired(source, source->Angles.Yaw + p->angleoffset, p->distance, source->Angles.Pitch + p->pitchoffset, p->damage, damagetype, puffclass, flags, p->offset_z, 0, p->offset_xy)) + if (source->Level->localEventManager->WorldRailgunPreFired(damagetype, puffclass, p)) { return; } diff --git a/wadsrc/static/zscript/events.zs b/wadsrc/static/zscript/events.zs index 72cf23a51..cc83ad28a 100644 --- a/wadsrc/static/zscript/events.zs +++ b/wadsrc/static/zscript/events.zs @@ -97,14 +97,16 @@ struct WorldEvent native play version("2.4") native readonly bool DamageIsRadius; native int NewDamage; native readonly State CrushedState; - native readonly double AttackAngle; - native readonly double AttackPitch; - native readonly double AttackDistance; - native readonly vector3 AttackPos; - native readonly double AttackOffsetForward; - native readonly double AttackOffsetSide; - native readonly double AttackZ; - native readonly class AttackPuffType; + native readonly int AttackLineFlags; + native readonly double AttackAngle; + native readonly double AttackPitch; + native readonly double AttackDistance; + native readonly vector3 AttackPos; + native readonly double AttackOffsetForward; + native readonly double AttackOffsetSide; + native readonly double AttackZ; + native readonly class AttackPuffType; + native readonly FRailParams RailParams; } struct PlayerEvent native play version("2.4") @@ -163,7 +165,8 @@ class StaticEventHandler : Object native play version("2.4") virtual void WorldThingRevived(WorldEvent e) {} virtual void WorldThingDamaged(WorldEvent e) {} virtual void WorldThingDestroyed(WorldEvent e) {} - virtual bool WorldHitscanPreFired(WorldEvent e) { return false; } + virtual bool WorldHitscanPreFired(WorldEvent e) { return false; } + virtual bool WorldRailgunPreFired(WorldEvent e) { return false; } virtual void WorldHitscanFired(WorldEvent e) {} virtual void WorldLinePreActivated(WorldEvent e) {} virtual void WorldLineActivated(WorldEvent e) {} From 2ad191b37427e955aa004abd5579882413a60f2b Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 21 Nov 2024 13:10:17 +0600 Subject: [PATCH 16/30] Add WorldRailgunFired --- src/events.cpp | 29 +++++++++++++++++++++++++++++ src/events.h | 3 +++ src/playsim/p_map.cpp | 2 +- wadsrc/static/zscript/events.zs | 1 + 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/events.cpp b/src/events.cpp index 88f0a2f82..e4d7d1d1a 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -752,6 +752,18 @@ void EventManager::WorldHitscanFired(AActor* actor, const DVector3& AttackPos, c handler->WorldHitscanFired(actor, AttackPos, DamagePosition, Inflictor, flags); } +void EventManager::WorldRailgunFired(AActor* actor, const DVector3& AttackPos, const DVector3& DamagePosition, AActor* Inflictor, int flags) +{ + // don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever. + if (actor->ObjectFlags & OF_EuthanizeMe) + return; + + if (ShouldCallStatic(true)) staticEventManager.WorldRailgunFired(actor, AttackPos, DamagePosition, Inflictor, flags); + + for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next) + handler->WorldRailgunFired(actor, AttackPos, DamagePosition, Inflictor, flags); +} + void EventManager::WorldThingGround(AActor* actor, FState* st) { // don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever. @@ -1865,6 +1877,23 @@ void DStaticEventHandler::WorldHitscanFired(AActor* actor, const DVector3& Attac } } +void DStaticEventHandler::WorldRailgunFired(AActor* actor, const DVector3& AttackPos, const DVector3& DamagePosition, AActor* Inflictor, int flags) +{ + IFVIRTUAL(DStaticEventHandler, WorldRailgunFired) + { + // don't create excessive DObjects if not going to be processed anyway + if (isEmpty(func)) return; + FWorldEvent e = owner->SetupWorldEvent(); + e.Thing = actor; + e.AttackPos = AttackPos; + e.DamagePosition = DamagePosition; + e.Inflictor = Inflictor; + e.AttackLineFlags = flags; + VMValue params[2] = { (DStaticEventHandler*)this, &e }; + VMCall(func, params, 2, nullptr, 0); + } +} + void DStaticEventHandler::WorldThingGround(AActor* actor, FState* st) { IFVIRTUAL(DStaticEventHandler, WorldThingGround) diff --git a/src/events.h b/src/events.h index 8a30bdfed..4a73406f8 100644 --- a/src/events.h +++ b/src/events.h @@ -315,6 +315,7 @@ public: bool WorldHitscanPreFired(AActor* actor, DAngle angle, double distance, DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags, double sz, double offsetforward, double offsetside); bool WorldRailgunPreFired(FName damageType, PClassActor* pufftype, FRailParams* param); void WorldHitscanFired(AActor* actor, const DVector3& AttackPos, const DVector3& DamagePosition, AActor* Inflictor, int flags); + void WorldRailgunFired(AActor* actor, const DVector3& AttackPos, const DVector3& DamagePosition, AActor* Inflictor, int flags); void WorldLinePreActivated(line_t* line, AActor* actor, int activationType, bool* shouldactivate); void WorldLineActivated(line_t* line, AActor* actor, int activationType); int WorldSectorDamaged(sector_t* sector, AActor* source, int damage, FName damagetype, int part, DVector3 position, bool isradius); @@ -485,6 +486,8 @@ struct EventManager bool WorldHitscanPreFired(AActor* actor, DAngle angle, double distance, DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags, double sz, double offsetforward, double offsetside); // called when a hitscan attack has been fired void WorldHitscanFired(AActor* actor, const DVector3& AttackPos, const DVector3& DamagePosition, AActor* Inflictor, int flags); + // called when a railgun attack has been fired + void WorldRailgunFired(AActor* actor, const DVector3& AttackPos, const DVector3& DamagePosition, AActor* Inflictor, int flags); // called when a railgun attack has been fired (can be overridden to block it) bool WorldRailgunPreFired(FName damageType, PClassActor* pufftype, FRailParams* param); // called inside AActor::Grind just before the corpse is destroyed diff --git a/src/playsim/p_map.cpp b/src/playsim/p_map.cpp index 177c27876..0c881928f 100644 --- a/src/playsim/p_map.cpp +++ b/src/playsim/p_map.cpp @@ -5639,7 +5639,7 @@ void P_RailAttack(FRailParams *p) } } - source->Level->localEventManager->WorldHitscanFired(source, start, trace.HitPos, thepuff, flags); + source->Level->localEventManager->WorldRailgunFired(source, start, trace.HitPos, thepuff, flags); if (thepuff != NULL) { diff --git a/wadsrc/static/zscript/events.zs b/wadsrc/static/zscript/events.zs index cc83ad28a..b1aaf30c8 100644 --- a/wadsrc/static/zscript/events.zs +++ b/wadsrc/static/zscript/events.zs @@ -167,6 +167,7 @@ class StaticEventHandler : Object native play version("2.4") virtual void WorldThingDestroyed(WorldEvent e) {} virtual bool WorldHitscanPreFired(WorldEvent e) { return false; } virtual bool WorldRailgunPreFired(WorldEvent e) { return false; } + virtual void WorldRailgunFired(WorldEvent e) {} virtual void WorldHitscanFired(WorldEvent e) {} virtual void WorldLinePreActivated(WorldEvent e) {} virtual void WorldLineActivated(WorldEvent e) {} From abf0206706a7ed5ad47a8428c9689427704a34e1 Mon Sep 17 00:00:00 2001 From: Boondorl Date: Thu, 14 Nov 2024 22:27:08 -0500 Subject: [PATCH 17/30] Fixes for serializing and initializing Fixed missing DViewPosition serializing. Fixed missing initializers in player_t. --- src/playsim/actor.h | 8 ++------ src/playsim/d_player.h | 14 +++++++------- src/playsim/p_mobj.cpp | 7 +++++++ src/playsim/p_user.cpp | 1 + 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/playsim/actor.h b/src/playsim/actor.h index f516b79f1..586ec377c 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -756,12 +756,6 @@ public: int Flags; // Functions - DViewPosition() - { - Offset = { 0,0,0 }; - Flags = 0; - } - void Set(DVector3 &off, int f = -1) { ZeroSubnormalsF(off.X); @@ -777,6 +771,8 @@ public: { return Offset.isZero(); } + + void Serialize(FSerializer& arc) override; }; const double MinVel = EQUAL_EPSILON; diff --git a/src/playsim/d_player.h b/src/playsim/d_player.h index 2a2fd3334..47c339e42 100644 --- a/src/playsim/d_player.h +++ b/src/playsim/d_player.h @@ -322,8 +322,8 @@ public: AActor *mo = nullptr; uint8_t playerstate = 0; ticcmd_t cmd = {}; - usercmd_t original_cmd; - uint32_t original_oldbuttons; + usercmd_t original_cmd = {}; + uint32_t original_oldbuttons = 0; userinfo_t userinfo; // [RH] who is this? @@ -340,7 +340,7 @@ public: // mo->velx and mo->vely represent true velocity experienced by player. // This only represents the thrust that the player applies himself. // This avoids anomalies with such things as Boom ice and conveyors. - DVector2 Vel = { 0,0 }; + DVector2 Vel; bool centering = false; uint8_t turnticks = 0; @@ -419,10 +419,10 @@ public: FString SoundClass; FString LogText; // [RH] Log for Strife FString SubtitleText; - int SubtitleCounter; + int SubtitleCounter = 0; - DAngle MinPitch = nullAngle; // Viewpitch limits (negative is up, positive is down) - DAngle MaxPitch = nullAngle; + DAngle MinPitch; // Viewpitch limits (negative is up, positive is down) + DAngle MaxPitch; double crouchfactor = 0; double crouchoffset = 0; @@ -432,7 +432,7 @@ public: // [CW] I moved these here for multiplayer conversation support. TObjPtr ConversationNPC = MakeObjPtr(nullptr), ConversationPC = MakeObjPtr(nullptr); - DAngle ConversationNPCAngle = nullAngle; + DAngle ConversationNPCAngle; bool ConversationFaceTalker = false; DVector3 LastSafePos = {}; // Mark the last known safe location the player was standing. diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index ad95f8ac6..2ef17b2a9 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -1545,6 +1545,13 @@ void DActorModelData::OnDestroy() animationIDs.Reset(); } +void DViewPosition::Serialize(FSerializer& arc) +{ + Super::Serialize(arc); + arc("offset", Offset) + ("flags", Flags); +} + //---------------------------------------------------------------------------- // // PROC P_ExplodeMissile diff --git a/src/playsim/p_user.cpp b/src/playsim/p_user.cpp index 652d533ca..934259797 100644 --- a/src/playsim/p_user.cpp +++ b/src/playsim/p_user.cpp @@ -1788,6 +1788,7 @@ void player_t::Serialize(FSerializer &arc) ("musinfoactor", MUSINFOactor) ("musinfotics", MUSINFOtics) ("soundclass", SoundClass) + ("angleoffsettargets", angleOffsetTargets); ("lastsafepos", LastSafePos); if (arc.isWriting ()) From 493ebb8bcbfc86bdfaf2327a84767261e7dc2afc Mon Sep 17 00:00:00 2001 From: Boondorl Date: Fri, 15 Nov 2024 23:48:18 -0500 Subject: [PATCH 18/30] Fixed angleOffsetTargets not being initialized --- src/playsim/d_player.h | 10 +++++----- src/playsim/p_user.cpp | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/playsim/d_player.h b/src/playsim/d_player.h index 47c339e42..862890f07 100644 --- a/src/playsim/d_player.h +++ b/src/playsim/d_player.h @@ -306,7 +306,7 @@ void WriteUserInfo(FSerializer &arc, userinfo_t &info); class player_t { public: - player_t() = default; + player_t() { angleOffsetTargets.Zero(); } ~player_t(); player_t &operator= (const player_t &p) = delete; void CopyFrom(player_t &src, bool copyPSP); @@ -340,7 +340,7 @@ public: // mo->velx and mo->vely represent true velocity experienced by player. // This only represents the thrust that the player applies himself. // This avoids anomalies with such things as Boom ice and conveyors. - DVector2 Vel; + DVector2 Vel = { 0.0, 0.0 }; bool centering = false; uint8_t turnticks = 0; @@ -421,8 +421,8 @@ public: FString SubtitleText; int SubtitleCounter = 0; - DAngle MinPitch; // Viewpitch limits (negative is up, positive is down) - DAngle MaxPitch; + DAngle MinPitch = nullAngle; // Viewpitch limits (negative is up, positive is down) + DAngle MaxPitch = nullAngle; double crouchfactor = 0; double crouchoffset = 0; @@ -432,7 +432,7 @@ public: // [CW] I moved these here for multiplayer conversation support. TObjPtr ConversationNPC = MakeObjPtr(nullptr), ConversationPC = MakeObjPtr(nullptr); - DAngle ConversationNPCAngle; + DAngle ConversationNPCAngle = nullAngle; bool ConversationFaceTalker = false; DVector3 LastSafePos = {}; // Mark the last known safe location the player was standing. diff --git a/src/playsim/p_user.cpp b/src/playsim/p_user.cpp index 934259797..65f892903 100644 --- a/src/playsim/p_user.cpp +++ b/src/playsim/p_user.cpp @@ -1788,7 +1788,7 @@ void player_t::Serialize(FSerializer &arc) ("musinfoactor", MUSINFOactor) ("musinfotics", MUSINFOtics) ("soundclass", SoundClass) - ("angleoffsettargets", angleOffsetTargets); + ("angleoffsettargets", angleOffsetTargets) ("lastsafepos", LastSafePos); if (arc.isWriting ()) From ac2c1741617ca7ff5a619bf19fa362375453a35e Mon Sep 17 00:00:00 2001 From: Boondorl Date: Tue, 26 Nov 2024 21:02:16 -0500 Subject: [PATCH 19/30] Added ripper damage logic to DoMissileDamage --- src/playsim/p_map.cpp | 72 +++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 47 deletions(-) diff --git a/src/playsim/p_map.cpp b/src/playsim/p_map.cpp index 0c881928f..e487c5b9c 100644 --- a/src/playsim/p_map.cpp +++ b/src/playsim/p_map.cpp @@ -1343,46 +1343,44 @@ static bool CanAttackHurt(AActor *victim, AActor *shooter) // //========================================================================== -void P_DoMissileDamage(AActor* inflictor, AActor* target) +void P_DoMissileDamage(AActor* self, AActor* victim) { + const bool ripper = (self->flags2 & MF2_RIP); + // Do poisoning (if using new style poison) - if (inflictor->PoisonDamage > 0 && inflictor->PoisonDuration != INT_MIN) - { - P_PoisonMobj(target, inflictor, inflictor->target, inflictor->PoisonDamage, inflictor->PoisonDuration, inflictor->PoisonPeriod, inflictor->PoisonDamageType); - } + if (self->PoisonDamage > 0 && self->PoisonDuration != INT_MIN) + P_PoisonMobj(victim, self, self->target, self->PoisonDamage, self->PoisonDuration, self->PoisonPeriod, self->PoisonDamageType); // Do damage - int damage = inflictor->GetMissileDamage((inflictor->flags4 & MF4_STRIFEDAMAGE) ? 3 : 7, 1); - if ((damage > 0) || (inflictor->flags6 & MF6_FORCEPAIN) || (inflictor->flags7 & MF7_CAUSEPAIN)) + int damage = ripper ? self->GetMissileDamage(3, 2) : self->GetMissileDamage((self->flags4 & MF4_STRIFEDAMAGE) ? 3 : 7, 1); + if (damage > 0 || (self->flags6 & MF6_FORCEPAIN) || (self->flags7 & MF7_CAUSEPAIN)) { - int newdam = P_DamageMobj(target, inflictor, inflictor->target, damage, inflictor->DamageType); - if (damage > 0) + if (ripper) + S_Sound(self, CHAN_BODY, 0, self->SoundVar(NAME_RipSound), 1.0f, ATTN_IDLE); + + int dealt = P_DamageMobj(victim, self, self->target, damage, self->DamageType); + if (damage > 0 && !(self->flags3 & MF3_BLOODLESSIMPACT) + && !(victim->flags & MF_NOBLOOD) + && !(victim->flags2 & (MF2_INVULNERABLE | MF2_DORMANT | MF2_REFLECTIVE))) { - if ((inflictor->flags5 & MF5_BLOODSPLATTER) && - !(target->flags & MF_NOBLOOD) && - !(target->flags2 & MF2_REFLECTIVE) && - !(target->flags2 & (MF2_INVULNERABLE | MF2_DORMANT)) && - !(inflictor->flags3 & MF3_BLOODLESSIMPACT) && - (pr_checkthing() < 192)) - { - P_BloodSplatter(inflictor->Pos(), target, inflictor->AngleTo(target)); - } - if (!(inflictor->flags3 & MF3_BLOODLESSIMPACT)) - { - P_TraceBleed(newdam > 0 ? newdam : damage, target, inflictor); - } + if (ripper) + P_RipperBlood(self, victim); + else if ((self->flags5 & MF5_BLOODSPLATTER) && pr_checkthing() < 192) + P_BloodSplatter(self->Pos(), victim, self->AngleTo(victim)); + + P_TraceBleed(dealt > 0 ? dealt : damage, victim, self); } } else { - P_GiveBody(target, -damage); + P_GiveBody(victim, -damage); } } -DEFINE_ACTION_FUNCTION(AActor, DoMissileDamage) +DEFINE_ACTION_FUNCTION_NATIVE(AActor, DoMissileDamage, P_DoMissileDamage) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT_NOT_NULL(target, AActor); - P_DoMissileDamage(self, target); + PARAM_OBJECT_NOT_NULL(victim, AActor); + P_DoMissileDamage(self, victim); return 0; } //========================================================================== @@ -1687,27 +1685,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch if (check == NULL || !*check) { tm.LastRipped[thing] = true; - if (!(thing->flags & MF_NOBLOOD) && - !(thing->flags2 & MF2_REFLECTIVE) && - !(tm.thing->flags3 & MF3_BLOODLESSIMPACT) && - !(thing->flags2 & (MF2_INVULNERABLE | MF2_DORMANT))) - { // Ok to spawn blood - P_RipperBlood(tm.thing, thing); - } - S_Sound(tm.thing, CHAN_BODY, 0, tm.thing->SoundVar(NAME_RipSound), 1, ATTN_IDLE); - - // Do poisoning (if using new style poison) - if (tm.thing->PoisonDamage > 0 && tm.thing->PoisonDuration != INT_MIN) - { - P_PoisonMobj(thing, tm.thing, tm.thing->target, tm.thing->PoisonDamage, tm.thing->PoisonDuration, tm.thing->PoisonPeriod, tm.thing->PoisonDamageType); - } - - damage = tm.thing->GetMissileDamage(3, 2); - int newdam = P_DamageMobj(thing, tm.thing, tm.thing->target, damage, tm.thing->DamageType); - if (!(tm.thing->flags3 & MF3_BLOODLESSIMPACT)) - { - P_TraceBleed(newdam > 0 ? newdam : damage, thing, tm.thing); - } + P_DoMissileDamage(tm.thing, thing); if (thing->flags2 & MF2_PUSHABLE && !(tm.thing->flags2 & MF2_CANNOTPUSH)) { // Push thing From 859bca44761e3ed8d9232faa422a4d6edaf7b0c5 Mon Sep 17 00:00:00 2001 From: Boondorl Date: Tue, 26 Nov 2024 21:23:04 -0500 Subject: [PATCH 20/30] Fixed successful bounces on Actor tops not damaging them --- src/playsim/p_mobj.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index 2ef17b2a9..c79255cca 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -4379,14 +4379,13 @@ void AActor::Tick () } if (Vel.Z != 0 && (BounceFlags & BOUNCE_Actors)) { - bool res = P_BounceActor(this, onmo, true); + if (flags & MF_MISSILE) + P_DoMissileDamage(this, onmo); + // If the bouncer is a missile and has hit the other actor it needs to be exploded here // to be in line with the case when an actor's side is hit. - if (!res && (flags & MF_MISSILE)) - { - P_DoMissileDamage(this, onmo); + if (!P_BounceActor(this, onmo, true) && (flags & MF_MISSILE)) P_ExplodeMissile(this, nullptr, onmo); - } } else { From a88516bbd2a3f04a543834dbc066ad0f434041a0 Mon Sep 17 00:00:00 2001 From: Boondorl Date: Tue, 26 Nov 2024 23:43:21 -0500 Subject: [PATCH 21/30] Various bouncing fixes Fixed bounce flag checks being inversed on 3D floors. Decoupled wall bouncing flag from floor/ceiling flags since they relied on it in the case of hitting steep ramps. Fixed wall bounces that actually bounce off planes not returning the correct value. --- src/playsim/p_map.cpp | 14 +++++++++----- src/playsim/p_mobj.cpp | 12 ++++++------ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/playsim/p_map.cpp b/src/playsim/p_map.cpp index e487c5b9c..ef5438afd 100644 --- a/src/playsim/p_map.cpp +++ b/src/playsim/p_map.cpp @@ -3552,7 +3552,9 @@ bool FSlide::BounceWall(AActor *mo) double movelen; line_t *line; - if (!(mo->BounceFlags & BOUNCE_Walls)) + // The plane bounce flags need to be checked here in case it hit a ramp while + // moving along the xy axes. + if (!(mo->BounceFlags & (BOUNCE_Walls | BOUNCE_Ceilings | BOUNCE_Floors))) { return false; } @@ -3587,16 +3589,18 @@ bool FSlide::BounceWall(AActor *mo) if (floordist <= ceildist) { NextLowestFloorAt(mo->Sector, mo->X(), mo->Y(), mo->Z(), 0, mo->MaxStepHeight, nullptr, &ff); - mo->FloorBounceMissile(ff != nullptr ? *ff->top.plane : mo->floorsector->floorplane, ff != nullptr); - return true; + return !mo->FloorBounceMissile(ff != nullptr ? *ff->top.plane : mo->floorsector->floorplane, ff != nullptr); } else { NextHighestCeilingAt(mo->Sector, mo->X(), mo->Y(), mo->Z(), mo->Top(), 0, nullptr, &ff); - mo->FloorBounceMissile(ff != nullptr ? *ff->bottom.plane : mo->ceilingsector->ceilingplane, ff != nullptr); - return true; + return !mo->FloorBounceMissile(ff != nullptr ? *ff->bottom.plane : mo->ceilingsector->ceilingplane, ff != nullptr); } } + + if (!(mo->BounceFlags & BOUNCE_Walls)) + return false; + line = bestslideline; if (mo->flags & MF_MISSILE) diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index c79255cca..09c97d2ff 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -1782,9 +1782,13 @@ bool AActor::FloorBounceMissile (secplane_t &plane, bool is3DFloor) } } + DVector3 norm = plane.Normal(); + if (is3DFloor) + norm = -norm; + bool onsky; - if (plane.fC() < 0) + if (norm.Z < 0) { // on ceiling if (!(BounceFlags & BOUNCE_Ceilings)) return true; @@ -1815,10 +1819,6 @@ bool AActor::FloorBounceMissile (secplane_t &plane, bool is3DFloor) return true; } - DVector3 norm = plane.Normal(); - if (is3DFloor) - norm = -norm; - double dot = (Vel | norm) * 2; if (BounceFlags & (BOUNCE_HereticType | BOUNCE_MBF)) @@ -1846,7 +1846,7 @@ bool AActor::FloorBounceMissile (secplane_t &plane, bool is3DFloor) // Set bounce state if (BounceFlags & BOUNCE_UseBounceState) { - FName names[2] = { NAME_Bounce, plane.fC() < 0 ? NAME_Ceiling : NAME_Floor }; + FName names[2] = { NAME_Bounce, norm.Z < 0 ? NAME_Ceiling : NAME_Floor }; FState *bouncestate = FindState(2, names); if (bouncestate != nullptr) { From 008761651187ca524ac5067f7ec781fa61d26665 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Fri, 29 Nov 2024 13:54:17 -0300 Subject: [PATCH 22/30] misc decoupled animation fixes --- src/playsim/p_actionfunctions.cpp | 84 ++++++++++++++++--------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/src/playsim/p_actionfunctions.cpp b/src/playsim/p_actionfunctions.cpp index ea7090c1d..8d50993d9 100644 --- a/src/playsim/p_actionfunctions.cpp +++ b/src/playsim/p_actionfunctions.cpp @@ -5130,6 +5130,7 @@ enum ESetAnimationFlags void SetAnimationInternal(AActor * self, FName animName, double framerate, int startFrame, int loopFrame, int endFrame, int interpolateTics, int flags, double ticFrac) { + if(!self) ThrowAbortException(X_READ_NIL, "In function parameter self"); if(!(self->flags9 & MF9_DECOUPLEDANIMATIONS)) @@ -5176,43 +5177,46 @@ void SetAnimationInternal(AActor * self, FName animName, double framerate, int s if(!(flags & SAF_INSTANT)) { - if(self->modelData->curAnim.startTic > tic) - { - ModelAnimFrameInterp to; - float inter; - - calcFrames(self->modelData->curAnim, tic, to, inter); - - const TArray* animationData = nullptr; - - int animationid = -1; - - const FSpriteModelFrame * smf = &BaseSpriteModelFrames[self->GetClass()]; - - if (self->modelData->animationIDs.Size() > 0 && self->modelData->animationIDs[0] >= 0) + if((self->modelData->curAnim.startTic - self->modelData->curAnim.switchOffset) != int(floor(tic))) + { // don't change interpolation data if animation switch happened in the same tic + if(self->modelData->curAnim.startTic > tic) { - animationid = self->modelData->animationIDs[0]; + ModelAnimFrameInterp to; + float inter; + + calcFrames(self->modelData->curAnim, tic, to, inter); + + const TArray* animationData = nullptr; + + int animationid = -1; + + const FSpriteModelFrame * smf = &BaseSpriteModelFrames[self->GetClass()]; + + if (self->modelData->animationIDs.Size() > 0 && self->modelData->animationIDs[0] >= 0) + { + animationid = self->modelData->animationIDs[0]; + } + else if(smf->modelsAmount > 0) + { + animationid = smf->animationIDs[0]; + } + + FModel* animation = mdl; + + if (animationid >= 0) + { + animation = Models[animationid]; + animationData = animation->AttachAnimationData(); + } + + self->modelData->prevAnim = animation->PrecalculateFrame(self->modelData->prevAnim, to, inter, animationData, self->boneComponentData, 0); } - else if(smf->modelsAmount > 0) + else { - animationid = smf->animationIDs[0]; + self->modelData->prevAnim = ModelAnimFrameInterp{}; + + calcFrame(self->modelData->curAnim, tic, std::get(self->modelData->prevAnim)); } - - FModel* animation = mdl; - - if (animationid >= 0) - { - animation = Models[animationid]; - animationData = animation->AttachAnimationData(); - } - - self->modelData->prevAnim = animation->PrecalculateFrame(self->modelData->prevAnim, to, inter, animationData, self->boneComponentData, 0); - } - else - { - self->modelData->prevAnim = ModelAnimFrameInterp{}; - - calcFrame(self->modelData->curAnim, tic, std::get(self->modelData->prevAnim)); } } else @@ -5524,7 +5528,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_ChangeModel, ChangeModelNative) DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetAnimation, SetAnimationNative) { - PARAM_ACTION_PROLOGUE(AActor); + PARAM_SELF_PROLOGUE(AActor); PARAM_NAME(animName); PARAM_FLOAT(framerate); PARAM_INT(startFrame); @@ -5540,7 +5544,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetAnimation, SetAnimationNative) DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetAnimationUI, SetAnimationUINative) { - PARAM_ACTION_PROLOGUE(AActor); + PARAM_SELF_PROLOGUE(AActor); PARAM_NAME(animName); PARAM_FLOAT(framerate); PARAM_INT(startFrame); @@ -5556,7 +5560,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetAnimationUI, SetAnimationUINative) DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetAnimationFrameRate, SetAnimationFrameRateNative) { - PARAM_ACTION_PROLOGUE(AActor); + PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(framerate); SetAnimationFrameRateInternal(self, framerate, 1); @@ -5566,7 +5570,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetAnimationFrameRate, SetAnimationFrameRa DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetAnimationFrameRateUI, SetAnimationFrameRateUINative) { - PARAM_ACTION_PROLOGUE(AActor); + PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(framerate); SetAnimationFrameRateInternal(self, framerate, I_GetTimeFrac()); @@ -5576,7 +5580,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetAnimationFrameRateUI, SetAnimationFrame DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetModelFlag, SetModelFlag) { - PARAM_ACTION_PROLOGUE(AActor); + PARAM_SELF_PROLOGUE(AActor); PARAM_INT(flag); SetModelFlag(self, flag); @@ -5586,7 +5590,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetModelFlag, SetModelFlag) DEFINE_ACTION_FUNCTION_NATIVE(AActor, ClearModelFlag, ClearModelFlag) { - PARAM_ACTION_PROLOGUE(AActor); + PARAM_SELF_PROLOGUE(AActor); PARAM_INT(flag); ClearModelFlag(self, flag); @@ -5596,7 +5600,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, ClearModelFlag, ClearModelFlag) DEFINE_ACTION_FUNCTION_NATIVE(AActor, ResetModelFlags, ResetModelFlags) { - PARAM_ACTION_PROLOGUE(AActor); + PARAM_SELF_PROLOGUE(AActor); ResetModelFlags(self); From fc3a2e2ad1d46e8b3b63c56c2af16d0c3167c385 Mon Sep 17 00:00:00 2001 From: Boondorl Date: Fri, 29 Nov 2024 07:24:30 -0500 Subject: [PATCH 23/30] Fixed A_SprayDecal not working on 3D floors --- src/playsim/a_decals.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/playsim/a_decals.cpp b/src/playsim/a_decals.cpp index 1c0fd4712..ab40d0706 100644 --- a/src/playsim/a_decals.cpp +++ b/src/playsim/a_decals.cpp @@ -854,7 +854,7 @@ void SprayDecal(AActor *shooter, const char *name, double distance, DVector3 off { if (trace.HitType == TRACE_HitWall) { - DImpactDecal::StaticCreate(shooter->Level, name, trace.HitPos, trace.Line->sidedef[trace.Side], NULL, entry, bloodTrans); + DImpactDecal::StaticCreate(shooter->Level, name, trace.HitPos, trace.Line->sidedef[trace.Side], trace.ffloor, entry, bloodTrans); } } } From 3e10e3f55115ce4ed70f62eb0d19bb67ff19153f Mon Sep 17 00:00:00 2001 From: RaveYard <29225776+MrRaveYard@users.noreply.github.com> Date: Thu, 5 Dec 2024 00:45:02 +0100 Subject: [PATCH 24/30] Fix M_SaveBitmap stream buffer size - credits to dpJudas for the solution --- src/common/textures/m_png.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/common/textures/m_png.cpp b/src/common/textures/m_png.cpp index 331b35e20..83714a6ac 100644 --- a/src/common/textures/m_png.cpp +++ b/src/common/textures/m_png.cpp @@ -54,7 +54,7 @@ // MACROS ------------------------------------------------------------------ // The maximum size of an IDAT chunk ZDoom will write. This is also the -// size of the compression buffer it allocates on the stack. +// size of the compression buffer it allocates on the heap. #define PNG_WRITE_SIZE 32768 // Set this to 1 to use a simple heuristic to select the filter to apply @@ -926,8 +926,7 @@ bool M_SaveBitmap(const uint8_t *from, ESSType color_type, int width, int height temprow[i] = &temprow_storage[temprow_size * i]; } - TArray array(PNG_WRITE_SIZE, true); - auto buffer = array.data(); + TArray buffer(PNG_WRITE_SIZE, true); z_stream stream; int err; int y; @@ -944,8 +943,8 @@ bool M_SaveBitmap(const uint8_t *from, ESSType color_type, int width, int height } y = height; - stream.next_out = buffer; - stream.avail_out = sizeof(buffer); + stream.next_out = buffer.data(); + stream.avail_out = buffer.size(); temprow[0][0] = 0; #if USE_FILTER_HEURISTIC @@ -1007,12 +1006,12 @@ bool M_SaveBitmap(const uint8_t *from, ESSType color_type, int width, int height } while (stream.avail_out == 0) { - if (!WriteIDAT (file, buffer, sizeof(buffer))) + if (!WriteIDAT (file, buffer.data(), buffer.size())) { return false; } - stream.next_out = buffer; - stream.avail_out = sizeof(buffer); + stream.next_out = buffer.data(); + stream.avail_out = buffer.size(); if (stream.avail_in != 0) { err = deflate (&stream, (y == 0) ? Z_FINISH : 0); @@ -1033,12 +1032,12 @@ bool M_SaveBitmap(const uint8_t *from, ESSType color_type, int width, int height } if (stream.avail_out == 0) { - if (!WriteIDAT (file, buffer, sizeof(buffer))) + if (!WriteIDAT (file, buffer.data(), buffer.size())) { return false; } - stream.next_out = buffer; - stream.avail_out = sizeof(buffer); + stream.next_out = buffer.data(); + stream.avail_out = buffer.size(); } } @@ -1048,7 +1047,7 @@ bool M_SaveBitmap(const uint8_t *from, ESSType color_type, int width, int height { return false; } - return WriteIDAT (file, buffer, sizeof(buffer)-stream.avail_out); + return WriteIDAT (file, buffer.data(), buffer.size() - stream.avail_out); } //========================================================================== From 1d04bd36d0005cb025927542fdf263a9e06d7a13 Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Thu, 5 Dec 2024 04:09:51 -0500 Subject: [PATCH 25/30] - allow forks to set OPTIONALWAD to (null) to disable searching for it. --- src/d_iwad.cpp | 2 +- src/version.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index 1eb0c0ea0..6ce60d30b 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -824,7 +824,7 @@ int FIWadManager::IdentifyVersion (std::vector&wadfiles, const char // [SP] Load non-free assets if available. This must be done before the IWAD. int iwadnum = 1; - if (D_AddFile(wadfiles, optional_wad, true, -1, GameConfig)) + if (optional_wad && D_AddFile(wadfiles, optional_wad, true, -1, GameConfig)) { iwadnum++; } diff --git a/src/version.h b/src/version.h index ca9cc3e59..c7bdc3072 100644 --- a/src/version.h +++ b/src/version.h @@ -93,6 +93,7 @@ const char *GetVersionString(); // This is so that derivates can use the same savegame versions without worrying about engine compatibility #define GAMESIG "GZDOOM" #define BASEWAD "gzdoom.pk3" +// Set OPTIONALWAD to "" (null) to disable searching for it #define OPTIONALWAD "game_support.pk3" #define GZDOOM 1 #define VR3D_ENABLED From 7fed2b85f647c2131fc613c0624937ffa8d64108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Tue, 10 Dec 2024 15:18:56 -0300 Subject: [PATCH 26/30] remove version check for array type fix, to prevent crashes/etc with bad types --- src/common/scripting/backend/codegen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/scripting/backend/codegen.cpp b/src/common/scripting/backend/codegen.cpp index 86bd606f9..03a41f3a8 100644 --- a/src/common/scripting/backend/codegen.cpp +++ b/src/common/scripting/backend/codegen.cpp @@ -8993,7 +8993,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) } else { - if (PFunction **Override; ctx.Version >= MakeVersion(4, 11, 0) && (Override = static_cast(Self->ValueType)->FnOverrides.CheckKey(MethodName))) + if (PFunction **Override; (Override = static_cast(Self->ValueType)->FnOverrides.CheckKey(MethodName))) { afd_override = *Override; } From b5b3fe1b5edb869869cf4d7cd833d9e32240237b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Fri, 13 Dec 2024 16:36:00 -0300 Subject: [PATCH 27/30] remove "DECORATE" from error string * print warning count as well * allow treating warnings as errors --- src/common/scripting/backend/vmbuilder.cpp | 1 + src/scripting/thingdef.cpp | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/common/scripting/backend/vmbuilder.cpp b/src/common/scripting/backend/vmbuilder.cpp index 5437ca848..c9bfc63af 100644 --- a/src/common/scripting/backend/vmbuilder.cpp +++ b/src/common/scripting/backend/vmbuilder.cpp @@ -40,6 +40,7 @@ #include "filesystem.h" CVAR(Bool, strictdecorate, false, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) +CVAR(Bool, warningstoerrors, false, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) EXTERN_CVAR(Bool, vm_jit) EXTERN_CVAR(Bool, vm_jit_aot) diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index 6affab4c3..bdec840f5 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -65,6 +65,7 @@ static TMap StateSourceLines; static FScriptPosition unknownstatesource("unknown file", 0); EXTERN_CVAR(Bool, strictdecorate); +EXTERN_CVAR(Bool, warningstoerrors); //========================================================================== // @@ -464,8 +465,27 @@ void LoadActors() if (FScriptPosition::ErrorCounter > 0) { - I_Error("%d errors while parsing DECORATE scripts", FScriptPosition::ErrorCounter); + if (FScriptPosition::WarnCounter > 0) + { + I_Error("%d errors, %d warnings while parsing scripts", FScriptPosition::ErrorCounter, FScriptPosition::WarnCounter); + } + else + { + I_Error("%d errors while parsing scripts", FScriptPosition::ErrorCounter); + } } + else if (FScriptPosition::WarnCounter > 0) + { + if(warningstoerrors) + { + I_Error("%d warnings while parsing scripts\n", FScriptPosition::WarnCounter); + } + else + { + Printf(TEXTCOLOR_ORANGE "%d warnings while parsing scripts\n", FScriptPosition::WarnCounter); + } + } + FScriptPosition::ResetErrorCounter(); // AllActorClasses hasn'T been set up yet. for (int i = PClass::AllClasses.Size() - 1; i >= 0; i--) From 2a940a7418e5fa02993432174577e5bc30f8bc01 Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Mon, 16 Dec 2024 04:38:27 -0500 Subject: [PATCH 28/30] - this is version 4.14.0 --- src/version.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/version.h b/src/version.h index c7bdc3072..28d54caeb 100644 --- a/src/version.h +++ b/src/version.h @@ -41,11 +41,11 @@ const char *GetVersionString(); /** Lots of different version numbers **/ -#define VERSIONSTR "4.14pre" +#define VERSIONSTR "4.14.0" // The version as seen in the Windows resource -#define RC_FILEVERSION 4,13,9999,0 -#define RC_PRODUCTVERSION 4,13,9999,0 +#define RC_FILEVERSION 4,14,0,0 +#define RC_PRODUCTVERSION 4,14,0,0 #define RC_PRODUCTVERSION2 VERSIONSTR // These are for content versioning. #define VER_MAJOR 4 From b37b95aa042a31b54d8cf3ae99b836f313617af6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Mon, 16 Dec 2024 17:05:39 -0300 Subject: [PATCH 29/30] Fix damage being skipped for spectral puffs --- src/playsim/p_interaction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/playsim/p_interaction.cpp b/src/playsim/p_interaction.cpp index 0ae77e914..60b6f3059 100644 --- a/src/playsim/p_interaction.cpp +++ b/src/playsim/p_interaction.cpp @@ -1158,7 +1158,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da // Special damage types if (inflictor) { - if (inflictor->flags4 & MF4_SPECTRAL) + if (inflictor->flags4 & MF4_SPECTRAL && !(inflictor->flags9 & MF9_ISPUFF)) { if (player != NULL) { From 25ec8a689d5654a7f57869e09c0ce0d0892ba6a4 Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Tue, 17 Dec 2024 14:17:50 -0500 Subject: [PATCH 30/30] - language update --- wadsrc/static/language.0 | 6 +++--- wadsrc/static/language.csv | 5 +++-- wadsrc_extra/static/language.csv | 8 ++++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/wadsrc/static/language.0 b/wadsrc/static/language.0 index cf004c828..3eefd93d7 100644 --- a/wadsrc/static/language.0 +++ b/wadsrc/static/language.0 @@ -873,12 +873,12 @@ Appearance,DSPLYMNU_APPEARANCE,,,,Vzhled,Udseende,Spieldarstellung,,Aspekto,Apar Advanced Display Options,DSPLYMNU_ADVANCED,,,,Grafika (pokročilé),Avancerede visningsindstillinger,Erweiterte Anzeigeoptionen,,Altnivelaj ekran-agordoj,Opciones avanzadas de visualización,,Näytön lisäasetukset,Options d'affichage avancées,Napredne postavke zaslona,Speciális megjelenítési beállítások,Opzioni di visualizzazione avanzate,高度なディスプレイオプション,고급 디스플레이 옵션,Geavanceerde Weergave Opties,Avanserte visningsalternativer,Zaawansowane Opcje Wyświetlania,Opções de vídeo avançadas,,Opțiuni avansate de afișare,Расширенные настройки экрана,Напредне опције приказа,Avancerade visningsalternativ,Gelişmiş Görüntüleme Seçenekleri,Додаткові параметри відображення, ,,IWAD/Game picker,,,,,,,,,,,,,,,,,,,,,,,,,,,, Select which game file to run.,PICKER_SELECT,,,,"Vyberte, jaký herní soubor spustit.","Vælg, hvilket spil du vil spille",Bitte wähle ein Spiel aus.,,Elektu kiun ludodosieron ruli.,,,Valitse suoritettava pelitiedosto.,Sélectionner le jeu à jouer,Odaberi koju igru želiš pokrenuti.,"Válassza ki, hogy melyik játékfájlt futtassa.",Selezionare il file di gioco da eseguire.,実行するゲームファイルを選択します。,실행할 게임 파일을 선택합니다.,Selecteer welk spel je wilt spelen,Velg hvilket spill du vil spille,"Wybierz, który plik gry uruchomić.",Selecione qual arquivo de jogo rodar.,,Selectați ce fișier de joc să rulați.,Выбор файла игры для запуска.,Изаберите коју датотеку игре желите да покренете.,Välj vilket spel du vill spela,Hangi oyunu oynayacağınızı seçin,Виберіть файл гри для запуску., -Play Game,PICKER_PLAY,,,,Hrát hru,Start spil,Spielen,,Ludi ludon,,,Pelin pelaaminen,Démarrer le jeu,Zaigraj igru,Játék lejátszása,Esegui gioco,ゲームをプレイする,게임 플레이,Spel starten,Start spill,Graj,Jogar,,Joacă jocul,Играть,Играј игру,Starta spel,Oyunu Başlat,Запустити гру, +Play Game,PICKER_PLAY,,,,Hrát hru,Start spil,Spielen,,Ludi ludon,,,Pelin pelaaminen,Démarrer le jeu,Zaigraj igru,Játék lejátszása,Esegui gioco,プレイ,게임 플레이,Spel starten,Start spill,Graj,Jogar,,Joacă jocul,Играть,Играј игру,Starta spel,Oyunu Başlat,Запустити гру, Exit,PICKER_EXIT,,,,Odejít,Afslut,Verlassen,,Eliri,,,Poistu,Quitter,Izlaz,Kilépés,Esci,終了,종료,Verlaten,Avslutt,Wyjdź,Sair,,Ieșire,Выход,Изађи,Avsluta,Çıkış,Вихід, General,PICKER_GENERAL,,,,Obecné,Generelt,Allgemein,,Ĝenerala,,,Yleistä,Général,Općenito,Általános,Generale,一般,일반,Algemeen,Generelt,Ogólne,Geral,,,Общее,Генерал,Allmänt,Genel,Загальні, Extra Graphics,PICKER_EXTRA,,,,Grafické doplňky,Ekstra grafik,Extragrafiken,,Ekstra grafiko,,,Extra Graphics,Graphiques supplémentaires,Dodatna grafika,Extra grafika,Grafica extra,追加グラフィックス,추가 그래픽,Extra afbeeldingen,Ekstra grafikk,Ekstra grafiki,Gráficos extras,,Grafică suplimentară,Доп. графика,Ектра Грапхицс,Extra grafik,Ekstra Grafikler,Додаткова графіка, Fullscreen,PICKER_FULLSCREEN,,,,Přes celou obrazovku,Fuld skærm,Vollbild,,Plena ekrano,,,Koko näyttö,Plein écran,Puni zaslon,Teljes képernyő,Schermo intero,フルスクリーン,전체 화면,Volledig scherm,Fullskjerm,Pełny ekran,Tela cheia,,Ecran complet,Полный экран,Цео екран,Fullskärm,Tam Ekran,Повноекранний режим, -Disable autoload,PICKER_NOAUTOLOAD,,,,Zakázat autoload,Deaktiver autoload,Autoload deaktivieren,,Malvalidigi aŭtoŝargon,,,Poista automaattinen lataus käytöstä,Désactiver le chargement automatique,Onemogući automatsko učitavanje,Automatikus betöltés kikapcsolása,Disabilita il caricamento automatico,オートロードを無効にする,자동 로드 비활성화,Autoload uitschakelen,Deaktiver autolading,Wyłącz auto-ładowanie,Desativar autocarregam.,,Dezactivați încărcarea automată,Откл. автозагрузку,Онемогући аутоматско учитавање,Inaktivera autoload,Otomatik yükleme yok,Вимкнути автозавантаження, +Disable autoload,PICKER_NOAUTOLOAD,,,,Zakázat autoload,Deaktiver autoload,Autoload deaktivieren,,Malvalidigi aŭtoŝargon,,,Poista automaattinen lataus käytöstä,Désactiver le chargement automatique,Onemogući automatsko učitavanje,Automatikus betöltés kikapcsolása,Disabilita il caricamento automatico,オートロード無効,자동 로드 비활성화,Autoload uitschakelen,Deaktiver autolading,Wyłącz auto-ładowanie,Desativar autocarregam.,,Dezactivați încărcarea automată,Откл. автозагрузку,Онемогући аутоматско учитавање,Inaktivera autoload,Otomatik yükleme yok,Вимкнути автозавантаження, Don't ask me again,PICKER_DONTASK,,,,Již se neptat,Spørg mig ikke igen,Nicht nochmal fragen,,Ne demandu min denove,,,Älä kysy uudestaan,Ne me demandez plus rien,Više me ne pitaj,Ne kérdezz újra,Non chiedermelo più,再度聞かない,다시 묻지 마세요,Vraag me niet opnieuw,Ikke spør meg igjen,Nie pytaj ponownie,Não perguntar de novo,,Nu mă mai întrebați din nou,Не спрашивать снова,Не питај ме поново,Fråga mig inte igen,Bir daha sorma.,Не запитуйте мене більше, Lights,PICKER_LIGHTS,,,,Světla,Lys,Lichtdefinitionen,,Lumoj,,,Valot,Lumières,Svjetla,Fények,Luci,ライト,조명,Verlichting,Lysdefinisjoner,Oświetlenie,Luzes,,Lumini,Освещение,Светла,Definitioner av ljus,Işık tanımları,Освітлення, Brightmaps,PICKER_BRIGHTMAPS,,,,,,,,Helomapoj,,,Brightmaps,Cartes lumineuses,Svijetle karte,Brightmaps,Mappe luminose,ブライトマップ,브라이트맵,Heldermaps,Lyskart,Mapowanie świateł,,,,Карты освещения,Бригхтмапс,Ljuskartor,Brightmaps,Яскраві карти, @@ -891,4 +891,4 @@ Game,PICKER_TAB_PLAY,,,,Hra,Spil,Spiel,,Ludo,Juego,,Peli,Jeu,Igra,Játék,Gioco, Enable this controller,JOYMNU_JOYENABLE,Option to enable or disable individual controllers/joysticks when configuring it in the Controller Options menu,,,Povolit tento ovladač,Aktivér denne controller,Diesen Controller aktivieren,,Ŝalti ĉi tiun ludregilon,Habilitar este controlador,,Aktivoi tämä ohjain,Activer ce contrôleur,Omogući ovaj kontroler,Engedélyezze ezt a vezérlőt,Attiva questo controller,このコントローラーを有効にする,이 컨트롤러 활성화,Deze controller inschakelen,Aktiver denne kontrolleren,Włącz ten kontroler,Habilitar este controle,,Activați acest controler,Включить этот контроллер,Омогућите овај контролер,Aktivera denna styrenhet,Bu denetleyiciyi etkinleştirin,Увімкніть цей контролер, Open Main Menu,CNTRLMNU_OPEN_MAIN,,,,Otevřít hlavní menu,Åbn hovedmenuen,Hauptmenü öffnen,,Malfermi ĉefan menuon,Abrir el menú principal,,Avaa päävalikko,Ouvrir le menu principal,Otvori glavni izbornik,Főmenü megnyitása,Apri il menu principale,メインメニューを開く,메인 메뉴 열기,Hoofdmenu openen,Åpne hovedmenyen,Otwórz meny główne,Abrir menu principal,,Deschideți meniul principal,Открыть главное меню,Отворите главни мени,Öppna huvudmenyn,Ana Menüyü Aç,Відкрити головне меню, ,,New content,,,,,,,,,,,,,,,,,,,,,,,,,,,, -Module replayer,MODMNU_REPLAYER,,,,Nastavení přehrávače modulů,Modulafspiller,Modul-Spieler,,Legilo de moduloj,Reproductor de módulos,,,Lecteur de module,,,Module replayer,,,Module replayer,Modulavspiller,,Reprodutor de módulos,,Redare a modulelor,Модуль-повторитель,,Modulåterspelare,,Module replayer, \ No newline at end of file +Module replayer,MODMNU_REPLAYER,,,,Nastavení přehrávače modulů,Modulafspiller,Modul-Spieler,,Legilo de moduloj,Reproductor de módulos,,,Lecteur de module,Ponavljač modula,,Module replayer,モジュール リプレイヤー,,Module replayer,Modulavspiller,,Reprodutor de módulos,,Redare a modulelor,Модуль-повторитель,,Modulåterspelare,,Module replayer, \ No newline at end of file diff --git a/wadsrc/static/language.csv b/wadsrc/static/language.csv index eaa712791..4661e4598 100644 --- a/wadsrc/static/language.csv +++ b/wadsrc/static/language.csv @@ -1911,7 +1911,7 @@ armură.",Игрока %o обслюнявила бронированная дв %o was hit by %k's propulsor.,OB_MPP_SPLASH,,,,%o byl@[ao_cs] zasažen@[ao_cs] propulzorem hráčem %k.,%o blev ramt af %k's propulsor.,%o wurde von %ks Propeller getroffen,,%o estas trafita de la propulsilo de %k.,%o fue impactad@[ao_esp] por el propulsor de %k.,,%k osui %o parkaan työntimellään.,%o à été frappé@[e_fr] par le propulseur de %k.,,%o elérte %k elhárítóját.,%o è stato colpito dal propulsore di %k.,%o に %k のロケットゾーチャーがとどいた。,%o 은(는) %k 의 저치 추진기의 방사 능력을 우습게 봤습니다.,%o werd geraakt door %k's propulsor.,%o ble truffet av %k's propulsor.,%o został@[ao_pl] trafion@[adj_pl] pędnikiem %k.,%o foi atingid@[ao_ptb] pelo propulsor de %k.,,%o a fost învins de acceleratorul lui %k.,Игрок %o подстрелен из ускорителя зорча %k.,%o је ударен %k погоном.,%o blev träffad av %ks propulsor.,"%o, %k tarafından yenildi.",%k врази@[adj_1_ua] %o з прискореного зорчера. %o was phase zorched by %k.,OB_MPPHASEZORCH,,,,%o byl@[ao_cs] bzukr-vyfázován@[ao_cs] hráčem %k.,%o blev fasezorched af %k.,%o wurde von %k wegsynchronisiert,,%o estas fluktuantzorĉita de %k.,%o fue electrizad@[ao_esp] en fase por %k.,,%k vaiheiszorchasi %o paran.,%o à été phasé@[e_fr] par %k.,,%o fázis zorker áldozata lett %k által.,%o è stato phase-zorchato da %k.,%o は %k によってスベスベにされた。,%o 은(는) %k 의 전자 자쳐에 의해 쓰러졌습니다.,%o was fase zorched door %k.,%o ble fasebrent av %k.,%o został@[ao_pl] został sfazowan@[adj_pl] przez %k.,%o foi atingid@[ao_ptb] pelo zorcher fásico por %k.,,%o a fost înfrânt de zorcherul fazat al lui %k.,Игрок %o получил заряд из фазерного зорчера %k.,%o је фазно торчован %k.,%o blev faszorchad av %k.,"%o, %k tarafından yenildi.",%k фазорчну@[adj_1_ua] %o. %o fell prey to %k's LAZ device.,OB_MPLAZ_BOOM,,,,%o padl@[ao_cs] velkodosahovému bzukru hráče %k.,%o blev offer for %k's LAZ-enhed.,%o fiel %ks Flächenzorcher zum Opfer,,%o iĝis predo de la LAZ-aparato de %k.,%o cayó pres@[ao_esp] ante el dispositivo LAZ de %k.,,%o lankesi pelaajan %k SAZ-laitteen uhriksi.,%o est devenu@[e_fr] la proie du ZZL de %k.,,%o prédául lett ejtve %k LAZ készülékével.,%o è stato preda del dispositivo LAZ di %k.,%o は %k のLAZデバイスのえじきになった。,%k 이(가) LAZ 장치를 들기 전에 %o 은(는) 도망쳐야 했습니다.,%o viel ten prooi aan %k's LAZ apparaat.,%o ble offer for %k's LAZ-enhet.,%o stał@[ao_pl] się ofiarą urządzenia LAZ %k.,%o foi vítima do dispositivo LAZ de %k.,,%o a căzut pradă dispozitivului LAZ al lui %k.,Игрок %o склонился перед «ЗБР» игрока %k.,%o је постао жртва %k ЛАЗ уређаја.,%o föll offer för %ks LAZ-enhet.,"%o, %k tarafından lazzlandı.",%o па@[adj_1_ua] жертвою LAZ девайсу %k. -%o was lazzed by %k.,OB_MPLAZ_SPLASH,,,,%o byl@[ao_cs] odbzukrován hráčem %k.,%o blev lazzed af %k.,%o wurde von %k weggebeamt.,,%o estas LAZ-ita de %k.,%o fue LAZeado por %k.,,%k sazzasi pelaajaan %o.,%o à été pris@[e_fr] par le ZZL de %k.,,%o el lett lazzázva %k által.,%o è stato lazzato da %k.,%o は %k にとかされた。,%o 은(는) %k 의 LAZ 장치 범위를 벗어날 수 없었습니다.,%o werd gelazed door %k.,%o ble lazzed av %k.,%o został@[ao_pl] zLAZowan@[adj_pl] przez %k.,%o foi LAZead@[ao_ptb] por %k.,,%o a fost stropit de dispozitivul LAZ al lui %k.,Игрок %o получил заряд из «ЗБР» игрока %k.,%o је ЛАЗ-овао %k.,%o blev lazzad av %k.,"%o, %k tarafından lazzlandı.",%k LAZну@[adj_1_ua] %o. +%o was lazzed by %k.,OB_MPBFG_SPLASH,,chex,,%o byl@[ao_cs] odbzukrován hráčem %k.,%o blev lazzed af %k.,%o wurde von %k weggebeamt.,,%o estas LAZ-ita de %k.,%o fue LAZeado por %k.,,%k sazzasi pelaajaan %o.,%o à été pris@[e_fr] par le ZZL de %k.,,%o el lett lazzázva %k által.,%o è stato lazzato da %k.,%o は %k にとかされた。,%o 은(는) %k 의 LAZ 장치 범위를 벗어날 수 없었습니다.,%o werd gelazed door %k.,%o ble lazzed av %k.,%o został@[ao_pl] zLAZowan@[adj_pl] przez %k.,%o foi LAZead@[ao_ptb] por %k.,,%o a fost stropit de dispozitivul LAZ al lui %k.,Игрок %o получил заряд из «ЗБР» игрока %k.,%o је ЛАЗ-овао %k.,%o blev lazzad av %k.,"%o, %k tarafından lazzlandı.",%k LAZну@[adj_1_ua] %o. ,,Miscellaneous,,,,,,,,,,,,,,,,,,,,,,,,,,, E1M1: Landing Zone,CHUSTR_E1M1,,,,E1M1: Přistávací zóna,E1M1: Landingszone,E1M1: Landezone,,E1M1: Surterejo,E1M1: Zona de Aterrizaje,,E1M1: Laskeutumisalue,E1M1: La piste d'atterissage,,E1M1: Leszállópálya,E1M1: Zona di Atterraggio,E1M1: ちゃくりく ちてん,E1M1: 착륙 지점,E1M1: Landingszone,E1M1: Landingssone,E1M1: Strefa Lądowania,E1M1: Zona de Pouso,E1M1: Zona de Aterragem,E1M1: Pista de Aterizare,E1M1: Зона приземления,Е1М1: Зона слетања,E1M1: Landningszon,E1M1: İniş Bölgesi,E1M1: Зона висадки E1M2: Storage Facility,CHUSTR_E1M2,,,,E1M2: Skladiště,E1M2: Opbevaringsanlæg,E1M2: Lagerhalle,,E1M2: Stokejo,E1M2: Instalación de Almacenamiento,,E1M2: Varastolaitos,E1M2: Le centre de stockage,,E1M2: Raktárépület,E1M2: Struttura di Immagazzinamento,E1M2: ほかん しせつ,E1M2: 저장 시설,E1M2: Opslagfaciliteit,E1M2: Lagringsanlegg,E1M2: Magazyn,E1M2: Depósito,E1M2: Armazém,E1M2: Depozitul,E1M2: Хранилище,Е1М2: Складиште,E1M2: Förvaringsanläggning,E1M2: Depolama Tesisi,E1M2: Сховище @@ -3415,4 +3415,5 @@ Restart level on Death,MISCMNU_RESTARTONDEATH,Disables autoloading save on death Pistol Start,GMPLYMNU_PISTOLSTART,Resets inventory on every map,,,Začít jen s pistolí,Start med pistol,Pistolenstart,,Komenci kun pistolo,,,,Démarrage du pistolet,,,Avvio pistola,ピストルスタート,,Start met pistool,Start med pistol,Start z pistoletem,Iniciar com a pistola,,,Пистолет в начале,,Starta med pistol,Tabanca ile başlayın, Allow creation of zombie players,CMPTMNU_VOODOOZOMBIES,,,,Povolit zombie hráče,,Erlaube Zombieplayer,,Permesi kreadon de zombiaj ludantoj,,,,,,,,ゾンビプレイヤーの生成許可,,,,Pozwól na tworzenie graczy-zombie,Permitir criação de jogadores zumbi,,,Разрешить создание игроков-зомби,,,, ignore floor z when teleporting,CMPTMNU_FDTELEPORT,,,,Při teleportu ignorovat výšku podlahy,,Ignoriere Fußbodenhöhe bem Teleportieren,,Ignori altecon de planko dum teleportado,,,,,,,,テレポート時にfloor z値を無視する,,,,Ignoruj wysokość podłogi podczas teleportacji,Ignorar altura do chão ao teletransportar,,,игнорирование диагонали пола (Z) при телепортации,,,, -Forced-Perspective,OPTVAL_ANAMORPHIC,"Hardware Sprite Clipping mode that gives the illusion of a sprite being in a different position than it really is, allowing it to be rendered under the floor despite clipping",,,,,Erzwungene Perspektive,,,,,,,,,,,,,,,,,,Перспективный (анаморфотный),,,, \ No newline at end of file +Forced-Perspective,OPTVAL_ANAMORPHIC,"Hardware Sprite Clipping mode that gives the illusion of a sprite being in a different position than it really is, allowing it to be rendered under the floor despite clipping",,,Vynucená perspektiva,,Erzwungene Perspektive,,Devigita perspektivo,,,,,,,,,,,,,Perspectiva forçada,,,Принудительно перспективный,,,, +Footstep Volume,SNDMENU_FOOTSTEPVOLUME,,,,Hlasitost kroků,,Schrittlautstärke,,,,,,,,,,,,,,,Volume dos passos,,,Громкость шагов,,,, \ No newline at end of file diff --git a/wadsrc_extra/static/language.csv b/wadsrc_extra/static/language.csv index 2a62c0fcc..c2bd82f36 100644 --- a/wadsrc_extra/static/language.csv +++ b/wadsrc_extra/static/language.csv @@ -10701,8 +10701,8 @@ Where's the illegal tap?,TXT_RPLY2_SCRIPT02_D98540_WHERE,〃 (〃),,,Kde je nele どれをイジるかまでは知らん。 配電機はここの下水処理場にある。",그게 어딨는지 말해주지. 왜 그 동력선에 손을 대려고 하는지는 모르겠지마는. 저 앞 하수도 안에 있다네.,"Ik zal je vertellen waar hij is, maar ik weet niet met wie je met de koppeling zult knoeien. Het is hier in de rioolwaterzuiveringsinstallatie.","Jeg skal si deg hvor den er, men jeg vet ikke hvem sin kobling du skal tukle med. Den er her i kloakkanlegget.","Powiem ci gdzie jest, ale nie wiem czyj to odbierak, przy którym będziesz majstrować. Jest w oczyszczalni ścieków.","Vou te dizer onde está, mas não sei em qual ligação você vai acabar mexendo. Fica bem aqui na usina de tratamento de esgoto.",,"Îți voi spune unde este, dar nu știu de care cuplaj te vei lega. Este chiar aici, în sistemul de canalizare.","Я скажу тебе, где она, но не знаю, которая тебе нужна. Она прямо здесь, в очистной системе.",,"Jag ska berätta var den är, men jag vet inte vems koppling du kommer att mixtra med. Den finns här i reningsverket.","Nerede olduğunu söyleyeceğim, ama kimin bağlantılarını kurcalayacağınızı bilmiyorum. Tam burada, kanalizasyon tesisinde." Thanks,TXT_RPLY0_SCRIPT02_D100056_THANK,〃 (〃),,,Díky.,Tak,Danke,,Dankon.,Gracias.,,Kiitos,Merci.,,Kösz.,Grazie,ありがとう。,그렇군요.,Bedankt,Takk skal du ha.,Dzięki,Obrigado,,Mulțumesc,Спасибо.,,Tack,Teşekkürler. -That's right here in the sewage plant. But it's the Front's coupling. Whoever told you that it was the Order's was wrong.,TXT_DLG_SCRIPT02_D101572_THATS,〃 (〃),,,"Síť je přímo tady, v čističce. Ale je to spojka Fronty. Kdo ti řekl, že je Řádu, se mýlil.","Det er lige her i kloakanlægget. Men det er Fronts kobling. Den, der fortalte dig, at det var Ordenens, tog fejl.","Genau hier, in der Kläranlage. Aber sie gehört der Front. Wer auch immer dir gesagt hat, sie gehöre dem Orden, hat gelogen.",,"Ĝi estas ĉi tie, en la kloakpurigejo, sed ĝi estas la kuplado de la Fronto. Tiu ajn, kiu diris, ke ĝi estas de La Ordeno, eraris.","Está justo aquí en la planta de aguas residuales, pero es el acoplamiento del Frente. Quien te haya dicho que era de La Orden se ha equivocado. -","Está justo aquí en la planta de aguas residuales, pero es el acoplamiento del Frente. Quien te haya dicho que era de La Orden te dijo mal. +That's right here in the sewage plant. But it's the Front's coupling. Whoever told you that it was the Order's was wrong.,TXT_DLG_SCRIPT02_D101572_THATS,〃 (〃),,,"Síť je přímo tady, v čističce. Ale je to spojka Fronty. Kdo ti řekl, že je Řádu, se mýlil.","Det er lige her i kloakanlægget. Men det er Fronts kobling. Den, der fortalte dig, at det var Ordenens, tog fejl.","Genau hier, in der Kläranlage. Aber sie gehört der Front. Wer auch immer dir gesagt hat, sie gehöre dem Orden, hat gelogen.",,"Ĝi estas ĉi tie, en la kloakpurigejo, sed ĝi estas la kuplado de la Fronto. Kiu diris, ke ĝi estas de La Ordeno, tiu ajn eraris.","Está justo aquí en la planta de aguas residuales, aunque es el acoplamiento del Frente. Quien te haya dicho que era de La Orden se ha equivocado. +","Está justo aquí en la planta de aguas residuales, aunque es el acoplamiento del Frente. Quien te haya dicho que era de La Orden te dijo mal. ","Se on täällä jätelaitoksella. Mutta se on Rintaman kytkentä. Kuka sinulle kertoikaan sen kuuluvan Veljeskunnalle, oli väärässä.","Il se trouve ici dans le traitement des égouts, mais c'est le coupleur du Front . Celui qui vous a dit qu'il appartient à l'Ordre se plante.",,"Igen, jól hallottad, a szennyvíz tisztítóban. Ez azonban a Front kapcsolója. Akárki mondta, hogy a Rendé, hazudott neked.",È proprio qui nell'impianto fognario. Ma è il giunto del Fronte. Chiunque ti abbia detto che fosse il giunto dell'Ordine si sbagliava.,"正にここの下水処理場にあるさ。 だがそれはフロントにも繋いでいる。 そいつがオーダーの所有物と言われてたが、 @@ -12900,10 +12900,10 @@ What an up guy.,TXT_BBSUB_SCRIPT05_D4548_THEOR,MAP05: Prison Guard.,,,Takový ve Great. Now we're shopping for the Rat King.,TXT_BBSUB_SCRIPT06_D3032_BRING,〃,,,"Super, teď máme nakupovat pro Krysího krále.",Alle er så trængende. Nu skal vi købe ind til rottekongen.,"Klasse, jetzt machen wir die Arbeit für den Rattenkönig.",,,Genial. Ahora vamos de compras para el Rey de las Ratas.,,"Loistavaa, hoidamme nyt Rottakuninkaan ostoksia.","Parfait, maintenant on fait du shopping pour le roi des rats.",,Kiváló. A Patkány Király bevásárlói lettünk.,Grandioso. Adesso stiamo facendo shopping con il re dei ratti.,素敵ね。私達がラットキングのために買い物とか。,끝내준다. 이제 시궁쥐 왕의 심부름도 해야 한다니.,Geweldig. Nu zijn we aan het winkelen voor de rattenkoning.,Flott. Nå handler vi til Rottekongen.,Świetnie. Teraz robimy zakupy dla Króla Szczurów.,Que beleza. Agora estamos fazendo comprinhas pro Rato-Rei.,,Grozav. Acum facem cumpărături pentru Regele Șobolanilor.,Классно. Мы идём за покупками для Крысиного короля.,,Toppen. Nu ska vi shoppa för råttkungen.,Harika. Şimdi de Fare Kral için alışveriş yapıyoruz. "I bet this guy smells really bad, too.",TXT_BBSUB_SCRIPT06_D4548_OPENT,〃,,,"Hádám, že tenhle chlápek taky pěkně smrdí.","Jeg vil vædde med, at han også lugter rigtig dårligt.","Ich wette, dieser Kerl riecht auch übel.",,,"Apuesto a que este tipo huele muy mal, también.",,"Lyön vetoa, että tämä tyyppi myös haisee tosi pahalta.","Je parie que ce type sent salement mauvais, aussi.",,"Le merném fogadni, hogy ez a pacák is büdös.",Scommetto che questo tizio ha pure un cattivo odore.,この男も酷い悪臭がすると賭けるわ。,얘도 분명 냄새 하나는 죽여줄 거야.,Ik durf te wedden dat deze kerel ook heel erg stinkt.,Jeg vedder på at denne fyren også lukter fælt.,"Założę się, że ten facet też bardzo śmierdzi.",Aposto que esse cara fede pra caramba também.,,Pun pariu că tipul ăsta mai și pute.,"Уверена, этот парень воняет особенно ужасно.",,Jag slår vad om att den här killen luktar riktigt illa också.,Eminim bu adam da çok kötü kokuyordur. More sewers... Great. Wonder what lives down there.,TXT_BBSUB_SCRIPT06_D9096_YOUHA,〃,,,"Další stoky... skvělý. Zajímalo by mě, co tam dole žije.",Flere kloakker... Fedt. Gad vide hvad der bor dernede.,"Mehr Kanäle, toll... Ich frage mich, was da unten lebt.",,,Más alcantarillas... Genial. Me pregunto qué vivirá ahí abajo.,,Lisää viemäreitä... Mahtavaa. Kukakohan elää täällä alhaalla.,Plus d'égouts.. Youpi. Je me demande qui vit là dedans.,,Még több kanális... kiváló. Mi lakhat odalent?,Altre fogne... fantastico. Mi domando cosa vive qua giù.,更なる下水道...ヤッバ。下に何が住んでるのか不思議に思うわ。,또 하수도라... 끝내준다. 저 아래에 또 뭐가 살고 있을까?,Meer riolering.... Geweldig. Ik vraag me af wat daar beneden leeft.,Mer kloakk... Flott. Lurer på hva som bor der nede.,Więcej kanałów... Świetnie. Ciekawe co tam mieszka.,Mais esgotos... Que legal. O que será que vive lá embaixo?,,Mai multe canale... Grozav. Mă întreb ce-o mai trăi jos aici.,"Снова канализация... Замечательно. Интересно, кого мы там встретим?",,Mer kloaker... Toppen. Undrar vad som bor där nere.,Daha fazla kanalizasyon. Harika. Acaba orada ne yaşıyor? -Dead end here. We'd better keep looking.,TXT_BBSUB_SCRIPT07_D6064_PROGR,MAP07: Computer room.,,,Tudy cesta nevede. Měli bychom se podívat dál.,Det er en blindgyde her. Vi må hellere lede videre.,Sackgasse. Wir sollten es woanders versuchen.,,,Un callejón sin salida. Deberíamos seguir buscando.,,Umpikuja tässä. Parasta jatkaa etsintää.,"Une impasse. Bon, on continue de chercher.",,Zsákutca. Folytatnunk kell a keresést.,Qui c'è un vicolo cieco. Meglio continuare a guardare.,行き止まりだ。私達はまだこの景色を楽しめるわ。,여기가 아닌가 봐. 다른 곳을 찾아봐야겠어.,Doodlopend hier. We kunnen maar beter blijven zoeken.,Blindvei her. Vi får lete videre.,Tu jest ślepy zaułek. Lepiej szukajmy dalej.,Sem saída aqui. Melhor seguirmos procurando.,,Capăt de linie. Mai bine ne mai uităm împrejur.,Тупик. Давай продолжать поиски.,,Det är en återvändsgränd här. Det är bäst att fortsätta leta.,Burası çıkmaz sokak. Aramaya devam etsek iyi olur. +Dead end here. We'd better keep looking.,TXT_BBSUB_SCRIPT07_D6064_PROGR,MAP07: Computer room.,,,Tudy cesta nevede. Měli bychom se podívat dál.,Det er en blindgyde her. Vi må hellere lede videre.,Sackgasse. Wir sollten es woanders versuchen.,,,Un camino sin salida. Deberíamos seguir buscando.,,Umpikuja tässä. Parasta jatkaa etsintää.,"Une impasse. Bon, on continue de chercher.",,Zsákutca. Folytatnunk kell a keresést.,Qui c'è un vicolo cieco. Meglio continuare a guardare.,行き止まりだ。私達はまだこの景色を楽しめるわ。,여기가 아닌가 봐. 다른 곳을 찾아봐야겠어.,Doodlopend hier. We kunnen maar beter blijven zoeken.,Blindvei her. Vi får lete videre.,Tu jest ślepy zaułek. Lepiej szukajmy dalej.,Sem saída aqui. Melhor seguirmos procurando.,,Capăt de linie. Mai bine ne mai uităm împrejur.,Тупик. Давай продолжать поиски.,,Det är en återvändsgränd här. Det är bäst att fortsätta leta.,Burası çıkmaz sokak. Aramaya devam etsek iyi olur. "Onward, my champion. Let's make Mr. Ugly twist and shout. ",TXT_BBSUB_SCRIPT10_D10612_YOUHA,MAP10: Macil (Possible reference to a song of The Beatles).,,,"Kupředu, můj šampióne. Pojďme pana Ošklivu hezky nakopat.","Fremad, min mester. Lad os få hr. Grimme til at vride sig og skrige. -",Und weiter gehts. Lass die Hackfresse zittern!,,,"Adelante, mi campeón. Hagamos al Sr. Feo retorcerse y gritar.",,"Eteenpäin, sotaurhoni. Pannaan Herra Rumilus vääntelehtimään ja huutamaan.",Allons-y mon champion. Allons tordre de douleur Monsieur Sale-geule.,,Gyerünk bajnokom. Ne várakoztassuk meg Ocsmány urat.,"Vai avanti, mio campione. Facciamo agitare e urlare il signor Brutto.",進み出よ、わがチャンピオン。ミスター生塵を捻りつぶしてやれ。,"어서 가자, 나의 영웅. 그 못생긴 녀석에게 본때를 보여주자고.","Voorwaarts, mijn kampioen. Laten we Mr Lelijk laten draaien en schreeuwen.","Fremad, min mester. La oss få herr Stygg til å vri seg og rope.","Naprzód, mój mistrzu. Sprawmy, by Pan Brzydki skręcał się i krzyczał. +",Und weiter gehts. Lass die Hackfresse zittern!,,,"Adelante, campeón. Hagamos que el Sr. Feo se retuerza y grite.",,"Eteenpäin, sotaurhoni. Pannaan Herra Rumilus vääntelehtimään ja huutamaan.",Allons-y mon champion. Allons tordre de douleur Monsieur Sale-geule.,,Gyerünk bajnokom. Ne várakoztassuk meg Ocsmány urat.,"Vai avanti, mio campione. Facciamo agitare e urlare il signor Brutto.",進み出よ、わがチャンピオン。ミスター生塵を捻りつぶしてやれ。,"어서 가자, 나의 영웅. 그 못생긴 녀석에게 본때를 보여주자고.","Voorwaarts, mijn kampioen. Laten we Mr Lelijk laten draaien en schreeuwen.","Fremad, min mester. La oss få herr Stygg til å vri seg og rope.","Naprzód, mój mistrzu. Sprawmy, by Pan Brzydki skręcał się i krzyczał. ","Vai em frente, meu campeão. Vamos fazer o Sr. Feioso soltar a franga.",,"Drept în față, campionul meu. Să-l facem pe dl. Urât să țipe.","Вперёд, мой защитник. Заставим Г-на Урода сплясать и спеть.",,"Framåt, min mästare. Låt oss få herr Ful att vrida sig och skrika.","İleri, şampiyonum. Bay Çirkin'i döndürelim ve bağırtalım. " "Biomechanical? Well, that explains their seemingly endless supply of troops! And their bad attitude.