diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index 185160461..185d2a6de 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -283,6 +283,7 @@ Note: All fields default to false unless mentioned otherwise. For things with ACS specials (80-86 and 226), if arg0str is present and non-null, it will be used as the name of the script to execute, and arg0 will be ignored. + On dynamic lights, arg0str can be used to set a color by name, this will supersede all args which are normally used to define a color. } @@ -426,6 +427,9 @@ floor_reflect and ceiling_reflect. 1.28 28.01.2017 sector material colors. +1.29 04.02.2018 +arg0str in dynamic lights. + =============================================================================== EOF =============================================================================== diff --git a/src/g_level.cpp b/src/g_level.cpp index 17f76a67d..d6c712b24 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -648,7 +648,8 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill // If this is co-op, respawn any dead players now so they can // keep their inventory on the next map. - if ((multiplayer || level.flags2 & LEVEL2_ALLOWRESPAWN || sv_singleplayerrespawn) && !deathmatch && player->playerstate == PST_DEAD) + if ((multiplayer || level.flags2 & LEVEL2_ALLOWRESPAWN || sv_singleplayerrespawn || !!G_SkillProperty(SKILLP_PlayerRespawn)) + && !deathmatch && player->playerstate == PST_DEAD) { // Copied from the end of P_DeathThink [[ player->cls = NULL; // Force a new class if the player is using a random class diff --git a/src/gl/scene/gl_decal.cpp b/src/gl/scene/gl_decal.cpp index cf2310209..0f3bc7ffb 100644 --- a/src/gl/scene/gl_decal.cpp +++ b/src/gl/scene/gl_decal.cpp @@ -289,7 +289,7 @@ void GLWall::DrawDecal(DBaseDecal *decal) // Note: This should be replaced with proper shader based lighting. double x, y; decal->GetXY(seg->sidedef, x, y); - gl_SetDynSpriteLight(NULL, x, y, zpos, sub); + gl_SetDynSpriteLight(nullptr, x, y, zpos - decalheight * 0.5f, sub); } // alpha color only has an effect when using an alpha texture. diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index a0bcb4882..178b39ff7 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -842,7 +842,7 @@ sector_t * GLSceneDrawer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, f stereo3dMode.SetUp(); for (int eye_ix = 0; eye_ix < stereo3dMode.eye_count(); ++eye_ix) { - if (eye_ix > 0) + if (eye_ix > 0 && camera->player) SetFixedColormap(camera->player); // reiterate color map for each eye, so night vision goggles work in both eyes const s3d::EyePose * eye = stereo3dMode.getEyePose(eye_ix); eye->SetUp(); diff --git a/src/gl/scene/gl_spritelight.cpp b/src/gl/scene/gl_spritelight.cpp index 0b0660c39..9d017fb24 100644 --- a/src/gl/scene/gl_spritelight.cpp +++ b/src/gl/scene/gl_spritelight.cpp @@ -75,7 +75,7 @@ void gl_SetDynSpriteLight(AActor *self, float x, float y, float z, subsector_t * while (node) { light=node->lightsource; - if (light->visibletoplayer && !(light->flags2&MF2_DORMANT) && (!(light->lightflags&LF_DONTLIGHTSELF) || light->target != self) && !(light->lightflags&LF_DONTLIGHTACTORS)) + if (light->visibletoplayer && !(light->flags2&MF2_DORMANT) && (!(light->lightflags&LF_DONTLIGHTSELF) || light->target != self || !self) && !(light->lightflags&LF_DONTLIGHTACTORS)) { float dist; FVector3 L; diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 3e5358a3c..e36cecde7 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -835,12 +835,12 @@ inline int uallong(const int &foo) //============================================================================ // ACS variables with world scope -int32_t ACS_WorldVars[NUM_WORLDVARS]; -FWorldGlobalArray ACS_WorldArrays[NUM_WORLDVARS]; +static BoundsCheckingArray ACS_WorldVars; +static BoundsCheckingArray ACS_WorldArrays; // ACS variables with global scope -int32_t ACS_GlobalVars[NUM_GLOBALVARS]; -FWorldGlobalArray ACS_GlobalArrays[NUM_GLOBALVARS]; +BoundsCheckingArray ACS_GlobalVars; +BoundsCheckingArray ACS_GlobalArrays; //---------------------------------------------------------------------------- // @@ -851,21 +851,7 @@ FWorldGlobalArray ACS_GlobalArrays[NUM_GLOBALVARS]; // //---------------------------------------------------------------------------- -struct FACSStackMemory -{ - int32_t& operator[](const size_t index) - { - if (index >= STACK_SIZE) - { - I_Error("Corrupted stack pointer in ACS VM"); - } - - return buffer[index]; - } - -private: - int32_t buffer[STACK_SIZE]; -}; +using FACSStackMemory = BoundsCheckingArray; struct FACSStack { @@ -1470,10 +1456,10 @@ void ACSStringPool::UnlockForLevel(int lnum) void P_MarkWorldVarStrings() { - GlobalACSStrings.MarkStringArray(ACS_WorldVars, countof(ACS_WorldVars)); - for (size_t i = 0; i < countof(ACS_WorldArrays); ++i) + GlobalACSStrings.MarkStringArray(ACS_WorldVars.Pointer(), ACS_WorldVars.Size()); + for (size_t i = 0; i < ACS_WorldArrays.Size(); ++i) { - GlobalACSStrings.MarkStringMap(ACS_WorldArrays[i]); + GlobalACSStrings.MarkStringMap(ACS_WorldArrays.Pointer()[i]); } } @@ -1485,10 +1471,10 @@ void P_MarkWorldVarStrings() void P_MarkGlobalVarStrings() { - GlobalACSStrings.MarkStringArray(ACS_GlobalVars, countof(ACS_GlobalVars)); - for (size_t i = 0; i < countof(ACS_GlobalArrays); ++i) + GlobalACSStrings.MarkStringArray(ACS_GlobalVars.Pointer(), ACS_GlobalVars.Size()); + for (size_t i = 0; i < ACS_GlobalArrays.Size(); ++i) { - GlobalACSStrings.MarkStringMap(ACS_GlobalArrays[i]); + GlobalACSStrings.MarkStringMap(ACS_GlobalArrays.Pointer()[i]); } } @@ -1571,14 +1557,14 @@ void P_ClearACSVars(bool alsoglobal) { int i; - memset (ACS_WorldVars, 0, sizeof(ACS_WorldVars)); + ACS_WorldVars.Fill(0); for (i = 0; i < NUM_WORLDVARS; ++i) { ACS_WorldArrays[i].Clear (); } if (alsoglobal) { - memset (ACS_GlobalVars, 0, sizeof(ACS_GlobalVars)); + ACS_GlobalVars.Fill(0); for (i = 0; i < NUM_GLOBALVARS; ++i) { ACS_GlobalArrays[i].Clear (); @@ -1726,10 +1712,10 @@ static void ReadArrayVars (FSerializer &file, FWorldGlobalArray *vars, size_t co void P_ReadACSVars(FSerializer &arc) { - ReadVars (arc, ACS_WorldVars, NUM_WORLDVARS, "acsworldvars"); - ReadVars (arc, ACS_GlobalVars, NUM_GLOBALVARS, "acsglobalvars"); - ReadArrayVars (arc, ACS_WorldArrays, NUM_WORLDVARS, "acsworldarrays"); - ReadArrayVars (arc, ACS_GlobalArrays, NUM_GLOBALVARS, "acsglobalarrays"); + ReadVars (arc, ACS_WorldVars.Pointer(), NUM_WORLDVARS, "acsworldvars"); + ReadVars (arc, ACS_GlobalVars.Pointer(), NUM_GLOBALVARS, "acsglobalvars"); + ReadArrayVars (arc, ACS_WorldArrays.Pointer(), NUM_WORLDVARS, "acsworldarrays"); + ReadArrayVars (arc, ACS_GlobalArrays.Pointer(), NUM_GLOBALVARS, "acsglobalarrays"); GlobalACSStrings.ReadStrings(arc, "acsglobalstrings"); } @@ -1741,10 +1727,10 @@ void P_ReadACSVars(FSerializer &arc) void P_WriteACSVars(FSerializer &arc) { - WriteVars (arc, ACS_WorldVars, NUM_WORLDVARS, "acsworldvars"); - WriteVars (arc, ACS_GlobalVars, NUM_GLOBALVARS, "acsglobalvars"); - WriteArrayVars (arc, ACS_WorldArrays, NUM_WORLDVARS, "acsworldarrays"); - WriteArrayVars (arc, ACS_GlobalArrays, NUM_GLOBALVARS, "acsglobalarrays"); + WriteVars (arc, ACS_WorldVars.Pointer(), NUM_WORLDVARS, "acsworldvars"); + WriteVars (arc, ACS_GlobalVars.Pointer(), NUM_GLOBALVARS, "acsglobalvars"); + WriteArrayVars (arc, ACS_WorldArrays.Pointer(), NUM_WORLDVARS, "acsworldarrays"); + WriteArrayVars (arc, ACS_GlobalArrays.Pointer(), NUM_GLOBALVARS, "acsglobalarrays"); GlobalACSStrings.WriteStrings(arc, "acsglobalstrings"); } diff --git a/src/p_acs.h b/src/p_acs.h index 4f53ce1a3..7b0d18bd8 100644 --- a/src/p_acs.h +++ b/src/p_acs.h @@ -60,13 +60,32 @@ struct InitIntToZero }; typedef TMap, InitIntToZero> FWorldGlobalArray; -// ACS variables with world scope -extern int32_t ACS_WorldVars[NUM_WORLDVARS]; -extern FWorldGlobalArray ACS_WorldArrays[NUM_WORLDVARS]; +// Type of elements count is unsigned int instead of size_t to match ACSStringPool interface +template +struct BoundsCheckingArray +{ + T &operator[](const unsigned int index) + { + if (index >= N) + { + I_Error("Out of bounds memory access in ACS VM"); + } + + return buffer[index]; + } + + T *Pointer() { return buffer; } + unsigned int Size() const { return N; } + + void Fill(const T &value) { std::fill(std::begin(buffer), std::end(buffer), value); } + +private: + T buffer[N]; +}; // ACS variables with global scope -extern int32_t ACS_GlobalVars[NUM_GLOBALVARS]; -extern FWorldGlobalArray ACS_GlobalArrays[NUM_GLOBALVARS]; +extern BoundsCheckingArray ACS_GlobalVars; +extern BoundsCheckingArray ACS_GlobalArrays; #define LIBRARYID_MASK 0xFFF00000 #define LIBRARYID_SHIFT 20 @@ -359,7 +378,7 @@ public: ACSProfileInfo *GetFunctionProfileData(ScriptFunction *func) { return GetFunctionProfileData((int)(func - (ScriptFunction *)Functions)); } const char *LookupString (uint32_t index) const; - int32_t *MapVars[NUM_MAPVARS]; + BoundsCheckingArray MapVars; static FBehavior *StaticLoadModule (int lumpnum, FileReader * fr=NULL, int len=0); static void StaticLoadDefaultModules (); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index e0c9530d3..8e5e1d3a2 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -6101,6 +6101,9 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) if (mthing->arg0str != NAME_None) { PalEntry color = V_GetColor(nullptr, mthing->arg0str); + light->args[0] = color.r; + light->args[1] = color.g; + light->args[2] = color.b; } else if (light->lightflags & LF_SPOT) { diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index ff360f96b..b78b4e664 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -376,6 +376,14 @@ F481922F4881F74760F3C0437FD5EDD0 // map03 setlinespecial 1008 Door_Open 0 64 0 0 0 } +7ED9800213C00D6E7FB98652AB48B3DE // Ultimate Simplicity, map04 +{ + // Add missing map spots on easy and medium skills + // Demons will teleport into starting room making 100% kills possible + setthingskills 31 31 + setthingskills 32 31 +} + 1891E029994B023910CFE0B3209C3CDB // Ultimate Simplicity, map07 { // It is possible to get stuck on skill 0 or 1 when no shots have been fired @@ -386,6 +394,13 @@ F481922F4881F74760F3C0437FD5EDD0 // map03 setlinespecial 411 NoiseAlert 0 0 0 0 0 } +F0E6F30F57B0425F17E43600AA813E80 // Ultimate Simplicity, map11 +{ + // If door (sector #309) is closed it cannot be open again + // from one side potentially blocking level progression + clearlinespecial 2445 +} + 952CC8D03572E17BA550B01B366EFBB9 // Cheogsh map01 { // make the blue key spawn above the 3D floor diff --git a/wadsrc/static/mapinfo/common.txt b/wadsrc/static/mapinfo/common.txt index 1c1559b06..b79ecd5f4 100644 --- a/wadsrc/static/mapinfo/common.txt +++ b/wadsrc/static/mapinfo/common.txt @@ -118,7 +118,7 @@ DoomEdNums 9851 = SpotLightPulseAdditive 9852 = SpotLightFlickerAdditive 9853 = SectorSpotLightAdditive - 9854 = SpotLightFlickerRandomSubtractive + 9854 = SpotLightFlickerRandomAdditive 9860 = SpotLightSubtractive 9861 = SpotLightPulseSubtractive 9862 = SpotLightFlickerSubtractive diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index d43a59ce2..8ecce11cb 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -528,7 +528,7 @@ class PlayerPawn : Actor native if (level.time >= player.respawn_time || ((player.cmd.buttons & BT_USE) && player.Bot == NULL)) { player.cls = NULL; // Force a new class if the player is using a random class - player.playerstate = (multiplayer || (level.AllowRespawn) || sv_singleplayerrespawn)? PST_REBORN : PST_ENTER; + player.playerstate = (multiplayer || level.AllowRespawn || sv_singleplayerrespawn || G_SkillPropertyInt(SKILLP_PlayerRespawn)) ? PST_REBORN : PST_ENTER; if (special1 > 2) { special1 = 0;