From c7d0d7b1c25614230f9790d6768cc900a7f75b6e Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Sat, 9 Nov 2019 01:36:53 -0300 Subject: [PATCH 001/195] Flats as walls textures support, WIP, doesn't support animations yet --- src/doomdef.h | 4 ++ src/p_spec.c | 2 +- src/r_data.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/r_data.h | 12 ++++ 4 files changed, 166 insertions(+), 5 deletions(-) diff --git a/src/doomdef.h b/src/doomdef.h index 676c86e0d..1f28f7a80 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -620,8 +620,12 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; /// SRB2CB itself ported this from PrBoom+ #define NEWCLIP +/// PNG support #ifndef HAVE_PNG #define NO_PNG_LUMPS #endif +/// Render flats on walls +#define WALLFLATS + #endif // __DOOMDEF__ diff --git a/src/p_spec.c b/src/p_spec.c index 7fcdfd1e3..9ab50d947 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -464,7 +464,7 @@ static inline void P_FindAnimatedFlat(INT32 animnum) for (i = 0; i < numlevelflats; i++, foundflats++) { // is that levelflat from the flat anim sequence ? - if ((anims[animnum].istexture) && (foundflats->u.texture.num != 0 && foundflats->u.texture.num != -1) + if ((anims[animnum].istexture) && (foundflats->type == LEVELFLAT_TEXTURE) && ((UINT16)foundflats->u.texture.num >= startflatnum && (UINT16)foundflats->u.texture.num <= endflatnum)) { foundflats->u.texture.basenum = startflatnum; diff --git a/src/r_data.c b/src/r_data.c index fa5e5c43b..ac98aae77 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -456,6 +456,7 @@ static UINT8 *R_GenerateTexture(size_t texnum) texture_t *texture; texpatch_t *patch; patch_t *realpatch; + UINT8 *pdata; int x, x1, x2, i, width, height; size_t blocksize; column_t *patchcol; @@ -483,14 +484,17 @@ static UINT8 *R_GenerateTexture(size_t texnum) wadnum = patch->wad; lumpnum = patch->lump; lumplength = W_LumpLengthPwad(wadnum, lumpnum); - realpatch = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); // can't use W_CachePatchNumPwad because OpenGL + pdata = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); + realpatch = (patch_t *)pdata; #ifndef NO_PNG_LUMPS if (R_IsLumpPNG((UINT8 *)realpatch, lumplength)) - { - realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength, NULL, false); goto multipatch; - } +#endif + +#ifdef WALLFLATS + if (texture->type == TEXTURETYPE_FLAT) + goto multipatch; #endif // Check the patch for holes. @@ -582,6 +586,11 @@ static UINT8 *R_GenerateTexture(size_t texnum) #ifndef NO_PNG_LUMPS if (R_IsLumpPNG((UINT8 *)realpatch, lumplength)) realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength, NULL, false); + else +#endif +#ifdef WALLFLATS + if (texture->type == TEXTURETYPE_FLAT) + realpatch = R_FlatToPatch(pdata, texture->width, texture->height, 0, 0, NULL, false); #endif x1 = patch->originx; @@ -773,6 +782,39 @@ void R_LoadTextures(void) { numtextures += (UINT32)(texend - texstart); } + +#ifdef WALLFLATS + // Count flats + if (wadfiles[w]->type == RET_PK3) + { + texstart = W_CheckNumForFolderStartPK3("flats/", (UINT16)w, 0); + texend = W_CheckNumForFolderEndPK3("flats/", (UINT16)w, texstart); + } + else + { + texstart = W_CheckNumForNamePwad("F_START", (UINT16)w, 0); + texend = W_CheckNumForNamePwad("F_END", (UINT16)w, 0); + } + + if (texstart == INT16_MAX || texend == INT16_MAX) + continue; + + texstart++; // Do not count the first marker + + // PK3s have subfolders, so we can't just make a simple sum + if (wadfiles[w]->type == RET_PK3) + { + for (j = texstart; j < texend; j++) + { + if (!W_IsLumpFolder((UINT16)w, j)) // Check if lump is a folder; if not, then count it + numtextures++; + } + } + else // Add all the textures between F_START and F_END + { + numtextures += (UINT32)(texend - texstart); + } +#endif } // If no textures found by this point, bomb out @@ -866,6 +908,8 @@ void R_LoadTextures(void) texture->width = SHORT(patchlump->width); texture->height = SHORT(patchlump->height); } + + texture->type = TEXTURETYPE_SINGLEPATCH; texture->patchcount = 1; texture->holes = false; texture->flip = 0; @@ -884,6 +928,106 @@ void R_LoadTextures(void) textureheight[i] = texture->height << FRACBITS; i++; } + +#ifdef WALLFLATS + // Yes + if (wadfiles[w]->type == RET_PK3) + { + texstart = W_CheckNumForFolderStartPK3("flats/", (UINT16)w, 0); + texend = W_CheckNumForFolderEndPK3("flats/", (UINT16)w, texstart); + } + else + { + texstart = W_CheckNumForNamePwad("F_START", (UINT16)w, 0); + texend = W_CheckNumForNamePwad("F_END", (UINT16)w, 0); + } + + if (texstart == INT16_MAX || texend == INT16_MAX) + continue; + + texstart++; // Do not count the first marker + + // Work through each lump between the markers in the WAD. + for (j = 0; j < (texend - texstart); j++) + { + UINT8 *flatlump; + UINT16 wadnum = (UINT16)w; + lumpnum_t lumpnum = texstart + j; + size_t lumplength; + size_t flatsize = 0; + + if (wadfiles[w]->type == RET_PK3) + { + if (W_IsLumpFolder(wadnum, lumpnum)) // Check if lump is a folder + continue; // If it is then SKIP IT + } + + flatlump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); + lumplength = W_LumpLengthPwad(wadnum, lumpnum); + + switch (lumplength) + { + case 4194304: // 2048x2048 lump + flatsize = 2048; + break; + case 1048576: // 1024x1024 lump + flatsize = 1024; + break; + case 262144:// 512x512 lump + flatsize = 512; + break; + case 65536: // 256x256 lump + flatsize = 256; + break; + case 16384: // 128x128 lump + flatsize = 128; + break; + case 1024: // 32x32 lump + flatsize = 32; + break; + default: // 64x64 lump + flatsize = 64; + break; + } + + //CONS_Printf("\n\"%s\" is a flat, dimensions %d x %d",W_CheckNameForNumPwad((UINT16)w,texstart+j),flatsize,flatsize); + texture = textures[i] = Z_Calloc(sizeof(texture_t) + sizeof(texpatch_t), PU_STATIC, NULL); + + // Set texture properties. + M_Memcpy(texture->name, W_CheckNameForNumPwad(wadnum, lumpnum), sizeof(texture->name)); + +#ifndef NO_PNG_LUMPS + if (R_IsLumpPNG((UINT8 *)flatlump, lumplength)) + { + INT16 width, height; + R_PNGDimensions((UINT8 *)flatlump, &width, &height, lumplength); + texture->width = width; + texture->height = height; + } + else +#endif + texture->width = texture->height = flatsize; + + texture->type = TEXTURETYPE_FLAT; + texture->patchcount = 1; + texture->holes = false; + texture->flip = 0; + + // Allocate information for the texture's patches. + patch = &texture->patches[0]; + + patch->originx = patch->originy = 0; + patch->wad = (UINT16)w; + patch->lump = texstart + j; + patch->flip = 0; + + Z_Unlock(flatlump); + + texturewidth[i] = texture->width; + textureheight[i] = texture->height << FRACBITS; + i++; + } +#endif } } @@ -1195,6 +1339,7 @@ static texture_t *R_ParseTexture(boolean actuallyLoadTexture) M_Memcpy(resultTexture->name, newTextureName, 8); resultTexture->width = newTextureWidth; resultTexture->height = newTextureHeight; + resultTexture->type = TEXTURETYPE_COMPOSITE; } Z_Free(texturesToken); texturesToken = M_GetToken(NULL); diff --git a/src/r_data.h b/src/r_data.h index e71d45766..1d58a7815 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -45,6 +45,17 @@ typedef struct enum patchalphastyle style; } texpatch_t; +// texture type +enum +{ + TEXTURETYPE_UNKNOWN, + TEXTURETYPE_SINGLEPATCH, + TEXTURETYPE_COMPOSITE, +#ifdef WALLFLATS + TEXTURETYPE_FLAT, +#endif +}; + // A maptexturedef_t describes a rectangular texture, // which is composed of one or more mappatch_t structures // that arrange graphic patches. @@ -52,6 +63,7 @@ typedef struct { // Keep name for switch changing, etc. char name[8]; + UINT8 type; // TEXTURETYPE_ INT16 width, height; boolean holes; UINT8 flip; // 1 = flipx, 2 = flipy, 3 = both From 5e55a04f5f39bc3417bfde0303515b54b6dee26e Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Sat, 9 Nov 2019 01:50:47 -0300 Subject: [PATCH 002/195] minor tweaks --- src/r_data.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/r_data.c b/src/r_data.c index ac98aae77..e962d390c 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -456,6 +456,7 @@ static UINT8 *R_GenerateTexture(size_t texnum) texture_t *texture; texpatch_t *patch; patch_t *realpatch; + boolean dealloc = false; UINT8 *pdata; int x, x1, x2, i, width, height; size_t blocksize; @@ -583,6 +584,8 @@ static UINT8 *R_GenerateTexture(size_t texnum) lumpnum = patch->lump; lumplength = W_LumpLengthPwad(wadnum, lumpnum); realpatch = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); + dealloc = true; + #ifndef NO_PNG_LUMPS if (R_IsLumpPNG((UINT8 *)realpatch, lumplength)) realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength, NULL, false); @@ -591,7 +594,9 @@ static UINT8 *R_GenerateTexture(size_t texnum) #ifdef WALLFLATS if (texture->type == TEXTURETYPE_FLAT) realpatch = R_FlatToPatch(pdata, texture->width, texture->height, 0, 0, NULL, false); + else #endif + dealloc = false; x1 = patch->originx; width = SHORT(realpatch->width); @@ -628,6 +633,9 @@ static UINT8 *R_GenerateTexture(size_t texnum) colofs[x] = LONG((x * texture->height) + (texture->width*4)); ColumnDrawerPointer(patchcol, block + LONG(colofs[x]), patch, texture->height, height); } + + if (dealloc) + Z_Free(realpatch); } done: From 3f1681e0b3e0bb5536da875a558554c52923dea8 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Sat, 9 Nov 2019 02:09:10 -0300 Subject: [PATCH 003/195] fix uninitialized pdata* --- src/r_data.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/r_data.c b/src/r_data.c index e962d390c..d271e28f3 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -583,7 +583,8 @@ static UINT8 *R_GenerateTexture(size_t texnum) wadnum = patch->wad; lumpnum = patch->lump; lumplength = W_LumpLengthPwad(wadnum, lumpnum); - realpatch = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); + pdata = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); + realpatch = (patch_t *)pdata; dealloc = true; #ifndef NO_PNG_LUMPS From 3e7be585ca35a625bb426bef270f8bfcb1bc859c Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Sat, 9 Nov 2019 12:22:18 -0300 Subject: [PATCH 004/195] WORK!! --- src/r_data.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/r_data.c b/src/r_data.c index d271e28f3..38c711b7b 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -752,7 +752,6 @@ void R_LoadTextures(void) for (w = 0, numtextures = 0; w < numwadfiles; w++) { // Count the textures from TEXTURES lumps - texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0); while (texturesLumpPos != INT16_MAX) { @@ -761,7 +760,6 @@ void R_LoadTextures(void) } // Count single-patch textures - if (wadfiles[w]->type == RET_PK3) { texstart = W_CheckNumForFolderStartPK3("textures/", (UINT16)w, 0); @@ -774,7 +772,11 @@ void R_LoadTextures(void) } if (texstart == INT16_MAX || texend == INT16_MAX) +#ifdef WALLFLATS + goto countflats; +#else continue; +#endif texstart++; // Do not count the first marker @@ -793,6 +795,7 @@ void R_LoadTextures(void) } #ifdef WALLFLATS +countflats: // Count flats if (wadfiles[w]->type == RET_PK3) { @@ -802,7 +805,7 @@ void R_LoadTextures(void) else { texstart = W_CheckNumForNamePwad("F_START", (UINT16)w, 0); - texend = W_CheckNumForNamePwad("F_END", (UINT16)w, 0); + texend = W_CheckNumForNamePwad("F_END", (UINT16)w, texstart); } if (texstart == INT16_MAX || texend == INT16_MAX) @@ -873,7 +876,11 @@ void R_LoadTextures(void) } if (texstart == INT16_MAX || texend == INT16_MAX) +#ifdef WALLFLATS + goto checkflats; +#else continue; +#endif texstart++; // Do not count the first marker @@ -939,6 +946,7 @@ void R_LoadTextures(void) } #ifdef WALLFLATS +checkflats: // Yes if (wadfiles[w]->type == RET_PK3) { @@ -948,7 +956,7 @@ void R_LoadTextures(void) else { texstart = W_CheckNumForNamePwad("F_START", (UINT16)w, 0); - texend = W_CheckNumForNamePwad("F_END", (UINT16)w, 0); + texend = W_CheckNumForNamePwad("F_END", (UINT16)w, texstart); } if (texstart == INT16_MAX || texend == INT16_MAX) From 78a0048ee4f1555d2a43abbcd5d5a43404deda27 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Sat, 9 Nov 2019 13:23:38 -0300 Subject: [PATCH 005/195] Support animations --- src/p_spec.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/p_spec.c b/src/p_spec.c index 9ab50d947..7248d3ffb 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -138,6 +138,13 @@ static size_t maxanims; static animdef_t *animdefs = NULL; +// Increase the size of animdefs to make room for a new animation definition +static void GrowAnimDefs(void) +{ + maxanims++; + animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL); +} + // A prototype; here instead of p_spec.h, so they're "private" void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum); void P_ParseAnimationDefintion(SINT8 istexture); @@ -347,8 +354,7 @@ void P_ParseAnimationDefintion(SINT8 istexture) if (i == maxanims) { // Increase the size to make room for the new animation definition - maxanims++; - animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL); + GrowAnimDefs(); strncpy(animdefs[i].startname, animdefsToken, 9); } @@ -434,8 +440,17 @@ void P_ParseAnimationDefintion(SINT8 istexture) } animdefs[i].speed = animSpeed; Z_Free(animdefsToken); -} +#ifdef WALLFLATS + // hehe... uhh..... + if (!istexture) + { + GrowAnimDefs(); + M_Memcpy(&animdefs[maxanims-1], &animdefs[i], sizeof(animdef_t)); + animdefs[maxanims-1].istexture = 1; + } +#endif +} /** Checks for flats in levelflats that are part of a flat animation sequence * and sets them up for animation. From a9e3e0c00e8ad52b9d5cf98101a12a604a860062 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Sat, 9 Nov 2019 13:28:56 -0300 Subject: [PATCH 006/195] Support OpenGL --- src/hardware/hw_cache.c | 28 ++++++++++++++++++++-------- src/r_data.c | 6 ++++-- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index 0b47bc880..3b923d516 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -642,6 +642,7 @@ static void HWR_GenerateTexture(INT32 texnum, GLTexture_t *grtex) texture_t *texture; texpatch_t *patch; patch_t *realpatch; + UINT8 *pdata; INT32 i; boolean skyspecial = false; //poor hack for Legacy large skies.. @@ -690,19 +691,30 @@ static void HWR_GenerateTexture(INT32 texnum, GLTexture_t *grtex) // Composite the columns together. for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++) { -#ifndef NO_PNG_LUMPS + boolean dealloc = true; size_t lumplength = W_LumpLengthPwad(patch->wad, patch->lump); -#endif - realpatch = W_CacheLumpNumPwad(patch->wad, patch->lump, PU_CACHE); + pdata = W_CacheLumpNumPwad(patch->wad, patch->lump, PU_CACHE); + realpatch = (patch_t *)pdata; + #ifndef NO_PNG_LUMPS if (R_IsLumpPNG((UINT8 *)realpatch, lumplength)) realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength, NULL, false); + else #endif - HWR_DrawTexturePatchInCache(&grtex->mipmap, - blockwidth, blockheight, - texture, patch, - realpatch); - Z_Unlock(realpatch); +#ifdef WALLFLATS + if (texture->type == TEXTURETYPE_FLAT) + realpatch = R_FlatToPatch(pdata, texture->width, texture->height, 0, 0, NULL, false); + else +#endif + { + (void)lumplength; + dealloc = false; + } + + HWR_DrawTexturePatchInCache(&grtex->mipmap, blockwidth, blockheight, texture, patch, realpatch); + + if (dealloc) + Z_Unlock(realpatch); } //Hurdler: not efficient at all but I don't remember exactly how HWR_DrawPatchInCache works :( if (format2bpp[grtex->mipmap.grInfo.format]==4) diff --git a/src/r_data.c b/src/r_data.c index 38c711b7b..2674319e7 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -456,7 +456,6 @@ static UINT8 *R_GenerateTexture(size_t texnum) texture_t *texture; texpatch_t *patch; patch_t *realpatch; - boolean dealloc = false; UINT8 *pdata; int x, x1, x2, i, width, height; size_t blocksize; @@ -574,6 +573,7 @@ static UINT8 *R_GenerateTexture(size_t texnum) // Composite the columns together. for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++) { + boolean dealloc = true; static void (*ColumnDrawerPointer)(column_t *, UINT8 *, texpatch_t *, INT32, INT32); // Column drawing function pointer. if (patch->style != AST_COPY) ColumnDrawerPointer = (patch->flip & 2) ? R_DrawBlendFlippedColumnInCache : R_DrawBlendColumnInCache; @@ -585,7 +585,6 @@ static UINT8 *R_GenerateTexture(size_t texnum) lumplength = W_LumpLengthPwad(wadnum, lumpnum); pdata = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); realpatch = (patch_t *)pdata; - dealloc = true; #ifndef NO_PNG_LUMPS if (R_IsLumpPNG((UINT8 *)realpatch, lumplength)) @@ -597,7 +596,10 @@ static UINT8 *R_GenerateTexture(size_t texnum) realpatch = R_FlatToPatch(pdata, texture->width, texture->height, 0, 0, NULL, false); else #endif + { + (void)lumplength; dealloc = false; + } x1 = patch->originx; width = SHORT(realpatch->width); From 61164ea3109883492b3fa608e8329a255635f033 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Sat, 9 Nov 2019 14:09:20 -0300 Subject: [PATCH 007/195] Trying to make sense of chroma keying --- src/hardware/hw_cache.c | 40 ++++++++++++++++------------------------ src/hardware/hw_defs.h | 2 +- src/hardware/hw_glob.h | 1 - 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index 3b923d516..edb8a51a0 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -32,10 +32,6 @@ #include "../r_draw.h" #include "../p_setup.h" -//Hurdler: 25/04/2000: used for new colormap code in hardware mode -//static UINT8 *gr_colormap = NULL; // by default it must be NULL ! (because colormap tables are not initialized) -boolean firetranslucent = false; - // Values set after a call to HWR_ResizeBlock() static INT32 blocksize, blockwidth, blockheight; @@ -121,18 +117,16 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm texel = source[yfrac>>FRACBITS]; - if (firetranslucent && (transtables[(texel<<8)+0x40000]!=texel)) - alpha = 0x80; + //Hurdler: 25/04/2000: now support colormap in hardware mode + if (mipmap->colormap) + texel = mipmap->colormap[texel]; + + // transparent pixel + if (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX) + alpha = 0x00; else alpha = 0xff; - //Hurdler: not perfect, but better than holes - if (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX && (mipmap->flags & TF_CHROMAKEYED)) - texel = HWR_CHROMAKEY_EQUIVALENTCOLORINDEX; - //Hurdler: 25/04/2000: now support colormap in hardware mode - else if (mipmap->colormap) - texel = mipmap->colormap[texel]; - // hope compiler will get this switch out of the loops (dreams...) // gcc do it ! but vcc not ! (why don't use cygwin gcc for win32 ?) // Alam: SRB2 uses Mingw, HUGS @@ -235,18 +229,16 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block, texel = source[yfrac>>FRACBITS]; - if (firetranslucent && (transtables[(texel<<8)+0x40000]!=texel)) - alpha = 0x80; + //Hurdler: 25/04/2000: now support colormap in hardware mode + if (mipmap->colormap) + texel = mipmap->colormap[texel]; + + // transparent pixel + if (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX) + alpha = 0x00; else alpha = 0xff; - //Hurdler: not perfect, but better than holes - if (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX && (mipmap->flags & TF_CHROMAKEYED)) - texel = HWR_CHROMAKEY_EQUIVALENTCOLORINDEX; - //Hurdler: 25/04/2000: now support colormap in hardware mode - else if (mipmap->colormap) - texel = mipmap->colormap[texel]; - // hope compiler will get this switch out of the loops (dreams...) // gcc do it ! but vcc not ! (why don't use cygwin gcc for win32 ?) // Alam: SRB2 uses Mingw, HUGS @@ -612,7 +604,7 @@ static UINT8 *MakeBlock(GLMipmap_t *grMipmap) { UINT8 *block; INT32 bpp, i; - UINT16 bu16 = ((0x00 <<8) | HWR_CHROMAKEY_EQUIVALENTCOLORINDEX); + UINT16 bu16 = ((0x00 <<8) | HWR_PATCHES_CHROMAKEY_COLORINDEX); bpp = format2bpp[grMipmap->grInfo.format]; block = Z_Malloc(blocksize*bpp, PU_HWRCACHE, &(grMipmap->grInfo.data)); @@ -675,7 +667,7 @@ static void HWR_GenerateTexture(INT32 texnum, GLTexture_t *grtex) INT32 j; RGBA_t col; - col = V_GetColor(HWR_CHROMAKEY_EQUIVALENTCOLORINDEX); + col = V_GetColor(HWR_PATCHES_CHROMAKEY_COLORINDEX); for (j = 0; j < blockheight; j++) { for (i = 0; i < blockwidth; i++) diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index 5dcead77c..b8d420f68 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -42,7 +42,7 @@ typedef unsigned char FBOOLEAN; // byte value for paletted graphics, which represent the transparent color #define HWR_PATCHES_CHROMAKEY_COLORINDEX 255 -#define HWR_CHROMAKEY_EQUIVALENTCOLORINDEX 130 +//#define HWR_CHROMAKEY_EQUIVALENTCOLORINDEX 130 // the chroma key color shows on border sprites, set it to black #define HWR_PATCHES_CHROMAKEY_COLORVALUE (0x00000000) //RGBA format as in grSstWinOpen() diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index 72365013d..16bd97092 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -123,6 +123,5 @@ extern consvar_t cv_grrounddown; // on/off extern INT32 patchformat; extern INT32 textureformat; -extern boolean firetranslucent; #endif //_HW_GLOB_ From 243cbc02ec54502f91f09485dd4c751d09abcbfb Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Sat, 9 Nov 2019 17:53:05 -0300 Subject: [PATCH 008/195] Big Miss Steak --- src/r_plane.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/r_plane.c b/src/r_plane.c index 53b58c274..89a76aed2 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -1007,6 +1007,8 @@ void R_DrawSinglePlane(visplane_t *pl) R_CheckFlatLength(W_LumpLength(levelflat->u.flat.lumpnum)); // Raw flats always have dimensions that are powers-of-two numbers. ds_powersoftwo = true; + if (spanfunc == basespanfunc) + spanfunc = mmxspanfunc; break; default: switch (type) From 615547ddd17a6f3bcb777e6202073cd730210821 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Sat, 9 Nov 2019 19:32:06 -0300 Subject: [PATCH 009/195] Fix animated flats yet again --- src/p_spec.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/p_spec.c b/src/p_spec.c index 7248d3ffb..58fe5ef60 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -491,7 +491,8 @@ static inline void P_FindAnimatedFlat(INT32 animnum) atoi(sizeu1(i)), foundflats->name, foundflats->animseq, foundflats->numpics,foundflats->speed); } - else if (foundflats->u.flat.lumpnum >= startflatnum && foundflats->u.flat.lumpnum <= endflatnum) + else if ((!anims[animnum].istexture) && (foundflats->type == LEVELFLAT_FLAT) + && (foundflats->u.flat.lumpnum >= startflatnum && foundflats->u.flat.lumpnum <= endflatnum)) { foundflats->u.flat.baselumpnum = startflatnum; foundflats->animseq = foundflats->u.flat.lumpnum - startflatnum; @@ -5596,7 +5597,7 @@ void P_UpdateSpecials(void) if (foundflats->speed) // it is an animated flat { // update the levelflat texture number - if (foundflats->type == LEVELFLAT_TEXTURE) + if ((foundflats->type == LEVELFLAT_TEXTURE) && (foundflats->u.texture.basenum != -1)) foundflats->u.texture.num = foundflats->u.texture.basenum + ((leveltime/foundflats->speed + foundflats->animseq) % foundflats->numpics); // update the levelflat lump number else if ((foundflats->type == LEVELFLAT_FLAT) && (foundflats->u.flat.baselumpnum != LUMPERROR)) From d467d2b2295a9660631774b9edb29555cc5c30fe Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Sun, 10 Nov 2019 00:04:11 -0300 Subject: [PATCH 010/195] GIF recording --- src/hardware/hw_main.c | 4 ++-- src/m_anigif.c | 52 +++++++++++++++++++++++++++++++++++++++--- src/m_misc.c | 8 ++----- src/r_data.c | 3 +-- src/r_data.h | 2 ++ src/sdl/i_video.c | 5 ++-- src/v_video.c | 27 ++++++++++++++++++---- src/v_video.h | 12 ++++++++++ 8 files changed, 92 insertions(+), 21 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 7e0b369eb..f2c30107b 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -580,7 +580,7 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is if (nrPlaneVerts < 3) //not even a triangle ? return; - if (nrPlaneVerts > UINT16_MAX) // FIXME: exceeds plVerts size + if (nrPlaneVerts > INT16_MAX) // FIXME: exceeds plVerts size { CONS_Debug(DBG_RENDER, "polygon size of %d exceeds max value of %d vertices\n", nrPlaneVerts, UINT16_MAX); return; @@ -3171,7 +3171,7 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, if (nrPlaneVerts < 3) //not even a triangle ? return; - if (nrPlaneVerts > UINT16_MAX) // FIXME: exceeds plVerts size + if (nrPlaneVerts > INT16_MAX) // FIXME: exceeds plVerts size { CONS_Debug(DBG_RENDER, "polygon size of %s exceeds max value of %d vertices\n", sizeu1(nrPlaneVerts), UINT16_MAX); return; diff --git a/src/m_anigif.c b/src/m_anigif.c index 4e68819bc..f19679ef4 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -19,6 +19,10 @@ #include "v_video.h" #include "i_video.h" +#ifdef HWRENDER +#include "hardware/hw_main.h" +#endif + // GIFs are always little-endian #include "byteptr.h" @@ -452,6 +456,32 @@ const UINT8 gifframe_gchead[4] = {0x21,0xF9,0x04,0x04}; // GCE, bytes, packed by static UINT8 *gifframe_data = NULL; static size_t gifframe_size = 8192; +#ifdef HWRENDER +static void hwrconvert(void) +{ + UINT8 *linear = HWR_GetScreenshot(); + UINT8 *dest = screens[2]; + UINT8 r, g, b; + INT32 x, y; + size_t i = 0; + + InitColorLUT(); + + for (y = 0; y < vid.height; y++) + { + for (x = 0; x < vid.width; x++, i += 3) + { + r = (UINT8)linear[i]; + g = (UINT8)linear[i + 1]; + b = (UINT8)linear[i + 2]; + dest[(y * vid.width) + x] = colorlookup[r >> SHIFTCOLORBITS][g >> SHIFTCOLORBITS][b >> SHIFTCOLORBITS]; + } + } + + free(linear); +} +#endif + // // GIF_framewrite // writes a frame into the file. @@ -477,7 +507,12 @@ static void GIF_framewrite(void) GIF_optimizeregion(cur_screen, movie_screen, &blitx, &blity, &blitw, &blith); // blit to temp screen - I_ReadScreen(movie_screen); + if (rendermode == render_soft) + I_ReadScreen(movie_screen); +#ifdef HWRENDER + else if (rendermode == render_opengl) + hwrconvert(); +#endif } else { @@ -486,7 +521,18 @@ static void GIF_framewrite(void) blith = vid.height; if (gif_frames == 0) - I_ReadScreen(movie_screen); + { + if (rendermode == render_soft) + I_ReadScreen(movie_screen); +#ifdef HWRENDER + else if (rendermode == render_opengl) + { + hwrconvert(); + VID_BlitLinearScreen(screens[2], screens[0], vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.rowbytes); + } +#endif + } + movie_screen = screens[0]; } @@ -575,7 +621,7 @@ static void GIF_framewrite(void) // INT32 GIF_open(const char *filename) { -#ifdef HWRENDER +#if 0 if (rendermode != render_soft) { CONS_Alert(CONS_WARNING, M_GetText("GIFs cannot be taken in non-software modes!\n")); diff --git a/src/m_misc.c b/src/m_misc.c index c5e4fa21c..b2f5c5465 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -1119,12 +1119,8 @@ void M_StartMovie(void) switch (cv_moviemode.value) { case MM_GIF: - if (rendermode == render_soft) - { - moviemode = M_StartMovieGIF(pathname); - break; - } - /* FALLTHRU */ + moviemode = M_StartMovieGIF(pathname); + break; case MM_APNG: moviemode = M_StartMovieAPNG(pathname); break; diff --git a/src/r_data.c b/src/r_data.c index bd12eb248..c57535920 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -1162,7 +1162,6 @@ INT32 R_ColormapNumForName(char *name) // static double deltas[256][3], map[256][3]; -static UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b); static int RoundUp(double number); INT32 R_CreateColormap(char *p1, char *p2, char *p3) @@ -1342,7 +1341,7 @@ INT32 R_CreateColormap(char *p1, char *p2, char *p3) // Thanks to quake2 source! // utils3/qdata/images.c -static UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b) +UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b) { int dr, dg, db; int distortion, bestdistortion = 256 * 256 * 4, bestcolor = 0, i; diff --git a/src/r_data.h b/src/r_data.h index 5de51ccd4..614082fac 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -95,6 +95,8 @@ INT32 R_ColormapNumForName(char *name); INT32 R_CreateColormap(char *p1, char *p2, char *p3); const char *R_ColormapNameForNum(INT32 num); +UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b); + extern INT32 numtextures; #endif diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 77bf414cc..37beaefe6 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1292,6 +1292,7 @@ INT32 VID_SetMode(INT32 modeNum) //Impl_SetWindowName("SRB2 "VERSIONSTRING); SDLSetMode(vid.width, vid.height, USE_FULLSCREEN); + Impl_VideoSetupBuffer(); if (rendermode == render_soft) { @@ -1300,8 +1301,6 @@ INT32 VID_SetMode(INT32 modeNum) SDL_FreeSurface(bufSurface); bufSurface = NULL; } - - Impl_VideoSetupBuffer(); } return SDL_TRUE; @@ -1424,7 +1423,7 @@ static void Impl_VideoSetupSDLBuffer(void) static void Impl_VideoSetupBuffer(void) { // Set up game's software render buffer - if (rendermode == render_soft) + //if (rendermode == render_soft) { vid.rowbytes = vid.width * vid.bpp; vid.direct = NULL; diff --git a/src/v_video.c b/src/v_video.c index c3b29e157..0a57e22ac 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -2207,6 +2207,27 @@ Unoptimized version #endif } +// Taken from my videos-in-SRB2 project +// Generates a color look-up table +// which has up to 64 colors at each channel +// (see the defines in v_video.h) + +UINT8 colorlookup[CLUTSIZE][CLUTSIZE][CLUTSIZE]; + +void InitColorLUT(void) +{ + UINT8 r, g, b; + static boolean clutinit = false; + if (!clutinit) + { + for (r = 0; r < CLUTSIZE; r++) + for (g = 0; g < CLUTSIZE; g++) + for (b = 0; b < CLUTSIZE; b++) + colorlookup[r][g][b] = NearestColor(r << SHIFTCOLORBITS, g << SHIFTCOLORBITS, b << SHIFTCOLORBITS); + clutinit = true; + } +} + // V_Init // old software stuff, buffers are allocated at video mode setup // here we set the screens[x] pointers accordingly @@ -2218,13 +2239,9 @@ void V_Init(void) const INT32 screensize = vid.rowbytes * vid.height; LoadMapPalette(); - // hardware modes do not use screens[] pointers + for (i = 0; i < NUMSCREENS; i++) screens[i] = NULL; - if (rendermode != render_soft) - { - return; // be sure to cause a NULL read/write error so we detect it, in case of.. - } // start address of NUMSCREENS * width*height vidbuffers if (base) diff --git a/src/v_video.h b/src/v_video.h index 877a619b5..92c24946f 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -33,6 +33,18 @@ extern consvar_t cv_ticrate, cv_usegamma, cv_allcaps, cv_constextsize; // Allocates buffer screens, call before R_Init. void V_Init(void); +// Taken from my videos-in-SRB2 project +// Generates a color look-up table +// which has up to 64 colors at each channel + +#define COLORBITS 6 +#define SHIFTCOLORBITS (8-COLORBITS) +#define CLUTSIZE (1< Date: Mon, 11 Nov 2019 00:02:22 -0300 Subject: [PATCH 011/195] Recreate the CLUT when the palette changes --- src/v_video.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/v_video.c b/src/v_video.c index 0a57e22ac..eaaa7cd26 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -2218,13 +2218,15 @@ void InitColorLUT(void) { UINT8 r, g, b; static boolean clutinit = false; - if (!clutinit) + static RGBA_t *lastpalette = NULL; + if ((!clutinit) || (lastpalette != pLocalPalette)) { for (r = 0; r < CLUTSIZE; r++) for (g = 0; g < CLUTSIZE; g++) for (b = 0; b < CLUTSIZE; b++) colorlookup[r][g][b] = NearestColor(r << SHIFTCOLORBITS, g << SHIFTCOLORBITS, b << SHIFTCOLORBITS); clutinit = true; + lastpalette = pLocalPalette; } } From 6adb957f0f836349ee684d366d679505c9cfc0ec Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 4 Dec 2019 19:25:39 -0300 Subject: [PATCH 012/195] Slap colormap fades everywhere --- src/d_main.c | 16 ++++++++-- src/f_finale.c | 12 ++++---- src/f_finale.h | 7 ++++- src/f_wipe.c | 80 ++++++++++++++++++++++++++++++++++++++++---------- src/g_game.c | 9 +++--- src/g_game.h | 2 +- src/p_setup.c | 2 +- src/st_stuff.c | 5 ++-- src/st_stuff.h | 2 +- 9 files changed, 100 insertions(+), 35 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 5853fccf0..c26fbad0d 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -274,7 +274,10 @@ static void D_Display(void) && wipetypepre != UINT8_MAX) { F_WipeStartScreen(); - F_WipeColorFill(31); + // Check for Mega Genesis fade + wipestyleflags = WSF_FADEOUT; + if (F_TryColormapFade(31)) + wipetypepost = -1; // Don't run the fade below this one F_WipeEndScreen(); F_RunWipe(wipetypepre, gamestate != GS_TIMEATTACK && gamestate != GS_TITLESCREEN); } @@ -488,15 +491,24 @@ static void D_Display(void) if (rendermode != render_none) { F_WipeEndScreen(); + // Funny. if (WipeStageTitle && st_overlay) { lt_ticker--; lt_lasttic = lt_ticker; - ST_preLevelTitleCardDrawer(0, false); + ST_preLevelTitleCardDrawer(false); V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol); F_WipeStartScreen(); } + + // Check for Mega Genesis fade + if (F_ShouldColormapFade()) + { + wipestyleflags |= WSF_FADEIN; + wipestyleflags &= ~WSF_FADEOUT; + } + F_RunWipe(wipetypepost, gamestate != GS_TIMEATTACK && gamestate != GS_TITLESCREEN); } diff --git a/src/f_finale.c b/src/f_finale.c index 306dad4e9..c33cbc16b 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -910,8 +910,9 @@ void F_IntroDrawer(void) { if (rendermode != render_none) { + wipestyleflags = WSF_FADEOUT; F_WipeStartScreen(); - F_WipeColorFill(31); + F_TryColormapFade(31); F_WipeEndScreen(); F_RunWipe(99,true); } @@ -920,12 +921,11 @@ void F_IntroDrawer(void) } else if (intro_scenenum == 10) { - // The only fade to white in the entire damn game. - // (not true) if (rendermode != render_none) { + wipestyleflags = (WSF_FADEOUT|WSF_TOWHITE); F_WipeStartScreen(); - F_WipeColorFill(0); + F_TryColormapFade(0); F_WipeEndScreen(); F_RunWipe(99,true); } @@ -934,8 +934,9 @@ void F_IntroDrawer(void) { if (rendermode != render_none) { + wipestyleflags = WSF_FADEOUT; F_WipeStartScreen(); - F_WipeColorFill(31); + F_TryColormapFade(31); F_WipeEndScreen(); F_RunWipe(99,true); } @@ -970,6 +971,7 @@ void F_IntroDrawer(void) F_WipeStartScreen(); wipegamestate = -1; + wipestyleflags = WSF_CROSSFADE; animtimer = stoptimer = 0; } diff --git a/src/f_finale.h b/src/f_finale.h index 0002cb3cf..5c03518a1 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -146,7 +146,7 @@ extern boolean WipeStageTitle; typedef enum { WIPESTYLE_NORMAL, - WIPESTYLE_LEVEL + WIPESTYLE_COLORMAP } wipestyle_t; extern wipestyle_t wipestyle; @@ -159,6 +159,11 @@ typedef enum } wipestyleflags_t; extern wipestyleflags_t wipestyleflags; +// Even my function names are borderline +boolean F_ShouldColormapFade(void); +boolean F_TryColormapFade(UINT8 wipecolor); +void F_DecideWipeStyle(void); + #define FADECOLORMAPDIV 8 #define FADECOLORMAPROWS (256/FADECOLORMAPDIV) diff --git a/src/f_wipe.c b/src/f_wipe.c index b88b39ef0..ea52042a5 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -161,7 +161,7 @@ static fademask_t *F_GetFadeMask(UINT8 masknum, UINT8 scrnnum) { { // Determine pixel to use from fademask pcolor = &pMasterPalette[*lump++]; - if (wipestyle == WIPESTYLE_LEVEL) + if (wipestyle == WIPESTYLE_COLORMAP) *mask++ = pcolor->s.red / FADECOLORMAPDIV; else *mask++ = FixedDiv((pcolor->s.red+1)<>FRACBITS; @@ -191,7 +191,7 @@ void F_WipeStageTitle(void) { // draw level title if ((WipeStageTitle && st_overlay) - && (wipestyle == WIPESTYLE_LEVEL) + && (wipestyle == WIPESTYLE_COLORMAP) && !(mapheaderinfo[gamemap-1]->levelflags & LF_NOTITLECARD) && *mapheaderinfo[gamemap-1]->lvlttl != '\0') { @@ -282,7 +282,7 @@ static void F_DoWipe(fademask_t *fademask) relativepos += vid.width; } } - else if (*mask >= ((wipestyle == WIPESTYLE_LEVEL) ? FADECOLORMAPROWS : 10)) + else if (*mask >= ((wipestyle == WIPESTYLE_COLORMAP) ? FADECOLORMAPROWS : 10)) { // shortcut - memcpy target to work while (draw_linestogo--) @@ -293,7 +293,7 @@ static void F_DoWipe(fademask_t *fademask) } else { - if (wipestyle == WIPESTYLE_LEVEL) + if (wipestyle == WIPESTYLE_COLORMAP) { int nmask; UINT8 *fade = fadecolormap; @@ -321,7 +321,7 @@ static void F_DoWipe(fademask_t *fademask) e = e_base + relativepos; draw_rowstogo = draw_rowend - draw_rowstart; - if (wipestyle == WIPESTYLE_LEVEL) + if (wipestyle == WIPESTYLE_COLORMAP) { while (draw_rowstogo--) *w++ = transtbl[*e++]; @@ -382,6 +382,62 @@ void F_WipeEndScreen(void) #endif } +/** Verifies every condition for a colormapped fade. + */ +boolean F_ShouldColormapFade(void) +{ + if ((wipestyleflags & (WSF_FADEIN|WSF_FADEOUT)) // only if one of those wipestyleflags are actually set + && !(wipestyleflags & WSF_CROSSFADE)) // and if not crossfading + { + // World + return (gamestate == GS_LEVEL + || gamestate == GS_TITLESCREEN + // Finales + || gamestate == GS_CONTINUING + || gamestate == GS_CREDITS + || gamestate == GS_EVALUATION + || gamestate == GS_INTRO + || gamestate == GS_ENDING + // Menus + || gamestate == GS_TIMEATTACK); + } + return false; +} + +/** Decides what wipe style to use. + */ +void F_DecideWipeStyle(void) +{ + // Set default wipe style + wipestyle = WIPESTYLE_NORMAL; + + // Check for colormap wipe style + if (F_ShouldColormapFade()) + wipestyle = WIPESTYLE_COLORMAP; +} + +/** Attempt to run a colormap fade, + provided all the conditionals were properly met. + Returns true if so. + I demand you call F_RunWipe after this function. + */ +boolean F_TryColormapFade(UINT8 wipecolor) +{ + if (F_ShouldColormapFade()) + { +#ifdef HWRENDER + if (rendermode == render_opengl) + F_WipeColorFill(wipecolor); +#endif + return true; + } + else + { + F_WipeColorFill(wipecolor); + return false; + } +} + /** After setting up the screens you want to wipe, * calling this will do a 'typical' wipe. */ @@ -399,18 +455,10 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu) paldiv = FixedDiv(257<levelflags & LF_NOTITLECARD) @@ -1828,7 +1825,7 @@ void G_StartTitleCard(void) // // Run the title card before fading in to the level. // -void G_PreLevelTitleCard(tic_t ticker, boolean update) +void G_PreLevelTitleCard(void) { tic_t starttime = I_GetTime(); tic_t endtime = starttime + (PRELEVELTIME*NEWTICRATERATIO); @@ -1842,13 +1839,15 @@ void G_PreLevelTitleCard(tic_t ticker, boolean update) lasttime = nowtime; ST_runTitleCard(); - ST_preLevelTitleCardDrawer(ticker, update); + ST_preLevelTitleCardDrawer(true); if (moviemode) M_SaveFrame(); if (takescreenshot) // Only take screenshots after drawing. M_DoScreenShot(); } + if (!st_overlay) + wipestyleflags = WSF_CROSSFADE; } INT32 pausedelay = 0; diff --git a/src/g_game.h b/src/g_game.h index 0a575c099..b4898a68f 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -141,7 +141,7 @@ void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar, boolean SSSG, boolean FLS); void G_DoLoadLevel(boolean resetplayer); void G_StartTitleCard(void); -void G_PreLevelTitleCard(tic_t ticker, boolean update); +void G_PreLevelTitleCard(void); void G_DeferedPlayDemo(const char *demo); // Can be called by the startup code or M_Responder, calls P_SetupLevel. diff --git a/src/p_setup.c b/src/p_setup.c index 9054b582c..520f3136d 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3265,7 +3265,7 @@ boolean P_SetupLevel(boolean skipprecip) // If so... if ((!(mapheaderinfo[gamemap-1]->levelflags & LF_NOTITLECARD)) && (*mapheaderinfo[gamemap-1]->lvlttl != '\0')) - G_PreLevelTitleCard(lt_ticker, true); + G_PreLevelTitleCard(); return true; } diff --git a/src/st_stuff.c b/src/st_stuff.c index 3a8a4d2f1..8e255a46e 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1348,11 +1348,10 @@ luahook: // // Drawer for G_PreLevelTitleCard. // -void ST_preLevelTitleCardDrawer(tic_t ticker, boolean update) +void ST_preLevelTitleCardDrawer(boolean update) { V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol); - if (ticker < PRELEVELTIME-1) - ST_drawWipeTitleCard(); + ST_drawWipeTitleCard(); I_OsPolling(); I_UpdateNoBlit(); diff --git a/src/st_stuff.h b/src/st_stuff.h index 33ffa957a..325114af5 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -52,7 +52,7 @@ void ST_startTitleCard(void); void ST_runTitleCard(void); void ST_drawTitleCard(void); void ST_preDrawTitleCard(void); -void ST_preLevelTitleCardDrawer(tic_t ticker, boolean update); +void ST_preLevelTitleCardDrawer(boolean update); void ST_drawWipeTitleCard(void); extern tic_t lt_ticker, lt_lasttic; From 7384522aef5dcd85ac5ef3171571c120e1887143 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Thu, 5 Dec 2019 01:47:51 -0300 Subject: [PATCH 013/195] Fix Continue game state wipes --- src/f_finale.c | 2 ++ src/f_wipe.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/f_finale.c b/src/f_finale.c index c33cbc16b..73a82523f 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -3569,6 +3569,8 @@ void F_StartContinue(void) return; } + wipestyleflags = WSF_FADEOUT; + F_TryColormapFade(31); G_SetGamestate(GS_CONTINUING); gameaction = ga_nothing; diff --git a/src/f_wipe.c b/src/f_wipe.c index ea52042a5..f9d03a149 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -56,7 +56,7 @@ UINT8 wipedefs[NUMWIPEDEFS] = { 0, // wipe_level_toblack UINT8_MAX, // wipe_intermission_toblack - UINT8_MAX, // wipe_continuing_toblack + 0, // wipe_continuing_toblack 0, // wipe_titlescreen_toblack 0, // wipe_timeattack_toblack 99, // wipe_credits_toblack From ed34cb8d793692694a0a2694af00ec68793a5f5c Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Thu, 5 Dec 2019 16:25:19 -0300 Subject: [PATCH 014/195] Change st_overlay to cv_showhud.value --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 6b987646a..4df8071ad 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1847,7 +1847,7 @@ void G_PreLevelTitleCard(void) if (takescreenshot) // Only take screenshots after drawing. M_DoScreenShot(); } - if (!st_overlay) + if (!cv_showhud.value) wipestyleflags = WSF_CROSSFADE; } From 8ea7dd418a917d2677356d49c1e456567b1aa1ca Mon Sep 17 00:00:00 2001 From: Nev3r Date: Mon, 9 Dec 2019 13:26:31 +0100 Subject: [PATCH 015/195] Move the axis spawning code out of the mapthing read function, and read the mapthing z in the mapthing read function. --- src/p_setup.c | 55 ++++++++++++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index 3c45509ee..552617dbd 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1009,35 +1009,27 @@ void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum) static void P_PrepareRawThings(UINT8 *data, size_t i) { mapthing_t *mt; + sector_t *mtsector; nummapthings = i / (5 * sizeof (INT16)); mapthings = Z_Calloc(nummapthings * sizeof (*mapthings), PU_LEVEL, NULL); - // Spawn axis points first so they are - // at the front of the list for fast searching. - mt = mapthings; - for (i = 0; i < nummapthings; i++, mt++) + for (i = 0, mt = mapthings; i < nummapthings; i++, mt++) { mt->x = READINT16(data); mt->y = READINT16(data); + // Z for objects + mtsector = R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)->sector; + mt->z = (INT16)( +#ifdef ESLOPE + mtsector->f_slope ? P_GetZAt(mtsector->f_slope, mt->x << FRACBITS, mt->y << FRACBITS) : +#endif + mtsector->floorheight)>>FRACBITS; mt->angle = READINT16(data); mt->type = READUINT16(data); mt->options = READUINT16(data); mt->extrainfo = (UINT8)(mt->type >> 12); - mt->type &= 4095; - - switch (mt->type) - { - case 1700: // MT_AXIS - case 1701: // MT_AXISTRANSFER - case 1702: // MT_AXISTRANSFERLINE - mt->mobj = NULL; - P_SpawnMapThing(mt); - break; - default: - break; - } } } @@ -1053,21 +1045,26 @@ static void P_LoadThings(boolean loademblems) size_t i; mapthing_t *mt; - // Loading the things lump itself into memory is now handled in P_PrepareThings, above - - mt = mapthings; - numhuntemeralds = 0; - for (i = 0; i < nummapthings; i++, mt++) + // Spawn axis points first so they are at the front of the list for fast searching. + for (i = 0, mt = mapthings; i < nummapthings; i++, mt++) { - sector_t *mtsector = R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)->sector; + switch (mt->type) + { + case 1700: // MT_AXIS + case 1701: // MT_AXISTRANSFER + case 1702: // MT_AXISTRANSFERLINE + mt->mobj = NULL; + P_SpawnMapThing(mt); + break; + default: + break; + } + } - // Z for objects - mt->z = (INT16)( -#ifdef ESLOPE - mtsector->f_slope ? P_GetZAt(mtsector->f_slope, mt->x << FRACBITS, mt->y << FRACBITS) : -#endif - mtsector->floorheight)>>FRACBITS; + numhuntemeralds = 0; + for (i = 0, mt = mapthings; i < nummapthings; i++, mt++) + { if (mt->type == 1700 // MT_AXIS || mt->type == 1701 // MT_AXISTRANSFER || mt->type == 1702) // MT_AXISTRANSFERLINE From 6fe6db8e18dbe2907680e5d9c7805fc946679c29 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Mon, 9 Dec 2019 14:05:22 +0100 Subject: [PATCH 016/195] Removed seemingly redundant (and incorrect) mapthing Z load code. The proper code seems to sit inside P_SpawnMapThing() and the SpawnHoop functions. Time will tell if I've actually commited an atrocity. --- src/p_setup.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index 552617dbd..d082e95b2 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1009,7 +1009,6 @@ void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum) static void P_PrepareRawThings(UINT8 *data, size_t i) { mapthing_t *mt; - sector_t *mtsector; nummapthings = i / (5 * sizeof (INT16)); mapthings = Z_Calloc(nummapthings * sizeof (*mapthings), PU_LEVEL, NULL); @@ -1018,13 +1017,8 @@ static void P_PrepareRawThings(UINT8 *data, size_t i) { mt->x = READINT16(data); mt->y = READINT16(data); - // Z for objects - mtsector = R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)->sector; - mt->z = (INT16)( -#ifdef ESLOPE - mtsector->f_slope ? P_GetZAt(mtsector->f_slope, mt->x << FRACBITS, mt->y << FRACBITS) : -#endif - mtsector->floorheight)>>FRACBITS; + mt->z = 0; + mt->angle = READINT16(data); mt->type = READUINT16(data); mt->options = READUINT16(data); @@ -1137,11 +1131,6 @@ static void P_LoadThings(boolean loademblems) || mt->type == 1705 || mt->type == 1713) // hoops { mt->mobj = NULL; - - // Z for objects Tails 05-26-2002 - mt->z = (INT16)(R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS) - ->sector->floorheight>>FRACBITS); - P_SpawnHoopsAndRings(mt, false); } } From 3dfa526eead55b4407576b6954c51d3c1a23c876 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Tue, 10 Dec 2019 14:21:08 +0100 Subject: [PATCH 017/195] Separate Emerald Hunt emerald spawning into another function. --- src/p_setup.c | 96 ++++++++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index d082e95b2..86cc9d810 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1017,13 +1017,18 @@ static void P_PrepareRawThings(UINT8 *data, size_t i) { mt->x = READINT16(data); mt->y = READINT16(data); - mt->z = 0; mt->angle = READINT16(data); mt->type = READUINT16(data); mt->options = READUINT16(data); mt->extrainfo = (UINT8)(mt->type >> 12); + mt->type &= 4095; + + if (mt->type == 1705 || (mt->type == 750 && mt->extrainfo)) // NiGHTS Hoops + mt->z = mthing->options; + else + mt->z = mthing->options >> ZSHIFT; } } @@ -1034,6 +1039,51 @@ static void P_PrepareThings(lumpnum_t lumpnum) Z_Free(data); } +static void SpawnEmeraldHunt (void) +{ + INT32 emer1, emer2, emer3; + INT32 timeout = 0; // keeps from getting stuck + + emer1 = emer2 = emer3 = 0; + + //increment spawn numbers because zero is valid. + emer1 = (P_RandomKey(numhuntemeralds)) + 1; + while (timeout++ < 100) + { + emer2 = (P_RandomKey(numhuntemeralds)) + 1; + + if (emer2 != emer1) + break; + } + + timeout = 0; + while (timeout++ < 100) + { + emer3 = (P_RandomKey(numhuntemeralds)) + 1; + + if (emer3 != emer2 && emer3 != emer1) + break; + } + + //decrement spawn values to the actual number because zero is valid. + if (emer1--) + P_SpawnMobj(huntemeralds[emer1]->x<y<z<x<y<z<x<y<z<x<y<z<x<y<z<x<y<z< Date: Tue, 10 Dec 2019 18:03:15 +0100 Subject: [PATCH 018/195] Move mobj spawn Z calculating to a separate function. --- src/p_mobj.c | 181 +++++++++++++++++++++----------------------------- src/p_setup.c | 6 +- 2 files changed, 79 insertions(+), 108 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index dea4a7a4d..e64fb1537 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11550,6 +11550,80 @@ void P_MovePlayerToStarpost(INT32 playernum) mapthing_t *huntemeralds[MAXHUNTEMERALDS]; INT32 numhuntemeralds; + +static fixed_t GetMobjSpawnHeight (const mobjtype_t i, const mapthing_t* mthing, const fixed_t x, const fixed_t y) +{ + subsector_t *ss = R_PointInSubsector(x, y); + fixed_t z; + fixed_t extraoffset = 0; + fixed_t heightoffset = 0; + boolean flip; + + switch (i) + { + // Bumpers never spawn flipped. + case MT_NIGHTSBUMPER: + flip = false; + break; + + // Axis objects snap to the floor. + case MT_AXIS: + case MT_AXISTRANSFER: + case MT_AXISTRANSFERLINE: + return ONFLOORZ; + + // Objects with a non-zero default height. + case MT_CRAWLACOMMANDER: + case MT_DETON: + case MT_JETTBOMBER: + case MT_JETTGUNNER: + case MT_EGGMOBILE2: + heightoffset = mthing->z ? 0 : 33*FRACUNIT; + goto atend; + case MT_EGGMOBILE: + heightoffset = mthing->z ? 0 : 128*FRACUNIT; + goto atend; + case MT_GOLDBUZZ: + case MT_REDBUZZ: + heightoffset = mthing->z ? 0 : 288*FRACUNIT; + goto atend; + + // Ring-like items, may float additional units with MTF_AMBUSH. + case MT_SPIKEBALL: + case MT_EMERALDSPAWN: + case MT_TOKEN: + case MT_EMBLEM: + weaponfloat: + flip = mthing->options & MTF_OBJECTFLIP; + extraoffset = mthing->options & MTF_AMBUSH ? 24*FRACUNIT : 0; + heightoffset = mthing->z*FRACUNIT; + break; + + // Remaining objects. + default: + if (P_WeaponOrPanel(i)) + goto weaponfloat; // Ring-like items don't use MF_SPAWNCEILING to consider flips. + + atend: + heightoffset = mthing->z*FRACUNIT; + flip = (!!(mobjinfo[i].flags & MF_SPAWNCEILING) ^ !!(mthing->options & MTF_OBJECTFLIP)); + } + + // Establish height. + if (flip) + return ( +#ifdef ESLOPE + ss->sector->c_slope ? P_GetZAt(ss->sector->c_slope, x, y) : +#endif + ss->sector->ceilingheight) - extraoffset - mobjinfo[i].height; + else + return ( +#ifdef ESLOPE + ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) : +#endif + ss->sector->floorheight) + extraoffset + heightoffset; +} + // // P_SpawnMapThing // The fields of the mapthing should @@ -11560,7 +11634,6 @@ void P_SpawnMapThing(mapthing_t *mthing) mobjtype_t i; mobj_t *mobj; fixed_t x, y, z; - subsector_t *ss; boolean doangle = true; if (!mthing->type) @@ -11685,13 +11758,6 @@ You should think about modifying the deathmatch starts to take full advantage of if (gametype != GT_COOP) return; - ss = R_PointInSubsector(mthing->x << FRACBITS, mthing->y << FRACBITS); - mthing->z = (INT16)((( -#ifdef ESLOPE - ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, mthing->x << FRACBITS, mthing->y << FRACBITS) : -#endif - ss->sector->floorheight)>>FRACBITS) + (mthing->options >> ZSHIFT)); - if (numhuntemeralds < MAXHUNTEMERALDS) huntemeralds[numhuntemeralds++] = mthing; return; @@ -11820,102 +11886,7 @@ You should think about modifying the deathmatch starts to take full advantage of // spawn it x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; - ss = R_PointInSubsector(x, y); - - if (i == MT_NIGHTSBUMPER) - z = ( -#ifdef ESLOPE - ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) : -#endif - ss->sector->floorheight) + ((mthing->options >> ZSHIFT) << FRACBITS); - else if (i == MT_AXIS || i == MT_AXISTRANSFER || i == MT_AXISTRANSFERLINE) - z = ONFLOORZ; - else if (i == MT_SPIKEBALL || P_WeaponOrPanel(i) || i == MT_EMERALDSPAWN || i == MT_TOKEN || i == MT_EMBLEM) - { - if (mthing->options & MTF_OBJECTFLIP) - { - z = ( -#ifdef ESLOPE - ss->sector->c_slope ? P_GetZAt(ss->sector->c_slope, x, y) : -#endif - ss->sector->ceilingheight); - - if (mthing->options & MTF_AMBUSH) // Special flag for rings - z -= 24*FRACUNIT; - if (mthing->options >> ZSHIFT) - z -= (mthing->options >> ZSHIFT)*FRACUNIT; - - z -= mobjinfo[i].height; //Don't forget the height! - } - else - { - z = ( -#ifdef ESLOPE - ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) : -#endif - ss->sector->floorheight); - - if (mthing->options & MTF_AMBUSH) // Special flag for rings - z += 24*FRACUNIT; - if (mthing->options >> ZSHIFT) - z += (mthing->options >> ZSHIFT)*FRACUNIT; - } - - if (z == ONFLOORZ) - mthing->z = 0; - else - mthing->z = (INT16)(z>>FRACBITS); - } - else - { - fixed_t offset = 0; - boolean flip = (!!(mobjinfo[i].flags & MF_SPAWNCEILING) ^ !!(mthing->options & MTF_OBJECTFLIP)); - - // base positions - if (flip) - z = ( -#ifdef ESLOPE - ss->sector->c_slope ? P_GetZAt(ss->sector->c_slope, x, y) : -#endif - ss->sector->ceilingheight) - mobjinfo[i].height; - else - z = ( -#ifdef ESLOPE - ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) : -#endif - ss->sector->floorheight); - - // offsetting - if (mthing->options >> ZSHIFT) - offset = ((mthing->options >> ZSHIFT) << FRACBITS); - else if (i == MT_CRAWLACOMMANDER || i == MT_DETON || i == MT_JETTBOMBER || i == MT_JETTGUNNER || i == MT_EGGMOBILE2) - offset = 33*FRACUNIT; - else if (i == MT_EGGMOBILE) - offset = 128*FRACUNIT; - else if (i == MT_GOLDBUZZ || i == MT_REDBUZZ) - offset = 288*FRACUNIT; - - // applying offsets! (if any) - if (flip) - { - if (offset) - z -= offset; - else - z = ONCEILINGZ; - } - else - { - if (offset) - z += offset; - else - z = ONFLOORZ; - } - - if (z == ONFLOORZ) - mthing->z = 0; - else - mthing->z = (INT16)(z>>FRACBITS); - } + z = GetMobjSpawnHeight(i, mthing, x, y); mobj = P_SpawnMobj(x, y, z, i); mobj->spawnpoint = mthing; @@ -12019,7 +11990,7 @@ You should think about modifying the deathmatch starts to take full advantage of if (mthing->angle) mobj->health = mthing->angle; else - mobj->health = FixedMul(ss->sector->ceilingheight-ss->sector->floorheight, 3*(FRACUNIT/4))>>FRACBITS; + mobj->health = FixedMul(mobj->subsector->sector->ceilingheight - mobj->subsector->sector->floorheight, 3*(FRACUNIT/4))>>FRACBITS; break; case MT_METALSONIC_RACE: case MT_METALSONIC_BATTLE: diff --git a/src/p_setup.c b/src/p_setup.c index 86cc9d810..d40c728ab 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1025,10 +1025,10 @@ static void P_PrepareRawThings(UINT8 *data, size_t i) mt->type &= 4095; - if (mt->type == 1705 || (mt->type == 750 && mt->extrainfo)) // NiGHTS Hoops - mt->z = mthing->options; + if (mt->type == 1705 || (mt->type == 750 && mt->extrainfo)) + mt->z = mt->options; // NiGHTS Hoops use the full flags bits to set the height. else - mt->z = mthing->options >> ZSHIFT; + mt->z = mt->options >> ZSHIFT; } } From ca6a7ffbb3e720cc99c1355a58a51f15fdd97282 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Tue, 10 Dec 2019 18:53:49 +0100 Subject: [PATCH 019/195] Fix NiGHTS bumpers height. --- src/p_mobj.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index e64fb1537..3321107c7 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11563,6 +11563,7 @@ static fixed_t GetMobjSpawnHeight (const mobjtype_t i, const mapthing_t* mthing, { // Bumpers never spawn flipped. case MT_NIGHTSBUMPER: + heightoffset = mthing->z*FRACUNIT; flip = false; break; From 07316fc5bd81e986295cb1b7c00a9a709f5f05d3 Mon Sep 17 00:00:00 2001 From: GoldenTails Date: Tue, 10 Dec 2019 23:55:52 -0600 Subject: [PATCH 020/195] Stop characters from being able to activate their abilities when doing a shield ability! Fixes #61. --- src/p_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_user.c b/src/p_user.c index ea42a2c36..d409f6bcd 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -5273,7 +5273,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) player->secondjump = 0; player->pflags &= ~PF_THOKKED; } - else if (player->pflags & PF_SLIDING || (gametype == GT_CTF && player->gotflag)) + else if (player->pflags & PF_SLIDING || (gametype == GT_CTF && player->gotflag) || player->pflags & PF_SHIELDABILITY) ; /*else if (P_SuperReady(player)) { From 584348b91e67371719dba6ed017bdda20a7431a4 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Wed, 11 Dec 2019 10:13:52 +0100 Subject: [PATCH 021/195] Do not use mapthing flags to spawn hoops and rings; use the the previously set mapthing Z instead. --- src/p_mobj.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 3321107c7..34d33f788 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -13077,7 +13077,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) mobj_t *hoopcenter; INT16 spewangle; - z = mthing->options << FRACBITS; + z = mthing->z << FRACBITS; hoopcenter = P_SpawnMobj(x, y, z, MT_HOOPCENTER); @@ -13217,8 +13217,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) INT32 hoopsize; INT32 hoopplacement; - // Save our flags! - z = (mthing->options>>ZSHIFT) << FRACBITS; + z = mthing->z << FRACBITS; hoopcenter = P_SpawnMobj(x, y, z, MT_HOOPCENTER); hoopcenter->spawnpoint = mthing; @@ -13360,8 +13359,8 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : #endif sec->ceilingheight) - mobjinfo[ringthing].height; - if (mthing->options >> ZSHIFT) - z -= ((mthing->options >> ZSHIFT) << FRACBITS); + if (mthing->z) + z -= (mthing->z << FRACBITS); } else { @@ -13370,8 +13369,8 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : #endif sec->floorheight); - if (mthing->options >> ZSHIFT) - z += ((mthing->options >> ZSHIFT) << FRACBITS); + if (mthing->z) + z += (mthing->z << FRACBITS); } for (r = 1; r <= 5; r++) @@ -13420,8 +13419,8 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : #endif sec->ceilingheight) - mobjinfo[ringthing].height; - if (mthing->options >> ZSHIFT) - z -= ((mthing->options >> ZSHIFT) << FRACBITS); + if (mthing->z) + z -= (mthing->z << FRACBITS); } else { @@ -13430,8 +13429,8 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : #endif sec->floorheight); - if (mthing->options >> ZSHIFT) - z += ((mthing->options >> ZSHIFT) << FRACBITS); + if (mthing->z) + z += (mthing->z << FRACBITS); } for (r = 1; r <= iterations; r++) @@ -13477,8 +13476,8 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : #endif sec->floorheight; - if (mthing->options >> ZSHIFT) - z += ((mthing->options >> ZSHIFT) << FRACBITS); + if (mthing->z) + z += (mthing->z << FRACBITS); closestangle = FixedAngle(mthing->angle*FRACUNIT); @@ -13582,8 +13581,8 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : #endif sec->ceilingheight) - mobjinfo[ringthing].height; - if (mthing->options >> ZSHIFT) - z -= ((mthing->options >> ZSHIFT) << FRACBITS); + if (mthing->z) + z -= (mthing->z << FRACBITS); } else { @@ -13592,8 +13591,8 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : #endif sec->floorheight; - if (mthing->options >> ZSHIFT) - z += ((mthing->options >> ZSHIFT) << FRACBITS); + if (mthing->z) + z += (mthing->z << FRACBITS); } if (mthing->options & MTF_AMBUSH) // Special flag for rings From d2cbdd4fb1ebaf0a2ef2c093197e0a4c6f59a35f Mon Sep 17 00:00:00 2001 From: Nev3r Date: Wed, 11 Dec 2019 10:57:24 +0100 Subject: [PATCH 022/195] Do not overwrite the mapthing Z when spawning rings and similars, as it now causes them to respawn in wrong places because it is being actually used now. --- src/p_mobj.c | 3 --- src/p_setup.c | 4 ---- 2 files changed, 7 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 34d33f788..3d26b28f3 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11554,7 +11554,6 @@ INT32 numhuntemeralds; static fixed_t GetMobjSpawnHeight (const mobjtype_t i, const mapthing_t* mthing, const fixed_t x, const fixed_t y) { subsector_t *ss = R_PointInSubsector(x, y); - fixed_t z; fixed_t extraoffset = 0; fixed_t heightoffset = 0; boolean flip; @@ -13603,8 +13602,6 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) z += 24*FRACUNIT; } - mthing->z = (INT16)(z>>FRACBITS); - mobj = P_SpawnMobj(x, y, z, ringthing); mobj->spawnpoint = mthing; diff --git a/src/p_setup.c b/src/p_setup.c index d40c728ab..628292fe0 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -906,10 +906,6 @@ void P_ReloadRings(void) { mt->mobj = NULL; - // Z for objects Tails 05-26-2002 - mt->z = (INT16)(R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS) - ->sector->floorheight>>FRACBITS); - P_SpawnHoopsAndRings(mt, true); } } From 854d50f479f1ab775bfe1e8a3e86aeeb3edb06d6 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Wed, 11 Dec 2019 11:44:46 +0100 Subject: [PATCH 023/195] Added 'virtual resource' mechanism for temporary memory loaded lump lists. If you can come up with a better name then I'm all ears. --- src/w_wad.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/w_wad.h | 19 +++++++++++ 2 files changed, 114 insertions(+) diff --git a/src/w_wad.c b/src/w_wad.c index 801f50edd..2e2d00516 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -1888,3 +1888,98 @@ int W_VerifyNMUSlumps(const char *filename) }; return W_VerifyFile(filename, NMUSlist, false); } + +/** \brief Generates a virtual resource used for level data loading. + * + * \param lumpnum_t reference + * \return Virtual resource + * + */ +virtres_t* vres_GetMap (lumpnum_t lumpnum) +{ + UINT32 i; + virtres_t* vres = NULL; + virtlump_t* vlumps = NULL; + size_t numlumps = 0; + + if (W_IsLumpWad(lumpnum)) + { + // Remember that we're assuming that the WAD will have a specific set of lumps in a specific order. + UINT8 *wadData = W_CacheLumpNum(lumpnum, PU_LEVEL); + filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs); + numlumps = ((wadinfo_t *)wadData)->numlumps; + vlumps = Z_Malloc(sizeof(virtlump_t)*numlumps, PU_LEVEL, NULL); + + // Build the lumps. + for (i = 0; i < numlumps; i++) + { + vlumps[i].size = (size_t)(((filelump_t *)(fileinfo + i))->size); + // Play it safe with the name in this case. + memcpy(vlumps[i].name, (fileinfo + i)->name, 8); + vlumps[i].name[8] = '\0'; + vlumps[i].data = Z_Malloc(vlumps[i].size, PU_LEVEL, NULL); // This is memory inefficient, sorry about that. + memcpy(vlumps[i].data, wadData + (fileinfo + i)->filepos, vlumps[i].size); + } + + Z_Free(wadData); + } + else + { + // Count number of lumps until the end of resource OR up until next "MAPXX" lump. + lumpnum_t lumppos = lumpnum + 1; + for (i = LUMPNUM(lumppos); i < wadfiles[WADFILENUM(lumpnum)]->numlumps; i++, lumppos++, numlumps++) + if (memcmp(W_CheckNameForNum(lumppos), "MAP", 3) == 0) + break; + numlumps++; + + vlumps = Z_Malloc(sizeof(virtlump_t)*numlumps, PU_LEVEL, NULL); + for (i = 0; i < numlumps; i++, lumpnum++) + { + vlumps[i].size = W_LumpLength(lumpnum); + memcpy(vlumps[i].name, W_CheckNameForNum(lumpnum), 8); + vlumps[i].name[8] = '\0'; + vlumps[i].data = W_CacheLumpNum(lumpnum, PU_LEVEL); + } + } + vres = Z_Malloc(sizeof(virtres_t), PU_LEVEL, NULL); + vres->vlumps = vlumps; + vres->numlumps = numlumps; + return vres; +} + +/** \brief Frees zone memory for a given virtual resource. + * + * \param Virtual resource + */ +void vres_Free (virtres_t* vres) +{ + while (vres->numlumps--) + Z_Free(vres->vlumps[vres->numlumps].data); + Z_Free(vres->vlumps); + Z_Free(vres); +} + +/** (Debug) Prints lumps from a virtual resource into console. + */ +static void vres_Diag (const virtres_t* vres) +{ + UINT32 i; + for (i = 0; i < vres->numlumps; i++) + CONS_Printf("%s\n", vres->vlumps[i].name); +} + +/** \brief Finds a lump in a given virtual resource. + * + * \param Virtual resource + * \param Lump name to look for + * \return Virtual lump if found, NULL otherwise + * + */ +virtlump_t* vres_Find(const virtres_t* vres, const char* name) +{ + UINT32 i; + for (i = 0; i < vres->numlumps; i++) + if (fastcmp(name, vres->vlumps[i].name)) + return &vres->vlumps[i]; + return NULL; +} diff --git a/src/w_wad.h b/src/w_wad.h index a8be13ece..a265d78a9 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -72,6 +72,25 @@ typedef struct compmethod compression; // lump compression method } lumpinfo_t; +// ========================================================================= +// 'VIRTUAL' RESOURCES +// ========================================================================= + +typedef struct { + char name[9]; + UINT8* data; + size_t size; +} virtlump_t; + +typedef struct { + size_t numlumps; + virtlump_t* vlumps; +} virtres_t; + +virtres_t* vres_GetMap (lumpnum_t); +void vres_Free (virtres_t*); +virtlump_t* vres_Find (const virtres_t*, const char*); + // ========================================================================= // DYNAMIC WAD LOADING // ========================================================================= From f7c69f0c1cb81206f45db21ec93d15329b8ff188 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Wed, 11 Dec 2019 12:48:41 +0100 Subject: [PATCH 024/195] P_SetupLevel() no longer makes distinction on whether the map is a WAD in a PK3 or not. --- src/p_setup.c | 128 ++++++++++++++------------------------------------ 1 file changed, 34 insertions(+), 94 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index 3c45509ee..74d33f8f5 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1950,7 +1950,7 @@ static boolean P_LoadBlockMap(lumpnum_t lumpnum) // because making both the WAD and PK3 loading code use // the same functions is trickier than it looks for blockmap // -- Monster Iestyn 09/01/18 -static boolean P_LoadRawBlockMap(UINT8 *data, size_t count, const char *lumpname) +static boolean P_LoadRawBlockMap(UINT8 *data, size_t count) { #if 0 (void)data; @@ -1958,12 +1958,6 @@ static boolean P_LoadRawBlockMap(UINT8 *data, size_t count, const char *lumpname (void)lumpname; return false; #else - // Check if the lump is named "BLOCKMAP" - if (!lumpname || memcmp(lumpname, "BLOCKMAP", 8) != 0) - { - CONS_Printf("No blockmap lump found for pk3!\n"); - return false; - } if (!count || count >= 0x20000) return false; @@ -2120,16 +2114,8 @@ static void P_LoadReject(lumpnum_t lumpnum) // PK3 version // -- Monster Iestyn 09/01/18 -static void P_LoadRawReject(UINT8 *data, size_t count, const char *lumpname) +static void P_LoadRawReject(UINT8 *data, size_t count) { - // Check if the lump is named "REJECT" - if (!lumpname || memcmp(lumpname, "REJECT\0\0", 8) != 0) - { - rejectmatrix = NULL; - CONS_Debug(DBG_SETUP, "P_LoadRawReject: No valid REJECT lump found\n"); - return; - } - if (!count) // zero length, someone probably used ZDBSP { rejectmatrix = NULL; @@ -2892,51 +2878,42 @@ boolean P_SetupLevel(boolean skipprecip) P_MakeMapMD5(lastloadedmaplumpnum, &mapmd5); - // HACK ALERT: Cache the WAD, get the map data into the tables, free memory. - // As it is implemented right now, we're assuming an uncompressed WAD. - // (As in, a normal PWAD, not ZWAD or anything. The lump itself can be compressed.) - // We're not accounting for extra lumps and scrambled lump positions. Any additional data will cause an error. - if (W_IsLumpWad(lastloadedmaplumpnum)) + if (lastloadedmaplumpnum) { - // Remember that we're assuming that the WAD will have a specific set of lumps in a specific order. - UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC); - //filelump_t *fileinfo = wadData + ((wadinfo_t *)wadData)->infotableofs; - filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs); - UINT32 numlumps = ((wadinfo_t *)wadData)->numlumps; + virtres_t* virt = vres_GetMap(lastloadedmaplumpnum); + virtlump_t* virtthings = vres_Find(virt, "THINGS"); + virtlump_t* virtvertexes = vres_Find(virt, "VERTEXES"); + virtlump_t* virtsectors = vres_Find(virt, "SECTORS"); + virtlump_t* virtsidedefs = vres_Find(virt, "SIDEDEFS"); + virtlump_t* virtlinedefs = vres_Find(virt, "LINEDEFS"); - if (numlumps < ML_REJECT) // at least 9 lumps should be in the wad for a map to be loaded - { - I_Error("Bad WAD file for map %s!\n", maplumpname); - } + virtlump_t* virtssectors = vres_Find(virt, "SSECTORS"); + virtlump_t* virtsegs = vres_Find(virt, "SEGS"); + virtlump_t* virtnodes = vres_Find(virt, "NODES"); - if (numlumps > ML_BLOCKMAP) // enough room for a BLOCKMAP lump at least - { - loadedbm = P_LoadRawBlockMap( - wadData + (fileinfo + ML_BLOCKMAP)->filepos, - (fileinfo + ML_BLOCKMAP)->size, - (fileinfo + ML_BLOCKMAP)->name); - } - P_LoadRawVertexes(wadData + (fileinfo + ML_VERTEXES)->filepos, (fileinfo + ML_VERTEXES)->size); - P_LoadRawSectors(wadData + (fileinfo + ML_SECTORS)->filepos, (fileinfo + ML_SECTORS)->size); - P_LoadRawSideDefs((fileinfo + ML_SIDEDEFS)->size); - P_LoadRawLineDefs(wadData + (fileinfo + ML_LINEDEFS)->filepos, (fileinfo + ML_LINEDEFS)->size); - P_LoadRawSideDefs2(wadData + (fileinfo + ML_SIDEDEFS)->filepos); - P_LoadRawSubsectors(wadData + (fileinfo + ML_SSECTORS)->filepos, (fileinfo + ML_SSECTORS)->size); - P_LoadRawNodes(wadData + (fileinfo + ML_NODES)->filepos, (fileinfo + ML_NODES)->size); - P_LoadRawSegs(wadData + (fileinfo + ML_SEGS)->filepos, (fileinfo + ML_SEGS)->size); - if (numlumps > ML_REJECT) // enough room for a REJECT lump at least - { - P_LoadRawReject( - wadData + (fileinfo + ML_REJECT)->filepos, - (fileinfo + ML_REJECT)->size, - (fileinfo + ML_REJECT)->name); - } + virtlump_t* virtblockmap = vres_Find(virt, "BLOCKMAP"); + virtlump_t* virtreject = vres_Find(virt, "REJECT"); + + P_LoadRawVertexes(virtvertexes->data, virtvertexes->size); + P_LoadRawSectors(virtsectors->data, virtsectors->size); + P_LoadRawSideDefs(virtsidedefs->size); + P_LoadRawLineDefs(virtlinedefs->data, virtlinedefs->size); + P_LoadRawSideDefs2(virtsidedefs->data); + P_LoadRawSubsectors(virtssectors->data, virtssectors->size); + P_LoadRawNodes(virtnodes->data, virtnodes->size); + P_LoadRawSegs(virtsegs->data, virtsegs->size); + + if (virtreject) + P_LoadRawReject(virtreject->data, virtreject->size); + else + rejectmatrix = NULL; + + if (!(virtblockmap && P_LoadRawBlockMap(virtblockmap->data, virtblockmap->size))) + P_CreateBlockMap(); - // Important: take care of the ordering of the next functions. - if (!loadedbm) - P_CreateBlockMap(); // Graue 02-29-2004 P_LoadLineDefs2(); P_GroupLines(); + numdmstarts = numredctfstarts = numbluectfstarts = 0; // reset the player starts @@ -2954,46 +2931,9 @@ boolean P_SetupLevel(boolean skipprecip) P_MapStart(); - P_PrepareRawThings(wadData + (fileinfo + ML_THINGS)->filepos, (fileinfo + ML_THINGS)->size); - Z_Free(wadData); - } - else - { - // Important: take care of the ordering of the next functions. - loadedbm = P_LoadBlockMap(lastloadedmaplumpnum + ML_BLOCKMAP); - P_LoadVertexes(lastloadedmaplumpnum + ML_VERTEXES); - P_LoadSectors(lastloadedmaplumpnum + ML_SECTORS); - P_LoadSideDefs(lastloadedmaplumpnum + ML_SIDEDEFS); - P_LoadLineDefs(lastloadedmaplumpnum + ML_LINEDEFS); - P_LoadSideDefs2(lastloadedmaplumpnum + ML_SIDEDEFS); - P_LoadSubsectors(lastloadedmaplumpnum + ML_SSECTORS); - P_LoadNodes(lastloadedmaplumpnum + ML_NODES); - P_LoadSegs(lastloadedmaplumpnum + ML_SEGS); - P_LoadReject(lastloadedmaplumpnum + ML_REJECT); + P_PrepareRawThings(virtthings->data, virtthings->size); - // Important: take care of the ordering of the next functions. - if (!loadedbm) - P_CreateBlockMap(); // Graue 02-29-2004 - P_LoadLineDefs2(); - P_GroupLines(); - numdmstarts = numredctfstarts = numbluectfstarts = 0; - - // reset the player starts - for (i = 0; i < MAXPLAYERS; i++) - playerstarts[i] = bluectfstarts[i] = redctfstarts[i] = NULL; - - for (i = 0; i < MAX_DM_STARTS; i++) - deathmatchstarts[i] = NULL; - - for (i = 0; i < 2; i++) - skyboxmo[i] = NULL; - - for (i = 0; i < 16; i++) - skyboxviewpnts[i] = skyboxcenterpnts[i] = NULL; - - P_MapStart(); - - P_PrepareThings(lastloadedmaplumpnum + ML_THINGS); + vres_Free(virt); } // init gravity, tag lists, From bf5a2c68d594c09d802f8f99720845b9b4e96029 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Wed, 11 Dec 2019 12:48:41 +0100 Subject: [PATCH 025/195] P_SetupLevel() no longer makes distinction on whether the map is a WAD in a PK3 or not. --- src/p_saveg.c | 28 ++--------- src/p_setup.c | 128 ++++++++++++++------------------------------------ 2 files changed, 39 insertions(+), 117 deletions(-) diff --git a/src/p_saveg.c b/src/p_saveg.c index 89447db80..c876713e4 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -781,9 +781,10 @@ static void P_NetArchiveWorld(void) UINT8 *put; // reload the map just to see difference - mapsector_t *ms; - mapsidedef_t *msd; - maplinedef_t *mld; + virtres_t* virt = vres_GetMap(lastloadedmaplumpnum); + mapsector_t *ms = (mapsector_t*) vres_Find(virt, "SECTORS")->data; + mapsidedef_t *msd = (mapsidedef_t*) vres_Find(virt, "SIDEDEFS")->data; + maplinedef_t *mld = (maplinedef_t*) vres_Find(virt, "LINEDEFS")->data; const sector_t *ss = sectors; UINT8 diff, diff2, diff3; @@ -793,26 +794,6 @@ static void P_NetArchiveWorld(void) WRITEUINT32(save_p, ARCHIVEBLOCK_WORLD); put = save_p; - if (W_IsLumpWad(lastloadedmaplumpnum)) // welp it's a map wad in a pk3 - { // HACK: Open wad file rather quickly so we can get the data from the relevant lumps - UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC); - filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs); -#define retrieve_mapdata(d, f)\ - d = Z_Malloc((f)->size, PU_CACHE, NULL); \ - M_Memcpy(d, wadData + (f)->filepos, (f)->size) - retrieve_mapdata(ms, fileinfo + ML_SECTORS); - retrieve_mapdata(mld, fileinfo + ML_LINEDEFS); - retrieve_mapdata(msd, fileinfo + ML_SIDEDEFS); -#undef retrieve_mapdata - Z_Free(wadData); // we're done with this now - } - else // phew it's just a WAD - { - ms = W_CacheLumpNum(lastloadedmaplumpnum+ML_SECTORS, PU_CACHE); - mld = W_CacheLumpNum(lastloadedmaplumpnum+ML_LINEDEFS, PU_CACHE); - msd = W_CacheLumpNum(lastloadedmaplumpnum+ML_SIDEDEFS, PU_CACHE); - } - for (i = 0; i < numsectors; i++, ss++, ms++) { diff = diff2 = diff3 = 0; @@ -1037,6 +1018,7 @@ static void P_NetArchiveWorld(void) WRITEUINT16(put, 0xffff); R_ClearTextureNumCache(false); + vres_Free(virt); save_p = put; } diff --git a/src/p_setup.c b/src/p_setup.c index 3c45509ee..74d33f8f5 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1950,7 +1950,7 @@ static boolean P_LoadBlockMap(lumpnum_t lumpnum) // because making both the WAD and PK3 loading code use // the same functions is trickier than it looks for blockmap // -- Monster Iestyn 09/01/18 -static boolean P_LoadRawBlockMap(UINT8 *data, size_t count, const char *lumpname) +static boolean P_LoadRawBlockMap(UINT8 *data, size_t count) { #if 0 (void)data; @@ -1958,12 +1958,6 @@ static boolean P_LoadRawBlockMap(UINT8 *data, size_t count, const char *lumpname (void)lumpname; return false; #else - // Check if the lump is named "BLOCKMAP" - if (!lumpname || memcmp(lumpname, "BLOCKMAP", 8) != 0) - { - CONS_Printf("No blockmap lump found for pk3!\n"); - return false; - } if (!count || count >= 0x20000) return false; @@ -2120,16 +2114,8 @@ static void P_LoadReject(lumpnum_t lumpnum) // PK3 version // -- Monster Iestyn 09/01/18 -static void P_LoadRawReject(UINT8 *data, size_t count, const char *lumpname) +static void P_LoadRawReject(UINT8 *data, size_t count) { - // Check if the lump is named "REJECT" - if (!lumpname || memcmp(lumpname, "REJECT\0\0", 8) != 0) - { - rejectmatrix = NULL; - CONS_Debug(DBG_SETUP, "P_LoadRawReject: No valid REJECT lump found\n"); - return; - } - if (!count) // zero length, someone probably used ZDBSP { rejectmatrix = NULL; @@ -2892,51 +2878,42 @@ boolean P_SetupLevel(boolean skipprecip) P_MakeMapMD5(lastloadedmaplumpnum, &mapmd5); - // HACK ALERT: Cache the WAD, get the map data into the tables, free memory. - // As it is implemented right now, we're assuming an uncompressed WAD. - // (As in, a normal PWAD, not ZWAD or anything. The lump itself can be compressed.) - // We're not accounting for extra lumps and scrambled lump positions. Any additional data will cause an error. - if (W_IsLumpWad(lastloadedmaplumpnum)) + if (lastloadedmaplumpnum) { - // Remember that we're assuming that the WAD will have a specific set of lumps in a specific order. - UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC); - //filelump_t *fileinfo = wadData + ((wadinfo_t *)wadData)->infotableofs; - filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs); - UINT32 numlumps = ((wadinfo_t *)wadData)->numlumps; + virtres_t* virt = vres_GetMap(lastloadedmaplumpnum); + virtlump_t* virtthings = vres_Find(virt, "THINGS"); + virtlump_t* virtvertexes = vres_Find(virt, "VERTEXES"); + virtlump_t* virtsectors = vres_Find(virt, "SECTORS"); + virtlump_t* virtsidedefs = vres_Find(virt, "SIDEDEFS"); + virtlump_t* virtlinedefs = vres_Find(virt, "LINEDEFS"); - if (numlumps < ML_REJECT) // at least 9 lumps should be in the wad for a map to be loaded - { - I_Error("Bad WAD file for map %s!\n", maplumpname); - } + virtlump_t* virtssectors = vres_Find(virt, "SSECTORS"); + virtlump_t* virtsegs = vres_Find(virt, "SEGS"); + virtlump_t* virtnodes = vres_Find(virt, "NODES"); - if (numlumps > ML_BLOCKMAP) // enough room for a BLOCKMAP lump at least - { - loadedbm = P_LoadRawBlockMap( - wadData + (fileinfo + ML_BLOCKMAP)->filepos, - (fileinfo + ML_BLOCKMAP)->size, - (fileinfo + ML_BLOCKMAP)->name); - } - P_LoadRawVertexes(wadData + (fileinfo + ML_VERTEXES)->filepos, (fileinfo + ML_VERTEXES)->size); - P_LoadRawSectors(wadData + (fileinfo + ML_SECTORS)->filepos, (fileinfo + ML_SECTORS)->size); - P_LoadRawSideDefs((fileinfo + ML_SIDEDEFS)->size); - P_LoadRawLineDefs(wadData + (fileinfo + ML_LINEDEFS)->filepos, (fileinfo + ML_LINEDEFS)->size); - P_LoadRawSideDefs2(wadData + (fileinfo + ML_SIDEDEFS)->filepos); - P_LoadRawSubsectors(wadData + (fileinfo + ML_SSECTORS)->filepos, (fileinfo + ML_SSECTORS)->size); - P_LoadRawNodes(wadData + (fileinfo + ML_NODES)->filepos, (fileinfo + ML_NODES)->size); - P_LoadRawSegs(wadData + (fileinfo + ML_SEGS)->filepos, (fileinfo + ML_SEGS)->size); - if (numlumps > ML_REJECT) // enough room for a REJECT lump at least - { - P_LoadRawReject( - wadData + (fileinfo + ML_REJECT)->filepos, - (fileinfo + ML_REJECT)->size, - (fileinfo + ML_REJECT)->name); - } + virtlump_t* virtblockmap = vres_Find(virt, "BLOCKMAP"); + virtlump_t* virtreject = vres_Find(virt, "REJECT"); + + P_LoadRawVertexes(virtvertexes->data, virtvertexes->size); + P_LoadRawSectors(virtsectors->data, virtsectors->size); + P_LoadRawSideDefs(virtsidedefs->size); + P_LoadRawLineDefs(virtlinedefs->data, virtlinedefs->size); + P_LoadRawSideDefs2(virtsidedefs->data); + P_LoadRawSubsectors(virtssectors->data, virtssectors->size); + P_LoadRawNodes(virtnodes->data, virtnodes->size); + P_LoadRawSegs(virtsegs->data, virtsegs->size); + + if (virtreject) + P_LoadRawReject(virtreject->data, virtreject->size); + else + rejectmatrix = NULL; + + if (!(virtblockmap && P_LoadRawBlockMap(virtblockmap->data, virtblockmap->size))) + P_CreateBlockMap(); - // Important: take care of the ordering of the next functions. - if (!loadedbm) - P_CreateBlockMap(); // Graue 02-29-2004 P_LoadLineDefs2(); P_GroupLines(); + numdmstarts = numredctfstarts = numbluectfstarts = 0; // reset the player starts @@ -2954,46 +2931,9 @@ boolean P_SetupLevel(boolean skipprecip) P_MapStart(); - P_PrepareRawThings(wadData + (fileinfo + ML_THINGS)->filepos, (fileinfo + ML_THINGS)->size); - Z_Free(wadData); - } - else - { - // Important: take care of the ordering of the next functions. - loadedbm = P_LoadBlockMap(lastloadedmaplumpnum + ML_BLOCKMAP); - P_LoadVertexes(lastloadedmaplumpnum + ML_VERTEXES); - P_LoadSectors(lastloadedmaplumpnum + ML_SECTORS); - P_LoadSideDefs(lastloadedmaplumpnum + ML_SIDEDEFS); - P_LoadLineDefs(lastloadedmaplumpnum + ML_LINEDEFS); - P_LoadSideDefs2(lastloadedmaplumpnum + ML_SIDEDEFS); - P_LoadSubsectors(lastloadedmaplumpnum + ML_SSECTORS); - P_LoadNodes(lastloadedmaplumpnum + ML_NODES); - P_LoadSegs(lastloadedmaplumpnum + ML_SEGS); - P_LoadReject(lastloadedmaplumpnum + ML_REJECT); + P_PrepareRawThings(virtthings->data, virtthings->size); - // Important: take care of the ordering of the next functions. - if (!loadedbm) - P_CreateBlockMap(); // Graue 02-29-2004 - P_LoadLineDefs2(); - P_GroupLines(); - numdmstarts = numredctfstarts = numbluectfstarts = 0; - - // reset the player starts - for (i = 0; i < MAXPLAYERS; i++) - playerstarts[i] = bluectfstarts[i] = redctfstarts[i] = NULL; - - for (i = 0; i < MAX_DM_STARTS; i++) - deathmatchstarts[i] = NULL; - - for (i = 0; i < 2; i++) - skyboxmo[i] = NULL; - - for (i = 0; i < 16; i++) - skyboxviewpnts[i] = skyboxcenterpnts[i] = NULL; - - P_MapStart(); - - P_PrepareThings(lastloadedmaplumpnum + ML_THINGS); + vres_Free(virt); } // init gravity, tag lists, From 4d86dc11a639043e44794fd2159dd6ed954a522d Mon Sep 17 00:00:00 2001 From: Nev3r Date: Wed, 11 Dec 2019 13:54:15 +0100 Subject: [PATCH 026/195] 'prepare' mapthings using virtres in P_LevelInitStuff(). Whether 'preparing' them or not is actually necessary is another matter. --- src/p_setup.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index 74d33f8f5..587b0b55a 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2303,6 +2303,8 @@ void P_LoadThingsOnly(void) // Search through all the thinkers. thinker_t *think; INT32 i, viewid = -1, centerid = -1; // for skyboxes + virtres_t* virt = vres_GetMap(lastloadedmaplumpnum); + virtlump_t* vth = vres_Find(virt, "THINGS"); // check if these are any of the normal viewpoint/centerpoint mobjs in the level or not if (skyboxmo[0] || skyboxmo[1]) @@ -2314,7 +2316,6 @@ void P_LoadThingsOnly(void) centerid = i; // save id just in case } - for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next) { if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) @@ -2324,18 +2325,11 @@ void P_LoadThingsOnly(void) P_LevelInitStuff(); - if (W_IsLumpWad(lastloadedmaplumpnum)) // welp it's a map wad in a pk3 - { // HACK: Open wad file rather quickly so we can use the things lump - UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC); - filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs); - fileinfo += ML_THINGS; // we only need the THINGS lump - P_PrepareRawThings(wadData + fileinfo->filepos, fileinfo->size); - Z_Free(wadData); // we're done with this now - } - else // phew it's just a WAD - P_PrepareThings(lastloadedmaplumpnum + ML_THINGS); + P_PrepareRawThings(vth->data, vth->size); P_LoadThings(true); + vres_Free(virt); + // restore skybox viewpoint/centerpoint if necessary, set them to defaults if we can't do that skyboxmo[0] = skyboxviewpnts[(viewid >= 0) ? viewid : 0]; skyboxmo[1] = skyboxcenterpnts[(centerid >= 0) ? centerid : 0]; From 14ad3b938e7ece8aee71ba4c856ff1b3780186c6 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Wed, 11 Dec 2019 14:04:09 +0100 Subject: [PATCH 027/195] Use virtres in P_SpawnSpecials(). Whether accessing the lump again here is right or not is also a different question. --- src/p_spec.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/p_spec.c b/src/p_spec.c index dba4e17b5..8ec1646ce 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -6425,7 +6425,7 @@ void P_SpawnSpecials(INT32 fromnetsave) INT32 j; thinkerlist_t *secthinkers; thinker_t *th; - + virtres_t* virt = NULL; // This used to be used, and *should* be used in the future, // but currently isn't. (void)fromnetsave; @@ -7177,17 +7177,10 @@ void P_SpawnSpecials(INT32 fromnetsave) UINT8 *data; UINT16 b; - if (W_IsLumpWad(lastloadedmaplumpnum)) // welp it's a map wad in a pk3 - { // HACK: Open wad file rather quickly so we can get the data from the sidedefs lump - UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC); - filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs); - fileinfo += ML_SIDEDEFS; // we only need the SIDEDEFS lump - data = Z_Malloc(fileinfo->size, PU_STATIC, NULL); - M_Memcpy(data, wadData + fileinfo->filepos, fileinfo->size); // copy data - Z_Free(wadData); // we're done with this now - } - else // phew it's just a WAD - data = W_CacheLumpNum(lastloadedmaplumpnum + ML_SIDEDEFS,PU_STATIC); + if (!virt) + virt = vres_GetMap(lastloadedmaplumpnum); + + data = (UINT8*) vres_Find(virt, "SIDEDEFS")->data; for (b = 0; b < (INT16)numsides; b++) { @@ -7433,6 +7426,9 @@ void P_SpawnSpecials(INT32 fromnetsave) } } + if (virt) + vres_Free(virt); + // Allocate each list for (i = 0; i < numsectors; i++) if(secthinkers[i].thinkers) From 9952bae5ee5174c2c1a63da4db435c9eeeb3982b Mon Sep 17 00:00:00 2001 From: Nev3r Date: Wed, 11 Dec 2019 14:20:08 +0100 Subject: [PATCH 028/195] P_MakeMapMD5() now uses virtres. --- src/p_setup.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index 587b0b55a..e2d67581b 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2361,7 +2361,7 @@ static INT32 P_MakeBufferMD5(const char *buffer, size_t len, void *resblock) #endif } -static void P_MakeMapMD5(lumpnum_t maplumpnum, void *dest) +static void P_MakeMapMD5(virtres_t* virt, void *dest) { unsigned char linemd5[16]; unsigned char sectormd5[16]; @@ -2372,20 +2372,15 @@ static void P_MakeMapMD5(lumpnum_t maplumpnum, void *dest) // Create a hash for the current map // get the actual lumps! - UINT8 *datalines = W_CacheLumpNum(maplumpnum + ML_LINEDEFS, PU_CACHE); - UINT8 *datasectors = W_CacheLumpNum(maplumpnum + ML_SECTORS, PU_CACHE); - UINT8 *datathings = W_CacheLumpNum(maplumpnum + ML_THINGS, PU_CACHE); - UINT8 *datasides = W_CacheLumpNum(maplumpnum + ML_SIDEDEFS, PU_CACHE); + virtlump_t* virtlines = vres_Find(virt, "LINEDEFS"); + virtlump_t* virtsectors = vres_Find(virt, "SECTORS"); + virtlump_t* virtmthings = vres_Find(virt, "THINGS"); + virtlump_t* virtsides = vres_Find(virt, "SIDEDEFS"); - P_MakeBufferMD5((char*)datalines, W_LumpLength(maplumpnum + ML_LINEDEFS), linemd5); - P_MakeBufferMD5((char*)datasectors, W_LumpLength(maplumpnum + ML_SECTORS), sectormd5); - P_MakeBufferMD5((char*)datathings, W_LumpLength(maplumpnum + ML_THINGS), thingmd5); - P_MakeBufferMD5((char*)datasides, W_LumpLength(maplumpnum + ML_SIDEDEFS), sidedefmd5); - - Z_Free(datalines); - Z_Free(datasectors); - Z_Free(datathings); - Z_Free(datasides); + P_MakeBufferMD5((char*)virtlines->data, virtlines->size, linemd5); + P_MakeBufferMD5((char*)virtsectors->data, virtsectors->size, sectormd5); + P_MakeBufferMD5((char*)virtmthings->data, virtmthings->size, thingmd5); + P_MakeBufferMD5((char*)virtsides->data, virtsides->size, sidedefmd5); for (i = 0; i < 16; i++) resmd5[i] = (linemd5[i] + sectormd5[i] + thingmd5[i] + sidedefmd5[i]) & 0xFF; @@ -2870,8 +2865,6 @@ boolean P_SetupLevel(boolean skipprecip) // SRB2 determines the sky texture to be used depending on the map header. P_SetupLevelSky(mapheaderinfo[gamemap-1]->skynum, true); - P_MakeMapMD5(lastloadedmaplumpnum, &mapmd5); - if (lastloadedmaplumpnum) { virtres_t* virt = vres_GetMap(lastloadedmaplumpnum); @@ -2888,6 +2881,8 @@ boolean P_SetupLevel(boolean skipprecip) virtlump_t* virtblockmap = vres_Find(virt, "BLOCKMAP"); virtlump_t* virtreject = vres_Find(virt, "REJECT"); + P_MakeMapMD5(virt, &mapmd5); + P_LoadRawVertexes(virtvertexes->data, virtvertexes->size); P_LoadRawSectors(virtsectors->data, virtsectors->size); P_LoadRawSideDefs(virtsidedefs->size); From a87a9e6ff6a9844d75d5be29ad70ef2d5b0e2bbe Mon Sep 17 00:00:00 2001 From: Nev3r Date: Wed, 11 Dec 2019 14:40:31 +0100 Subject: [PATCH 029/195] Remove wrappers and dupes for map lump reading, as they are no longer used. --- src/p_setup.c | 168 -------------------------------------------------- 1 file changed, 168 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index e2d67581b..17909ee58 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -397,13 +397,6 @@ static inline void P_LoadRawVertexes(UINT8 *data, size_t i) } } -static inline void P_LoadVertexes(lumpnum_t lumpnum) -{ - UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC); - P_LoadRawVertexes(data, W_LumpLength(lumpnum)); - Z_Free(data); -} - /** Computes the length of a seg in fracunits. * * \param seg Seg to compute length for. @@ -488,14 +481,6 @@ static void P_LoadRawSegs(UINT8 *data, size_t i) } } -static void P_LoadSegs(lumpnum_t lumpnum) -{ - UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC); - P_LoadRawSegs(data, W_LumpLength(lumpnum)); - Z_Free(data); -} - - /** Loads the SSECTORS resource from a level. * * \param lump Lump number of the SSECTORS resource. @@ -525,13 +510,6 @@ static inline void P_LoadRawSubsectors(void *data, size_t i) } } -static void P_LoadSubsectors(lumpnum_t lumpnum) -{ - UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC); - P_LoadRawSubsectors(data, W_LumpLength(lumpnum)); - Z_Free(data); -} - // // levelflats // @@ -805,13 +783,6 @@ static void P_LoadRawSectors(UINT8 *data, size_t i) P_SetupLevelFlatAnims(); } -static void P_LoadSectors(lumpnum_t lumpnum) -{ - UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC); - P_LoadRawSectors(data, W_LumpLength(lumpnum)); - Z_Free(data); -} - // // P_LoadNodes // @@ -844,13 +815,6 @@ static void P_LoadRawNodes(UINT8 *data, size_t i) } } -static void P_LoadNodes(lumpnum_t lumpnum) -{ - UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC); - P_LoadRawNodes(data, W_LumpLength(lumpnum)); - Z_Free(data); -} - // // P_ReloadRings // Used by NiGHTS, clears all ring/wing/etc items and respawns them @@ -1041,13 +1005,6 @@ static void P_PrepareRawThings(UINT8 *data, size_t i) } } -static void P_PrepareThings(lumpnum_t lumpnum) -{ - UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC); - P_PrepareRawThings(data, W_LumpLength(lumpnum)); - Z_Free(data); -} - static void P_LoadThings(boolean loademblems) { size_t i; @@ -1300,13 +1257,6 @@ static void P_LoadRawLineDefs(UINT8 *data, size_t i) } } -static void P_LoadLineDefs(lumpnum_t lumpnum) -{ - UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC); - P_LoadRawLineDefs(data, W_LumpLength(lumpnum)); - Z_Free(data); -} - static void P_LoadLineDefs2(void) { size_t i = numlines; @@ -1419,12 +1369,6 @@ static inline void P_LoadRawSideDefs(size_t i) sides = Z_Calloc(numsides * sizeof (*sides), PU_LEVEL, NULL); } -static inline void P_LoadSideDefs(lumpnum_t lumpnum) -{ - P_LoadRawSideDefs(W_LumpLength(lumpnum)); -} - - static void P_LoadRawSideDefs2(void *data) { UINT16 i; @@ -1585,15 +1529,6 @@ static void P_LoadRawSideDefs2(void *data) R_ClearTextureNumCache(true); } -// Delay loading texture names until after loaded linedefs. -static void P_LoadSideDefs2(lumpnum_t lumpnum) -{ - UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC); - P_LoadRawSideDefs2(data); - Z_Free(data); -} - - static boolean LineInBlock(fixed_t cx1, fixed_t cy1, fixed_t cx2, fixed_t cy2, fixed_t bx1, fixed_t by1) { fixed_t bbox[4]; @@ -1873,79 +1808,6 @@ static void P_ReadBlockMapLump(INT16 *wadblockmaplump, size_t count) } } -// -// P_LoadBlockMap -// -// Levels might not have a blockmap, so if one does not exist -// this should return false. -static boolean P_LoadBlockMap(lumpnum_t lumpnum) -{ -#if 0 - (void)lumpnum; - return false; -#else - size_t count; - const char *lumpname = W_CheckNameForNum(lumpnum); - - // Check if the lump exists, and if it's named "BLOCKMAP" - if (!lumpname || memcmp(lumpname, "BLOCKMAP", 8) != 0) - { - return false; - } - - count = W_LumpLength(lumpnum); - - if (!count || count >= 0x20000) - return false; - - { - INT16 *wadblockmaplump = malloc(count); //INT16 *wadblockmaplump = W_CacheLumpNum (lump, PU_LEVEL); - if (!wadblockmaplump) - return false; - W_ReadLump(lumpnum, wadblockmaplump); - count /= 2; - P_ReadBlockMapLump(wadblockmaplump, count); - free(wadblockmaplump); - } - - bmaporgx = blockmaplump[0]< Date: Wed, 11 Dec 2019 15:16:56 +0100 Subject: [PATCH 030/195] Oversight, do not free the data yet vres_Free() does it already at the end. --- src/p_spec.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/p_spec.c b/src/p_spec.c index 8ec1646ce..b50fc66c0 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -7200,7 +7200,6 @@ void P_SpawnSpecials(INT32 fromnetsave) I_Error("Make-Your-Own-FOF (tag %d) needs a value in the linedef's second side upper texture field.", lines[i].tag); } } - Z_Free(data); } else I_Error("Make-Your-Own FOF (tag %d) found without a 2nd linedef side!", lines[i].tag); From d34fd4b755f7cf80cf84ca6ed31e337ff2ad762c Mon Sep 17 00:00:00 2001 From: Nev3r Date: Wed, 11 Dec 2019 15:48:44 +0100 Subject: [PATCH 031/195] Epic oversight in upside-down spawn offset. --- src/p_mobj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 3d26b28f3..dae891afd 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11615,7 +11615,7 @@ static fixed_t GetMobjSpawnHeight (const mobjtype_t i, const mapthing_t* mthing, #ifdef ESLOPE ss->sector->c_slope ? P_GetZAt(ss->sector->c_slope, x, y) : #endif - ss->sector->ceilingheight) - extraoffset - mobjinfo[i].height; + ss->sector->ceilingheight) - extraoffset - heightoffset - mobjinfo[i].height; else return ( #ifdef ESLOPE From edfe053cc304161a8b0cf56b35dc93edbe5d3e6b Mon Sep 17 00:00:00 2001 From: Nev3r Date: Wed, 11 Dec 2019 16:37:41 +0100 Subject: [PATCH 032/195] Treat warnings as errors; comment out unused function. --- src/w_wad.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/w_wad.c b/src/w_wad.c index 2e2d00516..f16e8eb5b 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -1944,6 +1944,7 @@ virtres_t* vres_GetMap (lumpnum_t lumpnum) vres = Z_Malloc(sizeof(virtres_t), PU_LEVEL, NULL); vres->vlumps = vlumps; vres->numlumps = numlumps; + return vres; } @@ -1961,12 +1962,14 @@ void vres_Free (virtres_t* vres) /** (Debug) Prints lumps from a virtual resource into console. */ +/* static void vres_Diag (const virtres_t* vres) { UINT32 i; for (i = 0; i < vres->numlumps; i++) CONS_Printf("%s\n", vres->vlumps[i].name); } +*/ /** \brief Finds a lump in a given virtual resource. * From 9340557d2de00ecdd8d3c4604ff92206c852a986 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 11 Dec 2019 13:09:27 -0300 Subject: [PATCH 033/195] Update f_wipe.c --- src/f_wipe.c | 152 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 121 insertions(+), 31 deletions(-) diff --git a/src/f_wipe.c b/src/f_wipe.c index 829bceae0..fc6fc6b6d 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -282,7 +282,7 @@ static void F_DoWipe(fademask_t *fademask) relativepos += vid.width; } } - else if (*mask >= ((wipestyle == WIPESTYLE_COLORMAP) ? FADECOLORMAPROWS : 10)) + else if (*mask >= 10) { // shortcut - memcpy target to work while (draw_linestogo--) @@ -293,25 +293,8 @@ static void F_DoWipe(fademask_t *fademask) } else { - if (wipestyle == WIPESTYLE_COLORMAP) - { - int nmask; - UINT8 *fade = fadecolormap; - - if (wipestyleflags & WSF_TOWHITE) - fade = fadecolormap + (FADECOLORMAPROWS * 256); - - nmask = *mask; - if (wipestyleflags & WSF_FADEIN) - nmask = (FADECOLORMAPROWS-1) - nmask; - - transtbl = fade + (nmask * 256); - } - else - { - // pointer to transtable that this mask would use - transtbl = transtables + ((9 - *mask)<= fademask->width) + ++masky, maskx = 0; + } while (++mask < maskend); + + free(scrxpos); + free(scrypos); + } +} + +static void F_DoColormapWipe(fademask_t *fademask, UINT8 *colormap) +{ + // Lactozilla: F_DoWipe for WIPESTYLE_COLORMAP + { + // wipe screen, start, end + UINT8 *w = wipe_scr; + const UINT8 *s = wipe_scr_start; + const UINT8 *e = wipe_scr_end; + + // first pixel for each screen + UINT8 *w_base = w; + const UINT8 *s_base = s; + const UINT8 *e_base = e; + + // mask data, end + UINT8 *transtbl; + const UINT8 *mask = fademask->mask; + const UINT8 *maskend = mask + fademask->size; + + // rectangle draw hints + UINT32 draw_linestart, draw_rowstart; + UINT32 draw_lineend, draw_rowend; + UINT32 draw_linestogo, draw_rowstogo; + + // rectangle coordinates, etc. + UINT16* scrxpos = (UINT16*)malloc((fademask->width + 1) * sizeof(UINT16)); + UINT16* scrypos = (UINT16*)malloc((fademask->height + 1) * sizeof(UINT16)); + UINT16 maskx, masky; + UINT32 relativepos; + + // --- + // Screw it, we do the fixed point math ourselves up front. + scrxpos[0] = 0; + for (relativepos = 0, maskx = 1; maskx < fademask->width; ++maskx) + scrxpos[maskx] = (relativepos += fademask->xscale)>>FRACBITS; + scrxpos[fademask->width] = vid.width; + + scrypos[0] = 0; + for (relativepos = 0, masky = 1; masky < fademask->height; ++masky) + scrypos[masky] = (relativepos += fademask->yscale)>>FRACBITS; + scrypos[fademask->height] = vid.height; + // --- + + maskx = masky = 0; + do + { + draw_rowstart = scrxpos[maskx]; + draw_rowend = scrxpos[maskx + 1]; + draw_linestart = scrypos[masky]; + draw_lineend = scrypos[masky + 1]; + + relativepos = (draw_linestart * vid.width) + draw_rowstart; + draw_linestogo = draw_lineend - draw_linestart; + + if (*mask == 0) + { + // shortcut - memcpy source to work + while (draw_linestogo--) + { + M_Memcpy(w_base+relativepos, s_base+relativepos, draw_rowend-draw_rowstart); + relativepos += vid.width; + } + } + else if (*mask >= FADECOLORMAPROWS) + { + // shortcut - memcpy target to work + while (draw_linestogo--) + { + M_Memcpy(w_base+relativepos, e_base+relativepos, draw_rowend-draw_rowstart); + relativepos += vid.width; + } + } + else + { + int nmask = *mask; + if (wipestyleflags & WSF_FADEIN) + nmask = (FADECOLORMAPROWS-1) - nmask; + + transtbl = colormap + (nmask * 256); + + // DRAWING LOOP + while (draw_linestogo--) + { + w = w_base + relativepos; + s = s_base + relativepos; + e = e_base + relativepos; + draw_rowstogo = draw_rowend - draw_rowstart; + + while (draw_rowstogo--) + *w++ = transtbl[*e++]; relativepos += vid.width; } @@ -484,7 +564,17 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu) } else #endif - F_DoWipe(fmask); + { + if (wipestyle == WIPESTYLE_COLORMAP) + { + UINT8 *colormap = fadecolormap; + if (wipestyleflags & WSF_TOWHITE) + colormap += (FADECOLORMAPROWS * 256); + F_DoColormapWipe(fmask, colormap); + } + else + F_DoWipe(fmask); + } if (wipestyle == WIPESTYLE_COLORMAP) F_WipeStageTitle(); From 37679bb44e94779d8ae9c4804030cc77ccfd3ccc Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 11 Dec 2019 13:26:28 -0300 Subject: [PATCH 034/195] Organise --- src/f_wipe.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/f_wipe.c b/src/f_wipe.c index fc6fc6b6d..a83d104f2 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -553,32 +553,40 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu) I_Sleep(); lastwipetic = nowtime; + // Wipe styles + if (wipestyle == WIPESTYLE_COLORMAP) + { #ifdef HWRENDER - if (rendermode == render_opengl) - { - // send in the wipe type and wipe frame because we need to cache the graphic - if (wipestyle == WIPESTYLE_COLORMAP) + if (rendermode == render_opengl) + { + // send in the wipe type and wipe frame because we need to cache the graphic HWR_DoTintedWipe(wipetype, wipeframe-1); + } else - HWR_DoWipe(wipetype, wipeframe-1); - } - else #endif - { - if (wipestyle == WIPESTYLE_COLORMAP) { UINT8 *colormap = fadecolormap; if (wipestyleflags & WSF_TOWHITE) colormap += (FADECOLORMAPROWS * 256); F_DoColormapWipe(fmask, colormap); } + + // Draw the title card above the wipe + F_WipeStageTitle(); + } + else + { +#ifdef HWRENDER + if (rendermode == render_opengl) + { + // send in the wipe type and wipe frame because we need to cache the graphic + HWR_DoWipe(wipetype, wipeframe-1); + } else +#endif F_DoWipe(fmask); } - if (wipestyle == WIPESTYLE_COLORMAP) - F_WipeStageTitle(); - I_OsPolling(); I_UpdateNoBlit(); From e01eb1904488672ee5dd4b73d9590471128a1b29 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 11 Dec 2019 22:11:00 -0300 Subject: [PATCH 035/195] Sad! --- src/r_data.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/r_data.c b/src/r_data.c index e8da4e4d3..a0655e611 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -438,7 +438,6 @@ static UINT8 *R_GenerateTexture(size_t texnum) texpatch_t *patch; patch_t *realpatch; UINT8 *pdata; - boolean dealloc = false; int x, x1, x2, i, width, height; size_t blocksize; column_t *patchcol; From d40359ee02a876efafdec5c77e9122ce166c0e58 Mon Sep 17 00:00:00 2001 From: Tatsuru Date: Wed, 11 Dec 2019 02:07:09 -0300 Subject: [PATCH 036/195] Hugging now requires being in the same Z position Don't try this at home --- src/p_mobj.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index dea4a7a4d..a6812ff01 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7833,7 +7833,8 @@ void P_MobjThinker(mobj_t *mobj) boolean dojump = false, targonground, love, makeheart = false; if (mobj->target != player->mo) P_SetTarget(&mobj->target, player->mo); - targonground = (P_IsObjectOnGround(mobj->target) && (player->panim == PA_IDLE || player->panim == PA_WALK || player->panim == PA_RUN)); + // Tatsuru: Don't try to hug them if they're above or below you! + targonground = (P_IsObjectOnGround(mobj->target) && (player->panim == PA_IDLE || player->panim == PA_WALK || player->panim == PA_RUN) && player->mo->z == mobj->z); love = (player->skin == 0 || player->skin == 5); switch (stat) From 0ff421d0017f3039e698c51452cd01658b7328fb Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 11 Dec 2019 22:10:22 -0800 Subject: [PATCH 037/195] Move I_ShutdownConsole to I_ShutdownSystem --- src/sdl/i_system.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 13fb25bea..03eeb634f 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2169,7 +2169,6 @@ void I_Quit(void) if (quiting) goto death; SDLforceUngrabMouse(); quiting = SDL_FALSE; - I_ShutdownConsole(); M_SaveConfig(NULL); //save game config, cvars.. #ifndef NONET D_SaveBan(); // save the ban list @@ -2287,8 +2286,6 @@ void I_Error(const char *error, ...) I_OutputMsg("\nI_Error(): %s\n", buffer); // --- - I_ShutdownConsole(); - M_SaveConfig(NULL); // save game config, cvars.. #ifndef NONET D_SaveBan(); // save the ban list @@ -2388,6 +2385,8 @@ void I_ShutdownSystem(void) { INT32 c; + I_ShutdownConsole(); + for (c = MAX_QUIT_FUNCS-1; c >= 0; c--) if (quit_funcs[c]) (*quit_funcs[c])(); From 7c383e4a1f75b530d7759178c04d4ecfd7fc2dd1 Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 11 Dec 2019 23:46:57 -0800 Subject: [PATCH 038/195] nix: Fork before game code and wait to catch signals and coredumps Ditched signal_handler to avoid worrying about async-signal-safe functions. D_QuitNetGame is not called, so players whose programs are interrupted by a signal will time out from the server. Because the game runs in a child process, the window can close before the "Signal Caught" text box appears. "(core dumped)" is also included in the message if core dumping could be determined. --- src/doomdef.h | 4 ++++ src/i_system.h | 4 ++++ src/sdl/i_main.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++ src/sdl/i_system.c | 33 +++++++++++++++++++++++------ 4 files changed, 87 insertions(+), 6 deletions(-) diff --git a/src/doomdef.h b/src/doomdef.h index d13ff9bc0..216b4fd90 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -125,6 +125,10 @@ #define LOGMESSAGES // write message in log.txt #endif +#if (defined (__unix__) && !defined (_MSDOS)) || defined (UNIXCOMMON) +#define NEWSIGNALHANDLER +#endif + #ifdef LOGMESSAGES extern FILE *logstream; #endif diff --git a/src/i_system.h b/src/i_system.h index 831acda32..131557ae9 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -84,6 +84,10 @@ ticcmd_t *I_BaseTiccmd2(void); */ void I_Quit(void) FUNCNORETURN; +/** \brief Print a message and text box about a signal that was raised. +*/ +void I_ReportSignal(int num, int coredumped); + typedef enum { EvilForce = -1, diff --git a/src/sdl/i_main.c b/src/sdl/i_main.c index 029febc05..16d0a242c 100644 --- a/src/sdl/i_main.c +++ b/src/sdl/i_main.c @@ -28,6 +28,11 @@ #include "time.h" // For log timestamps +#ifdef NEWSIGNALHANDLER +#include +#include +#endif + #ifdef HAVE_SDL #ifdef HAVE_TTF @@ -181,6 +186,53 @@ int main(int argc, char **argv) #endif MakeCodeWritable(); #endif + +#ifdef NEWSIGNALHANDLER + switch (fork()) + { + case -1: + I_Error( + "Error setting up signal reporting: fork(): %s\n", + strerror(errno) + ); + break; + case 0: + break; + default: + { + int status; + int signum; + if (wait(&status) == -1) + { + I_Error( + "Error setting up signal reporting: fork(): %s\n", + strerror(errno) + ); + } + else + { + if (WIFSIGNALED (status)) + { + signum = WTERMSIG (status); +#ifdef WCOREDUMP + I_ReportSignal(signum, WCOREDUMP (status)); +#else + I_ReportSignal(signum, 0); +#endif + status = 128 + signum; + } + else if (WIFEXITED (status)) + { + status = WEXITSTATUS (status); + } + + I_ShutdownSystem(); + exit(status); + } + } + } +#endif/*NEWSIGNALHANDLER*/ + // startup SRB2 CONS_Printf("Setting up SRB2...\n"); D_SRB2Main(); diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 03eeb634f..e58691de6 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -229,13 +229,11 @@ SDL_bool framebuffer = SDL_FALSE; UINT8 keyboard_started = false; -FUNCNORETURN static ATTRNORETURN void signal_handler(INT32 num) +void I_ReportSignal(int num, int coredumped) { //static char msg[] = "oh no! back to reality!\r\n"; const char * sigmsg; - char sigdef[32]; - - D_QuitNetGame(); // Fix server freezes + char msg[128]; switch (num) { @@ -261,8 +259,21 @@ FUNCNORETURN static ATTRNORETURN void signal_handler(INT32 num) sigmsg = "SIGABRT - abnormal termination triggered by abort call"; break; default: - sprintf(sigdef,"signal number %d", num); - sigmsg = sigdef; + sprintf(msg,"signal number %d", num); + if (coredumped) + sigmsg = 0; + else + sigmsg = msg; + } + + if (coredumped) + { + if (sigmsg) + sprintf(msg, "%s (core dumped)", sigmsg); + else + strcat(msg, " (core dumped)"); + + sigmsg = msg; } I_OutputMsg("\nsignal_handler() error: %s\n", sigmsg); @@ -270,11 +281,19 @@ FUNCNORETURN static ATTRNORETURN void signal_handler(INT32 num) SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Signal caught", sigmsg, NULL); +} + +#ifndef NEWSIGNALHANDLER +FUNCNORETURN static ATTRNORETURN void signal_handler(INT32 num) +{ + D_QuitNetGame(); // Fix server freezes + I_ReportSignal(num, 0); I_ShutdownSystem(); signal(num, SIG_DFL); //default signal action raise(num); I_Quit(); } +#endif FUNCNORETURN static ATTRNORETURN void quit_handler(int num) { @@ -664,10 +683,12 @@ void I_StartupKeyboard (void) // If these defines don't exist, // then compilation would have failed above us... +#ifndef NEWSIGNALHANDLER signal(SIGILL , signal_handler); signal(SIGSEGV , signal_handler); signal(SIGABRT , signal_handler); signal(SIGFPE , signal_handler); +#endif } // From 43cbad200cfb340c4d13ee0b3808570e60c86aa4 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Thu, 12 Dec 2019 10:35:38 +0100 Subject: [PATCH 039/195] Move loading functions around a bit and refactor the stage data allocation code. --- src/p_setup.c | 173 +++++++++++++++++++++++++------------------------- 1 file changed, 87 insertions(+), 86 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index 17909ee58..f569c4b73 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -373,21 +373,11 @@ UINT32 P_GetScoreForGrade(INT16 map, UINT8 mare, UINT8 grade) * \sa ML_VERTEXES */ -static inline void P_LoadRawVertexes(UINT8 *data, size_t i) +static inline void P_LoadRawVertexes(UINT8 *data) { - mapvertex_t *ml; - vertex_t *li; - - numvertexes = i / sizeof (mapvertex_t); - - if (numvertexes <= 0) - I_Error("Level has no vertices"); // instead of crashing - - // Allocate zone memory for buffer. - vertexes = Z_Calloc(numvertexes * sizeof (*vertexes), PU_LEVEL, NULL); - - ml = (mapvertex_t *)data; - li = vertexes; + mapvertex_t *ml = (mapvertex_t *)data; + vertex_t *li = vertexes; + size_t i; // Copy and convert vertex coordinates, internal representation as fixed. for (i = 0; i < numvertexes; i++, li++, ml++) @@ -677,19 +667,12 @@ INT32 P_CheckLevelFlat(const char *flatname) // Sets up the ingame sectors structures. // Lumpnum is the lumpnum of a SECTORS lump. -static void P_LoadRawSectors(UINT8 *data, size_t i) +static void P_LoadRawSectors(UINT8 *data) { - mapsector_t *ms; - sector_t *ss; + mapsector_t *ms = (mapsector_t *)data; + sector_t *ss = sectors; levelflat_t *foundflats; - - // We count how many sectors we got. - numsectors = i / sizeof (mapsector_t); - if (numsectors <= 0) - I_Error("Level has no sectors"); - - // Allocate as much memory as we need into the global sectors table. - sectors = Z_Calloc(numsectors*sizeof (*sectors), PU_LEVEL, NULL); + size_t i; // Allocate a big chunk of memory as big as our MAXLEVELFLATS limit. //Fab : FIXME: allocate for whatever number of flats - 512 different flats per level should be plenty @@ -700,8 +683,6 @@ static void P_LoadRawSectors(UINT8 *data, size_t i) numlevelflats = 0; // For each counted sector, copy the sector raw data from our cache pointer ms, to the global table pointer ss. - ms = (mapsector_t *)data; - ss = sectors; for (i = 0; i < numsectors; i++, ss++, ms++) { ss->floorheight = SHORT(ms->floorheight)<flags = SHORT(mld->flags); ld->special = SHORT(mld->special); ld->tag = SHORT(mld->tag); - v1 = ld->v1 = &vertexes[SHORT(mld->v1)]; - v2 = ld->v2 = &vertexes[SHORT(mld->v2)]; - ld->dx = v2->x - v1->x; - ld->dy = v2->y - v1->y; + ld->v1 = &vertexes[SHORT(mld->v1)]; + ld->v2 = &vertexes[SHORT(mld->v2)]; + + ld->sidenum[0] = SHORT(mld->sidenum[0]); + ld->sidenum[1] = SHORT(mld->sidenum[1]); + } +} + +static void SetupLines (void) +{ + line_t *ld = lines; + size_t i; + + for (i = 0; i < numlines; i++, ld++) + { + vertex_t *v1 = ld->v1; + vertex_t *v2 = ld->v2; #ifdef WALLSPLATS ld->splats = NULL; #endif +#ifdef POLYOBJECTS + ld->polyobj = NULL; +#endif + + ld->dx = v2->x - v1->x; + ld->dy = v2->y - v1->y; + if (!ld->dx) ld->slopetype = ST_VERTICAL; else if (!ld->dy) @@ -1208,52 +1202,43 @@ static void P_LoadRawLineDefs(UINT8 *data, size_t i) ld->bbox[BOXTOP] = v1->y; } - ld->sidenum[0] = SHORT(mld->sidenum[0]); - ld->sidenum[1] = SHORT(mld->sidenum[1]); - { // cph 2006/09/30 - fix sidedef errors right away. // cph 2002/07/20 - these errors are fatal if not fixed, so apply them UINT8 j; for (j=0; j < 2; j++) - { if (ld->sidenum[j] != 0xffff && ld->sidenum[j] >= (UINT16)numsides) { ld->sidenum[j] = 0xffff; CONS_Debug(DBG_SETUP, "P_LoadRawLineDefs: linedef %s has out-of-range sidedef number\n", sizeu1(numlines-i-1)); } - } } ld->frontsector = ld->backsector = NULL; ld->validcount = 0; ld->firsttag = ld->nexttag = -1; ld->callcount = 0; - // killough 11/98: fix common wad errors (missing sidedefs): + // killough 11/98: fix common wad errors (missing sidedefs): if (ld->sidenum[0] == 0xffff) { ld->sidenum[0] = 0; // Substitute dummy sidedef for missing right side // cph - print a warning about the bug - CONS_Debug(DBG_SETUP, "P_LoadRawLineDefs: linedef %s missing first sidedef\n", sizeu1(numlines-i-1)); + CONS_Debug(DBG_SETUP, "Linedef %s missing first sidedef\n", sizeu1(numlines-i-1)); } if ((ld->sidenum[1] == 0xffff) && (ld->flags & ML_TWOSIDED)) { ld->flags &= ~ML_TWOSIDED; // Clear 2s flag for missing left side // cph - print a warning about the bug - CONS_Debug(DBG_SETUP, "P_LoadRawLineDefs: linedef %s has two-sided flag set, but no second sidedef\n", sizeu1(numlines-i-1)); + CONS_Debug(DBG_SETUP, "Linedef %s has two-sided flag set, but no second sidedef\n", sizeu1(numlines-i-1)); } if (ld->sidenum[0] != 0xffff && ld->special) sides[ld->sidenum[0]].special = ld->special; if (ld->sidenum[1] != 0xffff && ld->special) sides[ld->sidenum[1]].special = ld->special; - -#ifdef POLYOBJECTS - ld->polyobj = NULL; -#endif } } @@ -1359,16 +1344,6 @@ static void P_LoadLineDefs2(void) } } - - -static inline void P_LoadRawSideDefs(size_t i) -{ - numsides = i / sizeof (mapsidedef_t); - if (numsides <= 0) - I_Error("Level has no sidedefs"); - sides = Z_Calloc(numsides * sizeof (*sides), PU_LEVEL, NULL); -} - static void P_LoadRawSideDefs2(void *data) { UINT16 i; @@ -2697,6 +2672,23 @@ boolean P_SetupLevel(boolean skipprecip) // SRB2 determines the sky texture to be used depending on the map header. P_SetupLevelSky(mapheaderinfo[gamemap-1]->skynum, true); + numdmstarts = numredctfstarts = numbluectfstarts = 0; + + // reset the player starts + for (i = 0; i < MAXPLAYERS; i++) + playerstarts[i] = bluectfstarts[i] = redctfstarts[i] = NULL; + + for (i = 0; i < MAX_DM_STARTS; i++) + deathmatchstarts[i] = NULL; + + for (i = 0; i < 2; i++) + skyboxmo[i] = NULL; + + for (i = 0; i < 16; i++) + skyboxviewpnts[i] = skyboxcenterpnts[i] = NULL; + + P_MapStart(); + if (lastloadedmaplumpnum) { virtres_t* virt = vres_GetMap(lastloadedmaplumpnum); @@ -2713,17 +2705,41 @@ boolean P_SetupLevel(boolean skipprecip) virtlump_t* virtblockmap = vres_Find(virt, "BLOCKMAP"); virtlump_t* virtreject = vres_Find(virt, "REJECT"); - P_MakeMapMD5(virt, &mapmd5); + // Traditional doom map format just assumes the number of elements from the lump sixes. + numvertexes = virtvertexes->size / sizeof (mapvertex_t); + numsectors = virtsectors->size / sizeof (mapsector_t); + numsides = virtsidedefs->size / sizeof (mapsidedef_t); + numlines = virtlinedefs->size / sizeof (maplinedef_t); + nummapthings = virtthings->size / (5 * sizeof (INT16)); - P_LoadRawVertexes(virtvertexes->data, virtvertexes->size); - P_LoadRawSectors(virtsectors->data, virtsectors->size); - P_LoadRawSideDefs(virtsidedefs->size); - P_LoadRawLineDefs(virtlinedefs->data, virtlinedefs->size); + if (numvertexes <= 0) + I_Error("Level has no vertices"); + if (numsectors <= 0) + I_Error("Level has no sectors"); + if (numsides <= 0) + I_Error("Level has no sidedefs"); + if (numlines <= 0) + I_Error("Level has no linedefs"); + + vertexes = Z_Calloc(numvertexes * sizeof (*vertexes), PU_LEVEL, NULL); + sectors = Z_Calloc(numsectors * sizeof (*sectors), PU_LEVEL, NULL); + sides = Z_Calloc(numsides * sizeof (*sides), PU_LEVEL, NULL); + lines = Z_Calloc(numlines * sizeof (*lines), PU_LEVEL, NULL); + mapthings= Z_Calloc(nummapthings * sizeof (*mapthings), PU_LEVEL, NULL); + + // Strict map data + P_LoadRawVertexes(virtvertexes->data); + P_LoadRawSectors(virtsectors->data); + P_LoadRawLineDefs(virtlinedefs->data); + SetupLines(); P_LoadRawSideDefs2(virtsidedefs->data); + + // Nodes P_LoadRawSubsectors(virtssectors->data, virtssectors->size); P_LoadRawNodes(virtnodes->data, virtnodes->size); P_LoadRawSegs(virtsegs->data, virtsegs->size); + // Lookup tables if (virtreject) P_LoadRawReject(virtreject->data, virtreject->size); else @@ -2735,25 +2751,10 @@ boolean P_SetupLevel(boolean skipprecip) P_LoadLineDefs2(); P_GroupLines(); - numdmstarts = numredctfstarts = numbluectfstarts = 0; - - // reset the player starts - for (i = 0; i < MAXPLAYERS; i++) - playerstarts[i] = bluectfstarts[i] = redctfstarts[i] = NULL; - - for (i = 0; i < MAX_DM_STARTS; i++) - deathmatchstarts[i] = NULL; - - for (i = 0; i < 2; i++) - skyboxmo[i] = NULL; - - for (i = 0; i < 16; i++) - skyboxviewpnts[i] = skyboxcenterpnts[i] = NULL; - - P_MapStart(); - P_PrepareRawThings(virtthings->data, virtthings->size); + P_MakeMapMD5(virt, &mapmd5); + vres_Free(virt); } From ec9f727e531ca11b735bcee2fc390af8e9080e0b Mon Sep 17 00:00:00 2001 From: Nev3r Date: Thu, 12 Dec 2019 11:16:55 +0100 Subject: [PATCH 040/195] Move map data load procedure to separate functions. --- src/p_setup.c | 161 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 98 insertions(+), 63 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index f569c4b73..0430ab997 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -951,16 +951,13 @@ void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum) } #endif -static void P_PrepareRawThings(UINT8 *data, size_t i) +static void P_PrepareRawThings(UINT8 *data) { - mapthing_t *mt; - - nummapthings = i / (5 * sizeof (INT16)); - mapthings = Z_Calloc(nummapthings * sizeof (*mapthings), PU_LEVEL, NULL); + mapthing_t *mt = mapthings; + size_t i; // Spawn axis points first so they are // at the front of the list for fast searching. - mt = mapthings; for (i = 0; i < nummapthings; i++, mt++) { mt->x = READINT16(data); @@ -1936,6 +1933,97 @@ static void P_LoadRawReject(UINT8 *data, size_t count) } } +static void LoadMapBSP (const virtres_t* virt) +{ + virtlump_t* virtssectors = vres_Find(virt, "SSECTORS"); + virtlump_t* virtsegs = vres_Find(virt, "SEGS"); + virtlump_t* virtnodes = vres_Find(virt, "NODES"); + + // Nodes + P_LoadRawSubsectors(virtssectors->data, virtssectors->size); + P_LoadRawNodes(virtnodes->data, virtnodes->size); + P_LoadRawSegs(virtsegs->data, virtsegs->size); +} + +static void LoadMapLUT (const virtres_t* virt) +{ + virtlump_t* virtblockmap = vres_Find(virt, "BLOCKMAP"); + virtlump_t* virtreject = vres_Find(virt, "REJECT"); + + // Lookup tables + if (virtreject) + P_LoadRawReject(virtreject->data, virtreject->size); + else + rejectmatrix = NULL; + + if (!(virtblockmap && P_LoadRawBlockMap(virtblockmap->data, virtblockmap->size))) + P_CreateBlockMap(); +} + +static void LoadMapData (const virtres_t* virt) +{ + virtlump_t* virtvertexes = NULL, * virtsectors = NULL, * virtsidedefs = NULL, * virtlinedefs = NULL, * virtthings = NULL; + virtlump_t* textmap = vres_Find(virt, "TEXTMAP"); + + // Count map data. + if (textmap) + { + nummapthings = 0; + numlines = 0; + numsides = 0; + numvertexes = 0; + numsectors = 0; + + // Count how many entries for each type we got in textmap. + //TextmapCount(vtextmap->data, vtextmap->size); + } + else + { + virtthings = vres_Find(virt, "THINGS"); + virtvertexes = vres_Find(virt, "VERTEXES"); + virtsectors = vres_Find(virt, "SECTORS"); + virtsidedefs = vres_Find(virt, "SIDEDEFS"); + virtlinedefs = vres_Find(virt, "LINEDEFS"); + + // Traditional doom map format just assumes the number of elements from the lump sixes. + numvertexes = virtvertexes->size / sizeof (mapvertex_t); + numsectors = virtsectors->size / sizeof (mapsector_t); + numsides = virtsidedefs->size / sizeof (mapsidedef_t); + numlines = virtlinedefs->size / sizeof (maplinedef_t); + nummapthings = virtthings->size / (5 * sizeof (INT16)); + } + + if (numvertexes <= 0) + I_Error("Level has no vertices"); + if (numsectors <= 0) + I_Error("Level has no sectors"); + if (numsides <= 0) + I_Error("Level has no sidedefs"); + if (numlines <= 0) + I_Error("Level has no linedefs"); + + vertexes = Z_Calloc(numvertexes * sizeof (*vertexes), PU_LEVEL, NULL); + sectors = Z_Calloc(numsectors * sizeof (*sectors), PU_LEVEL, NULL); + sides = Z_Calloc(numsides * sizeof (*sides), PU_LEVEL, NULL); + lines = Z_Calloc(numlines * sizeof (*lines), PU_LEVEL, NULL); + mapthings= Z_Calloc(nummapthings * sizeof (*mapthings), PU_LEVEL, NULL); + + if (textmap) + { + + } + else + { + // Strict map data + P_LoadRawVertexes(virtvertexes->data); + P_LoadRawSectors(virtsectors->data); + P_LoadRawLineDefs(virtlinedefs->data); + SetupLines(); + P_LoadRawSideDefs2(virtsidedefs->data); + P_PrepareRawThings(virtthings->data); + } +} + #if 0 static char *levellumps[] = { @@ -2133,7 +2221,7 @@ void P_LoadThingsOnly(void) P_LevelInitStuff(); - P_PrepareRawThings(vth->data, vth->size); + P_PrepareRawThings(vth->data); P_LoadThings(true); vres_Free(virt); @@ -2692,67 +2780,14 @@ boolean P_SetupLevel(boolean skipprecip) if (lastloadedmaplumpnum) { virtres_t* virt = vres_GetMap(lastloadedmaplumpnum); - virtlump_t* virtthings = vres_Find(virt, "THINGS"); - virtlump_t* virtvertexes = vres_Find(virt, "VERTEXES"); - virtlump_t* virtsectors = vres_Find(virt, "SECTORS"); - virtlump_t* virtsidedefs = vres_Find(virt, "SIDEDEFS"); - virtlump_t* virtlinedefs = vres_Find(virt, "LINEDEFS"); - virtlump_t* virtssectors = vres_Find(virt, "SSECTORS"); - virtlump_t* virtsegs = vres_Find(virt, "SEGS"); - virtlump_t* virtnodes = vres_Find(virt, "NODES"); - - virtlump_t* virtblockmap = vres_Find(virt, "BLOCKMAP"); - virtlump_t* virtreject = vres_Find(virt, "REJECT"); - - // Traditional doom map format just assumes the number of elements from the lump sixes. - numvertexes = virtvertexes->size / sizeof (mapvertex_t); - numsectors = virtsectors->size / sizeof (mapsector_t); - numsides = virtsidedefs->size / sizeof (mapsidedef_t); - numlines = virtlinedefs->size / sizeof (maplinedef_t); - nummapthings = virtthings->size / (5 * sizeof (INT16)); - - if (numvertexes <= 0) - I_Error("Level has no vertices"); - if (numsectors <= 0) - I_Error("Level has no sectors"); - if (numsides <= 0) - I_Error("Level has no sidedefs"); - if (numlines <= 0) - I_Error("Level has no linedefs"); - - vertexes = Z_Calloc(numvertexes * sizeof (*vertexes), PU_LEVEL, NULL); - sectors = Z_Calloc(numsectors * sizeof (*sectors), PU_LEVEL, NULL); - sides = Z_Calloc(numsides * sizeof (*sides), PU_LEVEL, NULL); - lines = Z_Calloc(numlines * sizeof (*lines), PU_LEVEL, NULL); - mapthings= Z_Calloc(nummapthings * sizeof (*mapthings), PU_LEVEL, NULL); - - // Strict map data - P_LoadRawVertexes(virtvertexes->data); - P_LoadRawSectors(virtsectors->data); - P_LoadRawLineDefs(virtlinedefs->data); - SetupLines(); - P_LoadRawSideDefs2(virtsidedefs->data); - - // Nodes - P_LoadRawSubsectors(virtssectors->data, virtssectors->size); - P_LoadRawNodes(virtnodes->data, virtnodes->size); - P_LoadRawSegs(virtsegs->data, virtsegs->size); - - // Lookup tables - if (virtreject) - P_LoadRawReject(virtreject->data, virtreject->size); - else - rejectmatrix = NULL; - - if (!(virtblockmap && P_LoadRawBlockMap(virtblockmap->data, virtblockmap->size))) - P_CreateBlockMap(); + LoadMapData(virt); + LoadMapBSP(virt); + LoadMapLUT(virt); P_LoadLineDefs2(); P_GroupLines(); - P_PrepareRawThings(virtthings->data, virtthings->size); - P_MakeMapMD5(virt, &mapmd5); vres_Free(virt); From c64a9d7ae9d0d3756c348397c00b5e8460c504a0 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Thu, 12 Dec 2019 11:37:48 +0100 Subject: [PATCH 041/195] Stop things from becoming Chocapic in THZ3, ACZ2, and special stages. Temporarily revert function call order for mapthings. --- src/p_setup.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/p_setup.c b/src/p_setup.c index 0430ab997..cc53f2d3d 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1963,6 +1963,7 @@ static void LoadMapLUT (const virtres_t* virt) static void LoadMapData (const virtres_t* virt) { virtlump_t* virtvertexes = NULL, * virtsectors = NULL, * virtsidedefs = NULL, * virtlinedefs = NULL, * virtthings = NULL; +#ifdef UDMF virtlump_t* textmap = vres_Find(virt, "TEXTMAP"); // Count map data. @@ -1978,6 +1979,7 @@ static void LoadMapData (const virtres_t* virt) //TextmapCount(vtextmap->data, vtextmap->size); } else +#endif { virtthings = vres_Find(virt, "THINGS"); virtvertexes = vres_Find(virt, "VERTEXES"); @@ -2008,11 +2010,13 @@ static void LoadMapData (const virtres_t* virt) lines = Z_Calloc(numlines * sizeof (*lines), PU_LEVEL, NULL); mapthings= Z_Calloc(nummapthings * sizeof (*mapthings), PU_LEVEL, NULL); +#ifdef UDMF if (textmap) { } else +#endif { // Strict map data P_LoadRawVertexes(virtvertexes->data); @@ -2020,7 +2024,6 @@ static void LoadMapData (const virtres_t* virt) P_LoadRawLineDefs(virtlinedefs->data); SetupLines(); P_LoadRawSideDefs2(virtsidedefs->data); - P_PrepareRawThings(virtthings->data); } } @@ -2788,6 +2791,8 @@ boolean P_SetupLevel(boolean skipprecip) P_LoadLineDefs2(); P_GroupLines(); + P_PrepareRawThings(vres_Find(virt, "THINGS")->data); + P_MakeMapMD5(virt, &mapmd5); vres_Free(virt); From c5d8fe47527c9cd1c4d354b8f730f7be5bd3350e Mon Sep 17 00:00:00 2001 From: Nev3r Date: Thu, 12 Dec 2019 15:04:48 +0100 Subject: [PATCH 042/195] Fix oversight on mapthing spawn Z calculation; ONFLOORZ and ONCEILINGZ don't equal to spawning the object at the base plane intersection. --- src/p_mobj.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index dae891afd..ed12407ff 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11609,6 +11609,14 @@ static fixed_t GetMobjSpawnHeight (const mobjtype_t i, const mapthing_t* mthing, flip = (!!(mobjinfo[i].flags & MF_SPAWNCEILING) ^ !!(mthing->options & MTF_OBJECTFLIP)); } + if (heightoffset + extraoffset == 0) // Snap to the surfaces when there's no offset set. + { + if (flip) + return ONCEILINGZ; + else + return ONFLOORZ; + } + // Establish height. if (flip) return ( From 4af0cfae36bb7bb3a61451d4635bb91a515c4c4c Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Thu, 12 Dec 2019 15:17:50 -0500 Subject: [PATCH 043/195] Init MUSICDEFs if started game with music off and toggled on --- src/s_sound.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/s_sound.c b/src/s_sound.c index a49499040..1d9c06cca 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -2543,6 +2543,7 @@ void GameDigiMusic_OnChange(void) I_StartupSound(); // will return early if initialised I_InitMusic(); S_StopMusic(); + S_InitMusicDefs(); if (Playing()) P_RestoreMusic(&players[consoleplayer]); else @@ -2585,6 +2586,7 @@ void GameMIDIMusic_OnChange(void) midi_disabled = false; I_StartupSound(); // will return early if initialised I_InitMusic(); + S_InitMusicDefs(); if (Playing()) P_RestoreMusic(&players[consoleplayer]); else From eb787c2b59ef6391bb4db8c25b514f9ab972f342 Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Thu, 12 Dec 2019 16:32:40 -0500 Subject: [PATCH 044/195] Move S_InitMusicDefs call outside of the check. As far as I know, this is competely safe. --- src/d_main.c | 3 ++- src/s_sound.c | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 397406293..ae2750da8 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1281,9 +1281,10 @@ void D_SRB2Main(void) I_StartupSound(); I_InitMusic(); S_InitSfxChannels(cv_soundvolume.value); - S_InitMusicDefs(); } + S_InitMusicDefs(); + CONS_Printf("ST_Init(): Init status bar.\n"); ST_Init(); diff --git a/src/s_sound.c b/src/s_sound.c index 1d9c06cca..a49499040 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -2543,7 +2543,6 @@ void GameDigiMusic_OnChange(void) I_StartupSound(); // will return early if initialised I_InitMusic(); S_StopMusic(); - S_InitMusicDefs(); if (Playing()) P_RestoreMusic(&players[consoleplayer]); else @@ -2586,7 +2585,6 @@ void GameMIDIMusic_OnChange(void) midi_disabled = false; I_StartupSound(); // will return early if initialised I_InitMusic(); - S_InitMusicDefs(); if (Playing()) P_RestoreMusic(&players[consoleplayer]); else From 6dcdb8d95179cc6efd67c70ec63232816e18d10c Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 12 Dec 2019 15:07:59 -0800 Subject: [PATCH 045/195] Move everything to i_system.c This also simplifies things; SDL isn't initialized in the parent process. --- src/doomdef.h | 4 ---- src/i_system.h | 4 ---- src/sdl/i_main.c | 51 ---------------------------------------- src/sdl/i_system.c | 58 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 57 insertions(+), 60 deletions(-) diff --git a/src/doomdef.h b/src/doomdef.h index 216b4fd90..d13ff9bc0 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -125,10 +125,6 @@ #define LOGMESSAGES // write message in log.txt #endif -#if (defined (__unix__) && !defined (_MSDOS)) || defined (UNIXCOMMON) -#define NEWSIGNALHANDLER -#endif - #ifdef LOGMESSAGES extern FILE *logstream; #endif diff --git a/src/i_system.h b/src/i_system.h index 131557ae9..831acda32 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -84,10 +84,6 @@ ticcmd_t *I_BaseTiccmd2(void); */ void I_Quit(void) FUNCNORETURN; -/** \brief Print a message and text box about a signal that was raised. -*/ -void I_ReportSignal(int num, int coredumped); - typedef enum { EvilForce = -1, diff --git a/src/sdl/i_main.c b/src/sdl/i_main.c index 16d0a242c..69e49b4a7 100644 --- a/src/sdl/i_main.c +++ b/src/sdl/i_main.c @@ -28,11 +28,6 @@ #include "time.h" // For log timestamps -#ifdef NEWSIGNALHANDLER -#include -#include -#endif - #ifdef HAVE_SDL #ifdef HAVE_TTF @@ -187,52 +182,6 @@ int main(int argc, char **argv) MakeCodeWritable(); #endif -#ifdef NEWSIGNALHANDLER - switch (fork()) - { - case -1: - I_Error( - "Error setting up signal reporting: fork(): %s\n", - strerror(errno) - ); - break; - case 0: - break; - default: - { - int status; - int signum; - if (wait(&status) == -1) - { - I_Error( - "Error setting up signal reporting: fork(): %s\n", - strerror(errno) - ); - } - else - { - if (WIFSIGNALED (status)) - { - signum = WTERMSIG (status); -#ifdef WCOREDUMP - I_ReportSignal(signum, WCOREDUMP (status)); -#else - I_ReportSignal(signum, 0); -#endif - status = 128 + signum; - } - else if (WIFEXITED (status)) - { - status = WEXITSTATUS (status); - } - - I_ShutdownSystem(); - exit(status); - } - } - } -#endif/*NEWSIGNALHANDLER*/ - // startup SRB2 CONS_Printf("Setting up SRB2...\n"); D_SRB2Main(); diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index e58691de6..9245673cc 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -102,6 +102,12 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T); #endif #endif +#if (defined (__unix__) && !defined (_MSDOS)) || defined (UNIXCOMMON) +#include +#include +#define NEWSIGNALHANDLER +#endif + #ifndef NOMUMBLE #ifdef __linux__ // need -lrt #include @@ -229,7 +235,7 @@ SDL_bool framebuffer = SDL_FALSE; UINT8 keyboard_started = false; -void I_ReportSignal(int num, int coredumped) +static void I_ReportSignal(int num, int coredumped) { //static char msg[] = "oh no! back to reality!\r\n"; const char * sigmsg; @@ -2160,6 +2166,53 @@ void I_Sleep(void) SDL_Delay(cv_sleep.value); } +#ifdef NEWSIGNALHANDLER +static void I_Fork(void) +{ + int status; + int signum; + switch (fork()) + { + case -1: + I_Error( + "Error setting up signal reporting: fork(): %s\n", + strerror(errno) + ); + break; + case 0: + break; + default: + if (wait(&status)) + { + I_Error( + "Error setting up signal reporting: fork(): %s\n", + strerror(errno) + ); + } + else + { + if (WIFSIGNALED (status)) + { + signum = WTERMSIG (status); +#ifdef WCOREDUMP + I_ReportSignal(signum, WCOREDUMP (status)); +#else + I_ReportSignal(signum, 0); +#endif + status = 128 + signum; + } + else if (WIFEXITED (status)) + { + status = WEXITSTATUS (status); + } + + I_ShutdownSystem(); + exit(status); + } + } +} +#endif/*NEWSIGNALHANDLER*/ + INT32 I_StartupSystem(void) { SDL_version SDLcompiled; @@ -2167,6 +2220,9 @@ INT32 I_StartupSystem(void) SDL_VERSION(&SDLcompiled) SDL_GetVersion(&SDLlinked); I_StartupConsole(); +#ifdef NEWSIGNALHANDLER + I_Fork(); +#endif I_OutputMsg("Compiled for SDL version: %d.%d.%d\n", SDLcompiled.major, SDLcompiled.minor, SDLcompiled.patch); I_OutputMsg("Linked with SDL version: %d.%d.%d\n", From f34886850ff59c51b2b70afeee755bf4e378a500 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 12 Dec 2019 21:20:51 -0800 Subject: [PATCH 046/195] Fix idiot mistake --- src/sdl/i_system.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 9245673cc..c3b469bca 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2182,7 +2182,7 @@ static void I_Fork(void) case 0: break; default: - if (wait(&status)) + if (wait(&status) == -1) { I_Error( "Error setting up signal reporting: fork(): %s\n", From 72ee91702cf7cec3a2076cb73e19835104dcc41d Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 12 Dec 2019 21:21:25 -0800 Subject: [PATCH 047/195] Kill child when wait fails, so I_Error exits both --- src/sdl/i_system.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index c3b469bca..7d1405268 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2169,9 +2169,13 @@ void I_Sleep(void) #ifdef NEWSIGNALHANDLER static void I_Fork(void) { + int child; int status; int signum; - switch (fork()) + + child = fork(); + + switch (child) { case -1: I_Error( @@ -2184,6 +2188,7 @@ static void I_Fork(void) default: if (wait(&status) == -1) { + kill(child, SIGKILL); I_Error( "Error setting up signal reporting: fork(): %s\n", strerror(errno) From 35053adfb2fdb5cf224b5170dd9fa1ee57413723 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 12 Dec 2019 21:30:35 -0800 Subject: [PATCH 048/195] Rename I_StartupKeyboard to I_RegisterSignals and call it in a sane place --- src/d_main.c | 3 --- src/i_system.h | 4 ---- src/sdl/i_system.c | 3 ++- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 397406293..00647048d 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -562,9 +562,6 @@ void D_SRB2Loop(void) // Pushing of + parameters is now done back in D_SRB2Main, not here. - CONS_Printf("I_StartupKeyboard()...\n"); - I_StartupKeyboard(); - #ifdef _WINDOWS CONS_Printf("I_StartupMouse()...\n"); I_DoStartupMouse(); diff --git a/src/i_system.h b/src/i_system.h index 831acda32..2532ba0ee 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -184,10 +184,6 @@ void I_StartupMouse(void); */ void I_StartupMouse2(void); -/** \brief keyboard startup, shutdown, handler -*/ -void I_StartupKeyboard(void); - /** \brief setup timer irq and user timer routine. */ void I_StartupTimer(void); diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 7d1405268..95745497c 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -675,7 +675,7 @@ static inline void I_ShutdownConsole(void){} // // StartupKeyboard // -void I_StartupKeyboard (void) +void I_RegisterSignals (void) { #ifdef SIGINT signal(SIGINT , quit_handler); @@ -2228,6 +2228,7 @@ INT32 I_StartupSystem(void) #ifdef NEWSIGNALHANDLER I_Fork(); #endif + I_RegisterSignals(); I_OutputMsg("Compiled for SDL version: %d.%d.%d\n", SDLcompiled.major, SDLcompiled.minor, SDLcompiled.patch); I_OutputMsg("Linked with SDL version: %d.%d.%d\n", From 838850ffc1a240a1a1381f4b297995d49dcd0ddc Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 12 Dec 2019 21:57:54 -0800 Subject: [PATCH 049/195] Fix signal handler setup error reporting --- src/sdl/i_system.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 95745497c..4bed8e7f2 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2167,6 +2167,26 @@ void I_Sleep(void) } #ifdef NEWSIGNALHANDLER +static void newsignalhandler_Warn(const char *pr) +{ + char text[128]; + + snprintf(text, sizeof text, + "Error while setting up signal reporting: %s: %s", + pr, + strerror(errno) + ); + + I_OutputMsg("%s\n", text); + + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, + "Startup error", + text, NULL); + + I_ShutdownConsole(); + exit(-1); +} + static void I_Fork(void) { int child; @@ -2178,10 +2198,7 @@ static void I_Fork(void) switch (child) { case -1: - I_Error( - "Error setting up signal reporting: fork(): %s\n", - strerror(errno) - ); + newsignalhandler_Warn("fork()"); break; case 0: break; @@ -2189,10 +2206,7 @@ static void I_Fork(void) if (wait(&status) == -1) { kill(child, SIGKILL); - I_Error( - "Error setting up signal reporting: fork(): %s\n", - strerror(errno) - ); + newsignalhandler_Warn("wait()"); } else { @@ -2211,7 +2225,7 @@ static void I_Fork(void) status = WEXITSTATUS (status); } - I_ShutdownSystem(); + I_ShutdownConsole(); exit(status); } } @@ -2468,8 +2482,6 @@ void I_ShutdownSystem(void) { INT32 c; - I_ShutdownConsole(); - for (c = MAX_QUIT_FUNCS-1; c >= 0; c--) if (quit_funcs[c]) (*quit_funcs[c])(); From 8bea7f6dbc87f29239286644627167cb516bc9d4 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 12 Dec 2019 22:01:16 -0800 Subject: [PATCH 050/195] Rename signal caught message to be more obvious --- src/sdl/i_system.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 4bed8e7f2..a28fadc02 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -282,10 +282,10 @@ static void I_ReportSignal(int num, int coredumped) sigmsg = msg; } - I_OutputMsg("\nsignal_handler() error: %s\n", sigmsg); + I_OutputMsg("\nProcess killed by signal: %s\n\n", sigmsg); SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, - "Signal caught", + "Process killed by signal", sigmsg, NULL); } From ad776e560c18644d8dadde16aac0dd98fa962633 Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Fri, 13 Dec 2019 16:36:33 -0500 Subject: [PATCH 051/195] Rework G_SetCustomExitVars to allow skipstats 2 --- src/lua_baselib.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index b68d16c2a..018529722 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -2664,23 +2664,17 @@ static int lib_gSetCustomExitVars(lua_State *L) // Supported: // G_SetCustomExitVars(); [reset to defaults] // G_SetCustomExitVars(int) [nextmap override only] - // G_SetCustomExitVars(bool) [skipstats only] - // G_SetCustomExitVars(int, bool) [both of the above] + // G_SetCustomExitVars(nil, int) [skipstats only] + // G_SetCustomExitVars(int, int) [both of the above] + + nextmapoverride = 0; + skipstats = 0; + if (n >= 1) { - if (lua_isnumber(L, 1) || n >= 2) - { - nextmapoverride = (INT16)luaL_checknumber(L, 1); - lua_remove(L, 1); // remove nextmapoverride; skipstats now 1 if available - } - skipstats = luaL_optinteger(L, 2, 0); + nextmapoverride = (INT16)luaL_optinteger(L, 1, 0); + skipstats = (INT16)luaL_optinteger(L, 2, 0); } - else - { - nextmapoverride = 0; - skipstats = 0; - } - // --- return 0; } From 553ad46c74cd99b77300589ec9a592370b80441e Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 13 Dec 2019 15:04:31 -0800 Subject: [PATCH 052/195] Add this back for Windoodoo because I'm an idiot --- src/sdl/i_system.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index a28fadc02..effdec8e2 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2482,6 +2482,10 @@ void I_ShutdownSystem(void) { INT32 c; +#ifndef NEWSIGNALHANDLER + I_ShutdownConsole(); +#endif + for (c = MAX_QUIT_FUNCS-1; c >= 0; c--) if (quit_funcs[c]) (*quit_funcs[c])(); From 8a23ff0bc857d93eb9c7218f6a957fc8f4db6335 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 13 Dec 2019 16:51:49 -0800 Subject: [PATCH 053/195] Handle log file in parent properly --- src/doomdef.h | 1 + src/sdl/i_main.c | 12 +++++++----- src/sdl/i_system.c | 15 ++++++++++++++- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/doomdef.h b/src/doomdef.h index d13ff9bc0..b2be062c3 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -127,6 +127,7 @@ #ifdef LOGMESSAGES extern FILE *logstream; +extern char logfilename[1024]; #endif //#define DEVELOP // Disable this for release builds to remove excessive cheat commands and enable MD5 checking and stuff, all in one go. :3 diff --git a/src/sdl/i_main.c b/src/sdl/i_main.c index 69e49b4a7..d0830396f 100644 --- a/src/sdl/i_main.c +++ b/src/sdl/i_main.c @@ -47,6 +47,7 @@ extern int SDL_main(int argc, char *argv[]); #ifdef LOGMESSAGES FILE *logstream = NULL; +char logfilename[1024]; #endif #ifndef DOXYGEN @@ -116,7 +117,6 @@ int main(int argc, char **argv) #endif { const char *logdir = NULL; - char logfile[MAX_WADPATH]; myargc = argc; myargv = argv; /// \todo pull out path to exe from this string @@ -141,7 +141,7 @@ int main(int argc, char **argv) timeinfo = localtime(&my_time); strftime(buf, 26, "%Y-%m-%d %H-%M-%S", timeinfo); - strcpy(logfile, va("log-%s.txt", buf)); + strcpy(logfilename, va("log-%s.txt", buf)); #ifdef DEFAULTDIR if (logdir) @@ -149,14 +149,16 @@ int main(int argc, char **argv) // Create dirs here because D_SRB2Main() is too late. I_mkdir(va("%s%s"DEFAULTDIR, logdir, PATHSEP), 0755); I_mkdir(va("%s%s"DEFAULTDIR"%slogs",logdir, PATHSEP, PATHSEP), 0755); - logstream = fopen(va("%s%s"DEFAULTDIR"%slogs%s%s",logdir, PATHSEP, PATHSEP, PATHSEP, logfile), "wt"); + strcpy(logfilename, va("%s%s"DEFAULTDIR"%slogs%s%s",logdir, PATHSEP, PATHSEP, PATHSEP, logfilename)); } else #endif { I_mkdir("."PATHSEP"logs"PATHSEP, 0755); - logstream = fopen(va("."PATHSEP"logs"PATHSEP"%s", logfile), "wt"); + strcpy(logfilename, va("."PATHSEP"logs"PATHSEP"%s", logfilename)); } + + logstream = fopen(logfilename, "wt"); } #endif @@ -187,7 +189,7 @@ int main(int argc, char **argv) D_SRB2Main(); #ifdef LOGMESSAGES if (!M_CheckParm("-nolog")) - CONS_Printf("Logfile: %s\n", logfile); + CONS_Printf("Logfile: %s\n", logfilename); #endif CONS_Printf("Entering main game loop...\n"); // never return diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index effdec8e2..a5e536bf5 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2192,6 +2192,7 @@ static void I_Fork(void) int child; int status; int signum; + int c; child = fork(); @@ -2203,7 +2204,19 @@ static void I_Fork(void) case 0: break; default: - if (wait(&status) == -1) + if (logstream) + fclose(logstream);/* the child has this */ + + c = wait(&status); + +#ifdef LOGMESSAGES + /* By the way, exit closes files. */ + logstream = fopen(logfilename, "at"); +#else + logstream = 0; +#endif + + if (c == -1) { kill(child, SIGKILL); newsignalhandler_Warn("wait()"); From bcfd9fe504464c8186e4c1ca2d83e5b3bb44d8d3 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Sun, 15 Dec 2019 00:22:17 +0100 Subject: [PATCH 054/195] Cleaned up GetMobjSpawnHeight a bit. Ring-likes no longer ignore MF_SPAWNCEILING, because why should they? --- src/p_mobj.c | 48 +++++++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index ed12407ff..9af9f8791 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11551,18 +11551,16 @@ mapthing_t *huntemeralds[MAXHUNTEMERALDS]; INT32 numhuntemeralds; -static fixed_t GetMobjSpawnHeight (const mobjtype_t i, const mapthing_t* mthing, const fixed_t x, const fixed_t y) +static fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mthing, const fixed_t x, const fixed_t y) { - subsector_t *ss = R_PointInSubsector(x, y); - fixed_t extraoffset = 0; - fixed_t heightoffset = 0; - boolean flip; + const subsector_t *ss = R_PointInSubsector(x, y); + fixed_t offset = mthing->z << FRACBITS; + boolean flip = (!!(mobjinfo[mobjtype].flags & MF_SPAWNCEILING) ^ !!(mthing->options & MTF_OBJECTFLIP)); - switch (i) + switch (mobjtype) { // Bumpers never spawn flipped. case MT_NIGHTSBUMPER: - heightoffset = mthing->z*FRACUNIT; flip = false; break; @@ -11578,38 +11576,34 @@ static fixed_t GetMobjSpawnHeight (const mobjtype_t i, const mapthing_t* mthing, case MT_JETTBOMBER: case MT_JETTGUNNER: case MT_EGGMOBILE2: - heightoffset = mthing->z ? 0 : 33*FRACUNIT; - goto atend; + if (!offset) + offset = 33*FRACUNIT; + break; case MT_EGGMOBILE: - heightoffset = mthing->z ? 0 : 128*FRACUNIT; - goto atend; + if (!offset) + offset = 128*FRACUNIT; + break; case MT_GOLDBUZZ: case MT_REDBUZZ: - heightoffset = mthing->z ? 0 : 288*FRACUNIT; - goto atend; + if (!offset) + offset = 288*FRACUNIT; + break; // Ring-like items, may float additional units with MTF_AMBUSH. case MT_SPIKEBALL: case MT_EMERALDSPAWN: case MT_TOKEN: case MT_EMBLEM: - weaponfloat: - flip = mthing->options & MTF_OBJECTFLIP; - extraoffset = mthing->options & MTF_AMBUSH ? 24*FRACUNIT : 0; - heightoffset = mthing->z*FRACUNIT; + offset += mthing->options & MTF_AMBUSH ? 24*FRACUNIT : 0; break; // Remaining objects. default: - if (P_WeaponOrPanel(i)) - goto weaponfloat; // Ring-like items don't use MF_SPAWNCEILING to consider flips. - - atend: - heightoffset = mthing->z*FRACUNIT; - flip = (!!(mobjinfo[i].flags & MF_SPAWNCEILING) ^ !!(mthing->options & MTF_OBJECTFLIP)); + if (P_WeaponOrPanel(mobjtype)) + offset += mthing->options & MTF_AMBUSH ? 24 * FRACUNIT : 0; } - if (heightoffset + extraoffset == 0) // Snap to the surfaces when there's no offset set. + if (!offset) // Snap to the surfaces when there's no offset set. { if (flip) return ONCEILINGZ; @@ -11623,13 +11617,13 @@ static fixed_t GetMobjSpawnHeight (const mobjtype_t i, const mapthing_t* mthing, #ifdef ESLOPE ss->sector->c_slope ? P_GetZAt(ss->sector->c_slope, x, y) : #endif - ss->sector->ceilingheight) - extraoffset - heightoffset - mobjinfo[i].height; + ss->sector->ceilingheight) - offset - mobjinfo[mobjtype].height; else return ( #ifdef ESLOPE ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) : #endif - ss->sector->floorheight) + extraoffset + heightoffset; + ss->sector->floorheight) + offset; } // @@ -11894,7 +11888,7 @@ You should think about modifying the deathmatch starts to take full advantage of // spawn it x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; - z = GetMobjSpawnHeight(i, mthing, x, y); + z = P_GetMobjSpawnHeight(i, mthing, x, y); mobj = P_SpawnMobj(x, y, z, i); mobj->spawnpoint = mthing; From 8a6e244e60c0f760be4716346e8f4b6d20946e7f Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Sun, 15 Dec 2019 09:49:54 +0100 Subject: [PATCH 055/195] SpawnEmeraldHunt() -> P_SpawnEmeraldHunt() --- src/p_setup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index 628292fe0..9a546c5b5 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1035,7 +1035,7 @@ static void P_PrepareThings(lumpnum_t lumpnum) Z_Free(data); } -static void SpawnEmeraldHunt (void) +static void P_SpawnEmeraldHunt(void) { INT32 emer1, emer2, emer3; INT32 timeout = 0; // keeps from getting stuck @@ -1119,7 +1119,7 @@ static void P_LoadThings(boolean loademblems) // random emeralds for hunt if (numhuntemeralds) - SpawnEmeraldHunt(); + P_SpawnEmeraldHunt(); if (metalrecording) // Metal Sonic gets no rings to distract him. return; From 23b3f5a649fcd43c3eefd46b5ca54ee40559278e Mon Sep 17 00:00:00 2001 From: GoldenTails Date: Sun, 15 Dec 2019 04:09:56 -0600 Subject: [PATCH 056/195] Fix a divide by zero crash when mindash and maxdash were the same. Props to rumia1 for finding this and Lach for figuring out this was a divide by zero error. --- src/p_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_user.c b/src/p_user.c index ea42a2c36..2c9a766bc 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4635,7 +4635,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) S_StartSound(player->mo, sfx_spin); break; } - if (player->dashspeed < player->maxdash) + if (player->dashspeed < player->maxdash && player->mindash != player->maxdash) { #define chargecalculation (6*(player->dashspeed - player->mindash))/(player->maxdash - player->mindash) fixed_t soundcalculation = chargecalculation; From b17bf5d836d21652dfc83072b032e277598e8e87 Mon Sep 17 00:00:00 2001 From: Sryder Date: Sun, 15 Dec 2019 14:37:30 +0000 Subject: [PATCH 057/195] Use Scaled Radial Deadzones, instead of Axial deadzones. Additionally fixes some weird padscale 0 stuff that was flipped. This does have gameplay implications in both NiGHTS and regular gameplay. Notably you won't feel like you're locked into up/down left/right when you want to turn, but this can make running perfectly straight a little bit more tricky. --- src/g_game.c | 210 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 142 insertions(+), 68 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 2a12dd298..0105b88c6 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -275,6 +275,12 @@ static UINT8 *metalbuffer = NULL; static UINT8 *metal_p; static UINT16 metalversion; +typedef struct joystickvector2_s +{ + INT32 xaxis; + INT32 yaxis; +} joystickvector2_t; + // extra data stuff (events registered this frame while recording) static struct { UINT8 flags; // EZT flags @@ -882,12 +888,6 @@ static INT32 JoyAxis(axis_input_e axissel) retaxis = -JOYAXISRANGE; if (retaxis > (+JOYAXISRANGE)) retaxis = +JOYAXISRANGE; - if (!Joystick.bGamepadStyle && axissel < AXISDEAD) - { - const INT32 jdeadzone = JOYAXISRANGE/4; - if (-jdeadzone < retaxis && retaxis < jdeadzone) - return 0; - } if (flp) retaxis = -retaxis; //flip it around return retaxis; } @@ -955,16 +955,74 @@ static INT32 Joy2Axis(axis_input_e axissel) retaxis = -JOYAXISRANGE; if (retaxis > (+JOYAXISRANGE)) retaxis = +JOYAXISRANGE; - if (!Joystick2.bGamepadStyle && axissel < AXISDEAD) - { - const INT32 jdeadzone = JOYAXISRANGE/4; - if (-jdeadzone < retaxis && retaxis < jdeadzone) - return 0; - } if (flp) retaxis = -retaxis; //flip it around return retaxis; } +// Take a magnitude of two axes, and adjust it to take out the deadzone +// Will return a value between 0 and JOYAXISRANGE +static INT32 G_BasicDeadZoneCalculation(INT32 magnitude) +{ + // TODO: console variable for deadzone setting + const INT32 jdeadzone = JOYAXISRANGE/4; + INT32 deadzoneAppliedValue = 0; + + if (jdeadzone > 0) + { + if (magnitude > jdeadzone) + { + INT32 adjustedMagnitude = abs(magnitude); + adjustedMagnitude = min(adjustedMagnitude, JOYAXISRANGE); + + adjustedMagnitude -= jdeadzone; + + deadzoneAppliedValue = (adjustedMagnitude * JOYAXISRANGE) / (JOYAXISRANGE - jdeadzone); + } + } + + return deadzoneAppliedValue; +} + +// Get the actual sensible radial value for a joystick axis when accounting for a deadzone +static void G_HandleAxisDeadZone(UINT8 splitnum, joystickvector2_t *joystickvector) +{ + INT32 gamepadStyle = Joystick.bGamepadStyle; + + if (splitnum == 1) + { + gamepadStyle = Joystick2.bGamepadStyle; + } + + // When gamepadstyle is "true" the values are just -1, 0, or 1. This is done in the interface code. + if (!gamepadStyle) + { + // Get the total magnitude of the 2 axes + INT32 magnitude = (joystickvector->xaxis * joystickvector->xaxis) + (joystickvector->yaxis * joystickvector->yaxis); + INT32 normalisedxaxis; + INT32 normalisedyaxis; + INT32 normalisedMagnitude; + double dMagnitude = sqrt((double)magnitude); + magnitude = (INT32)dMagnitude; + + // Get the normalised xy values from the magnitude + normalisedxaxis = (joystickvector->xaxis * magnitude) / JOYAXISRANGE; + normalisedyaxis = (joystickvector->yaxis * magnitude) / JOYAXISRANGE; + + // Apply the deadzone to the magnitude to give a correct value between 0 and JOYAXISRANGE + normalisedMagnitude = G_BasicDeadZoneCalculation(magnitude); + + // Apply the deadzone to the xy axes + joystickvector->xaxis = (normalisedxaxis * normalisedMagnitude) / JOYAXISRANGE; + joystickvector->yaxis = (normalisedyaxis * normalisedMagnitude) / JOYAXISRANGE; + + // Cap the values so they don't go above the correct maximum + joystickvector->xaxis = min(joystickvector->xaxis, JOYAXISRANGE); + joystickvector->xaxis = max(joystickvector->xaxis, -JOYAXISRANGE); + joystickvector->yaxis = min(joystickvector->yaxis, JOYAXISRANGE); + joystickvector->yaxis = max(joystickvector->yaxis, -JOYAXISRANGE); + } +} + // // G_BuildTiccmd @@ -985,12 +1043,13 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) { boolean forcestrafe = false; boolean forcefullinput = false; - INT32 tspeed, forward, side, axis, altaxis, i; + INT32 tspeed, forward, side, axis, strafeaxis, moveaxis, turnaxis, lookaxis, i; const INT32 speed = 1; // these ones used for multiple conditions boolean turnleft, turnright, strafelkey, straferkey, movefkey, movebkey, mouseaiming, analogjoystickmove, gamepadjoystickmove, thisjoyaiming; player_t *player = &players[consoleplayer]; camera_t *thiscam = &camera; + joystickvector2_t movejoystickvector, lookjoystickvector; static INT32 turnheld; // for accelerative turning static boolean keyboard_look; // true if lookup/down using keyboard @@ -1030,11 +1089,16 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) localaiming = 0; joyaiming = thisjoyaiming; - axis = JoyAxis(AXISTURN); - if (gamepadjoystickmove && axis != 0) + turnaxis = JoyAxis(AXISTURN); + lookaxis = JoyAxis(AXISLOOK); + lookjoystickvector.xaxis = turnaxis; + lookjoystickvector.yaxis = lookaxis; + G_HandleAxisDeadZone(0, &lookjoystickvector); + + if (gamepadjoystickmove && lookjoystickvector.xaxis != 0) { - turnright = turnright || (axis > 0); - turnleft = turnleft || (axis < 0); + turnright = turnright || (lookjoystickvector.xaxis > 0); + turnleft = turnleft || (lookjoystickvector.xaxis < 0); } forward = side = 0; @@ -1074,10 +1138,10 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) if (turnleft) side -= sidemove[speed]; - if (analogjoystickmove && axis != 0) + if (analogjoystickmove && lookjoystickvector.xaxis != 0) { // JOYAXISRANGE is supposed to be 1023 (divide by 1024) - side += ((axis * sidemove[1]) >> 10); + side += ((lookjoystickvector.xaxis * sidemove[1]) >> 10); } } else if (cv_analog.value) // Analog @@ -1094,41 +1158,44 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) else if (turnleft) cmd->angleturn = (INT16)(cmd->angleturn + angleturn[tspeed]); - if (analogjoystickmove && axis != 0) + if (analogjoystickmove && lookjoystickvector.xaxis != 0) { // JOYAXISRANGE should be 1023 (divide by 1024) - cmd->angleturn = (INT16)(cmd->angleturn - ((axis * angleturn[1]) >> 10)); // ANALOG! + cmd->angleturn = (INT16)(cmd->angleturn - ((lookjoystickvector.xaxis * angleturn[1]) >> 10)); // ANALOG! } } - axis = JoyAxis(AXISSTRAFE); - if (gamepadjoystickmove && axis != 0) + strafeaxis = JoyAxis(AXISSTRAFE); + moveaxis = JoyAxis(AXISMOVE); + movejoystickvector.xaxis = strafeaxis; + movejoystickvector.yaxis = moveaxis; + G_HandleAxisDeadZone(0, &movejoystickvector); + + if (gamepadjoystickmove && movejoystickvector.xaxis != 0) { - if (axis < 0) + if (movejoystickvector.xaxis > 0) side += sidemove[speed]; - else if (axis > 0) + else if (movejoystickvector.xaxis < 0) side -= sidemove[speed]; } - else if (analogjoystickmove && axis != 0) + else if (analogjoystickmove && movejoystickvector.xaxis != 0) { // JOYAXISRANGE is supposed to be 1023 (divide by 1024) - side += ((axis * sidemove[1]) >> 10); + side += ((movejoystickvector.xaxis * sidemove[1]) >> 10); } // forward with key or button - axis = JoyAxis(AXISMOVE); - altaxis = JoyAxis(AXISLOOK); - if (movefkey || (gamepadjoystickmove && axis < 0) + if (movefkey || (gamepadjoystickmove && movejoystickvector.yaxis < 0) || ((player->powers[pw_carry] == CR_NIGHTSMODE) - && (PLAYER1INPUTDOWN(gc_lookup) || (gamepadjoystickmove && altaxis < 0)))) + && (PLAYER1INPUTDOWN(gc_lookup) || (gamepadjoystickmove && lookjoystickvector.yaxis > 0)))) forward = forwardmove[speed]; - if (movebkey || (gamepadjoystickmove && axis > 0) + if (movebkey || (gamepadjoystickmove && movejoystickvector.yaxis > 0) || ((player->powers[pw_carry] == CR_NIGHTSMODE) - && (PLAYER1INPUTDOWN(gc_lookdown) || (gamepadjoystickmove && altaxis > 0)))) + && (PLAYER1INPUTDOWN(gc_lookdown) || (gamepadjoystickmove && lookjoystickvector.yaxis < 0)))) forward -= forwardmove[speed]; - if (analogjoystickmove && axis != 0) - forward -= ((axis * forwardmove[1]) >> 10); // ANALOG! + if (analogjoystickmove && movejoystickvector.yaxis != 0) + forward -= ((movejoystickvector.yaxis * forwardmove[1]) >> 10); // ANALOG! // some people strafe left & right with mouse buttons // those people are weird @@ -1211,9 +1278,8 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) localaiming += (mlooky<<19)*player_invert*screen_invert; } - axis = JoyAxis(AXISLOOK); - if (analogjoystickmove && joyaiming && axis != 0 && cv_lookaxis.value != 0) - localaiming += (axis<<16) * screen_invert; + if (analogjoystickmove && joyaiming && lookjoystickvector.yaxis != 0 && cv_lookaxis.value != 0) + localaiming += (lookjoystickvector.yaxis<<16) * screen_invert; // spring back if not using keyboard neither mouselookin' if (!keyboard_look && cv_lookaxis.value == 0 && !joyaiming && !mouseaiming) @@ -1221,12 +1287,12 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) if (!(player->powers[pw_carry] == CR_NIGHTSMODE)) { - if (PLAYER1INPUTDOWN(gc_lookup) || (gamepadjoystickmove && axis < 0)) + if (PLAYER1INPUTDOWN(gc_lookup) || (gamepadjoystickmove && lookjoystickvector.yaxis > 0)) { localaiming += KB_LOOKSPEED * screen_invert; keyboard_look = true; } - else if (PLAYER1INPUTDOWN(gc_lookdown) || (gamepadjoystickmove && axis > 0)) + else if (PLAYER1INPUTDOWN(gc_lookdown) || (gamepadjoystickmove && lookjoystickvector.yaxis < 0)) { localaiming -= KB_LOOKSPEED * screen_invert; keyboard_look = true; @@ -1316,12 +1382,13 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) { boolean forcestrafe = false; boolean forcefullinput = false; - INT32 tspeed, forward, side, axis, altaxis, i; + INT32 tspeed, forward, side, axis, strafeaxis, moveaxis, turnaxis, lookaxis, i; const INT32 speed = 1; // these ones used for multiple conditions boolean turnleft, turnright, strafelkey, straferkey, movefkey, movebkey, mouseaiming, analogjoystickmove, gamepadjoystickmove, thisjoyaiming; player_t *player = &players[secondarydisplayplayer]; camera_t *thiscam = (player->bot == 2 ? &camera : &camera2); + joystickvector2_t movejoystickvector, lookjoystickvector; static INT32 turnheld; // for accelerative turning static boolean keyboard_look; // true if lookup/down using keyboard @@ -1359,11 +1426,16 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) localaiming2 = 0; joyaiming = thisjoyaiming; - axis = Joy2Axis(AXISTURN); - if (gamepadjoystickmove && axis != 0) + turnaxis = Joy2Axis(AXISTURN); + lookaxis = Joy2Axis(AXISLOOK); + lookjoystickvector.xaxis = turnaxis; + lookjoystickvector.yaxis = lookaxis; + G_HandleAxisDeadZone(1, &lookjoystickvector); + + if (gamepadjoystickmove && lookjoystickvector.xaxis != 0) { - turnright = turnright || (axis > 0); - turnleft = turnleft || (axis < 0); + turnright = turnright || (lookjoystickvector.xaxis > 0); + turnleft = turnleft || (lookjoystickvector.xaxis < 0); } forward = side = 0; @@ -1404,10 +1476,10 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) if (turnleft) side -= sidemove[speed]; - if (analogjoystickmove && axis != 0) + if (analogjoystickmove && lookjoystickvector.xaxis != 0) { // JOYAXISRANGE is supposed to be 1023 (divide by 1024) - side += ((axis * sidemove[1]) >> 10); + side += ((lookjoystickvector.xaxis * sidemove[1]) >> 10); } } else if (cv_analog2.value) // Analog @@ -1424,41 +1496,44 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) else if (turnleft) cmd->angleturn = (INT16)(cmd->angleturn + angleturn[tspeed]); - if (analogjoystickmove && axis != 0) + if (analogjoystickmove && lookjoystickvector.xaxis != 0) { // JOYAXISRANGE should be 1023 (divide by 1024) - cmd->angleturn = (INT16)(cmd->angleturn - ((axis * angleturn[1]) >> 10)); // ANALOG! + cmd->angleturn = (INT16)(cmd->angleturn - ((lookjoystickvector.xaxis * angleturn[1]) >> 10)); // ANALOG! } } - axis = Joy2Axis(AXISSTRAFE); - if (gamepadjoystickmove && axis != 0) + strafeaxis = Joy2Axis(AXISSTRAFE); + moveaxis = Joy2Axis(AXISMOVE); + movejoystickvector.xaxis = strafeaxis; + movejoystickvector.yaxis = moveaxis; + G_HandleAxisDeadZone(1, &movejoystickvector); + + if (gamepadjoystickmove && movejoystickvector.xaxis != 0) { - if (axis < 0) + if (movejoystickvector.xaxis > 0) side += sidemove[speed]; - else if (axis > 0) + else if (movejoystickvector.xaxis < 0) side -= sidemove[speed]; } - else if (analogjoystickmove && axis != 0) + else if (analogjoystickmove && movejoystickvector.xaxis != 0) { // JOYAXISRANGE is supposed to be 1023 (divide by 1024) - side += ((axis * sidemove[1]) >> 10); + side += ((movejoystickvector.xaxis * sidemove[1]) >> 10); } // forward with key or button - axis = Joy2Axis(AXISMOVE); - altaxis = Joy2Axis(AXISLOOK); - if (movefkey || (gamepadjoystickmove && axis < 0) + if (movefkey || (gamepadjoystickmove && movejoystickvector.yaxis < 0) || ((player->powers[pw_carry] == CR_NIGHTSMODE) - && (PLAYER2INPUTDOWN(gc_lookup) || (gamepadjoystickmove && altaxis < 0)))) + && (PLAYER2INPUTDOWN(gc_lookup) || (gamepadjoystickmove && lookjoystickvector.yaxis > 0)))) forward = forwardmove[speed]; - if (movebkey || (gamepadjoystickmove && axis > 0) + if (movebkey || (gamepadjoystickmove && movejoystickvector.yaxis > 0) || ((player->powers[pw_carry] == CR_NIGHTSMODE) - && (PLAYER2INPUTDOWN(gc_lookdown) || (gamepadjoystickmove && altaxis > 0)))) + && (PLAYER2INPUTDOWN(gc_lookdown) || (gamepadjoystickmove && lookjoystickvector.yaxis < 0)))) forward -= forwardmove[speed]; - if (analogjoystickmove && axis != 0) - forward -= ((axis * forwardmove[1]) >> 10); // ANALOG! + if (analogjoystickmove && movejoystickvector.yaxis != 0) + forward -= ((movejoystickvector.yaxis * forwardmove[1]) >> 10); // ANALOG! // some people strafe left & right with mouse buttons // those people are (still) weird @@ -1538,9 +1613,8 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) localaiming2 += (mlook2y<<19)*player_invert*screen_invert; } - axis = Joy2Axis(AXISLOOK); - if (analogjoystickmove && joyaiming && axis != 0 && cv_lookaxis2.value != 0) - localaiming2 += (axis<<16) * screen_invert; + if (analogjoystickmove && joyaiming && lookjoystickvector.yaxis != 0 && cv_lookaxis2.value != 0) + localaiming2 += (lookjoystickvector.yaxis<<16) * screen_invert; // spring back if not using keyboard neither mouselookin' if (!keyboard_look && cv_lookaxis2.value == 0 && !joyaiming && !mouseaiming) @@ -1548,12 +1622,12 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) if (!(player->powers[pw_carry] == CR_NIGHTSMODE)) { - if (PLAYER2INPUTDOWN(gc_lookup) || (gamepadjoystickmove && axis < 0)) + if (PLAYER2INPUTDOWN(gc_lookup) || (gamepadjoystickmove && lookjoystickvector.yaxis > 0)) { localaiming2 += KB_LOOKSPEED * screen_invert; keyboard_look = true; } - else if (PLAYER2INPUTDOWN(gc_lookdown) || (gamepadjoystickmove && axis > 0)) + else if (PLAYER2INPUTDOWN(gc_lookdown) || (gamepadjoystickmove && lookjoystickvector.yaxis < 0)) { localaiming2 -= KB_LOOKSPEED * screen_invert; keyboard_look = true; From 76d59330f7ad201d50efb055846cccea7b4d51d5 Mon Sep 17 00:00:00 2001 From: Sryder Date: Sun, 15 Dec 2019 15:36:13 +0000 Subject: [PATCH 058/195] Port the deadzone cvar stuff from kart. Add menu items for deadzone. --- src/d_netcmd.c | 4 ++++ src/g_game.c | 27 ++++++++++++++++----------- src/g_game.h | 1 + src/m_menu.c | 6 +++++- 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index e80d07b76..f622966c5 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -823,6 +823,10 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_autobrake); CV_RegisterVar(&cv_autobrake2); + // Ported from kart + CV_RegisterVar(&cv_deadzone); + CV_RegisterVar(&cv_deadzone2); + // s_sound.c CV_RegisterVar(&cv_soundvolume); CV_RegisterVar(&cv_closedcaptioning); diff --git a/src/g_game.c b/src/g_game.c index 0105b88c6..d2d27528c 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -400,6 +400,11 @@ consvar_t cv_directionchar2 = {"directionchar2", "Movement", CV_SAVE|CV_CALL, di consvar_t cv_autobrake = {"autobrake", "On", CV_SAVE|CV_CALL, CV_OnOff, AutoBrake_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_autobrake2 = {"autobrake2", "On", CV_SAVE|CV_CALL, CV_OnOff, AutoBrake2_OnChange, 0, NULL, NULL, 0, 0, NULL}; +static CV_PossibleValue_t deadzone_cons_t[] = {{0, "MIN"}, {FRACUNIT, "MAX"}, {0, NULL}}; +consvar_t cv_deadzone = {"deadzone", "0.25", CV_FLOAT|CV_SAVE, deadzone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_deadzone2 = {"deadzone2", "0.25", CV_FLOAT|CV_SAVE, deadzone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; + + typedef enum { AXISNONE = 0, @@ -407,7 +412,6 @@ typedef enum AXISMOVE, AXISLOOK, AXISSTRAFE, - AXISDEAD, //Axises that don't want deadzones AXISJUMP, AXISSPIN, AXISFIRE, @@ -961,10 +965,9 @@ static INT32 Joy2Axis(axis_input_e axissel) // Take a magnitude of two axes, and adjust it to take out the deadzone // Will return a value between 0 and JOYAXISRANGE -static INT32 G_BasicDeadZoneCalculation(INT32 magnitude) +static INT32 G_BasicDeadZoneCalculation(INT32 magnitude, fixed_t deadZone) { - // TODO: console variable for deadzone setting - const INT32 jdeadzone = JOYAXISRANGE/4; + const INT32 jdeadzone = (JOYAXISRANGE * deadZone) / FRACUNIT; INT32 deadzoneAppliedValue = 0; if (jdeadzone > 0) @@ -987,10 +990,12 @@ static INT32 G_BasicDeadZoneCalculation(INT32 magnitude) static void G_HandleAxisDeadZone(UINT8 splitnum, joystickvector2_t *joystickvector) { INT32 gamepadStyle = Joystick.bGamepadStyle; + fixed_t deadZone = cv_deadzone.value; if (splitnum == 1) { gamepadStyle = Joystick2.bGamepadStyle; + deadZone = cv_deadzone2.value; } // When gamepadstyle is "true" the values are just -1, 0, or 1. This is done in the interface code. @@ -998,22 +1003,22 @@ static void G_HandleAxisDeadZone(UINT8 splitnum, joystickvector2_t *joystickvect { // Get the total magnitude of the 2 axes INT32 magnitude = (joystickvector->xaxis * joystickvector->xaxis) + (joystickvector->yaxis * joystickvector->yaxis); - INT32 normalisedxaxis; - INT32 normalisedyaxis; + INT32 normalisedXAxis; + INT32 normalisedYAxis; INT32 normalisedMagnitude; double dMagnitude = sqrt((double)magnitude); magnitude = (INT32)dMagnitude; // Get the normalised xy values from the magnitude - normalisedxaxis = (joystickvector->xaxis * magnitude) / JOYAXISRANGE; - normalisedyaxis = (joystickvector->yaxis * magnitude) / JOYAXISRANGE; + normalisedXAxis = (joystickvector->xaxis * magnitude) / JOYAXISRANGE; + normalisedYAxis = (joystickvector->yaxis * magnitude) / JOYAXISRANGE; // Apply the deadzone to the magnitude to give a correct value between 0 and JOYAXISRANGE - normalisedMagnitude = G_BasicDeadZoneCalculation(magnitude); + normalisedMagnitude = G_BasicDeadZoneCalculation(magnitude, deadZone); // Apply the deadzone to the xy axes - joystickvector->xaxis = (normalisedxaxis * normalisedMagnitude) / JOYAXISRANGE; - joystickvector->yaxis = (normalisedyaxis * normalisedMagnitude) / JOYAXISRANGE; + joystickvector->xaxis = (normalisedXAxis * normalisedMagnitude) / JOYAXISRANGE; + joystickvector->yaxis = (normalisedYAxis * normalisedMagnitude) / JOYAXISRANGE; // Cap the values so they don't go above the correct maximum joystickvector->xaxis = min(joystickvector->xaxis, JOYAXISRANGE); diff --git a/src/g_game.h b/src/g_game.h index e7f4a4677..c19faebe4 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -72,6 +72,7 @@ extern consvar_t cv_useranalog, cv_useranalog2; extern consvar_t cv_analog, cv_analog2; extern consvar_t cv_directionchar, cv_directionchar2; extern consvar_t cv_autobrake, cv_autobrake2; +extern consvar_t cv_deadzone, cv_deadzone2; extern consvar_t cv_sideaxis,cv_turnaxis,cv_moveaxis,cv_lookaxis,cv_jumpaxis,cv_spinaxis,cv_fireaxis,cv_firenaxis; extern consvar_t cv_sideaxis2,cv_turnaxis2,cv_moveaxis2,cv_lookaxis2,cv_jumpaxis2,cv_spinaxis2,cv_fireaxis2,cv_firenaxis2; extern consvar_t cv_ghost_bestscore, cv_ghost_besttime, cv_ghost_bestrings, cv_ghost_last, cv_ghost_guest; diff --git a/src/m_menu.c b/src/m_menu.c index e367041e0..cbcc3bdb6 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1119,6 +1119,8 @@ static menuitem_t OP_Joystick1Menu[] = {IT_STRING | IT_CVAR, NULL, "First-Person Vert-Look", &cv_alwaysfreelook, 120}, {IT_STRING | IT_CVAR, NULL, "Third-Person Vert-Look", &cv_chasefreelook, 130}, + {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, + NULL, "Deadzone", &cv_deadzone, 140 }, }; static menuitem_t OP_Joystick2Menu[] = @@ -1135,6 +1137,8 @@ static menuitem_t OP_Joystick2Menu[] = {IT_STRING | IT_CVAR, NULL, "First-Person Vert-Look", &cv_alwaysfreelook2,120}, {IT_STRING | IT_CVAR, NULL, "Third-Person Vert-Look", &cv_chasefreelook2, 130}, + {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, + NULL, "Deadzone", &cv_deadzone2, 140 }, }; static menuitem_t OP_JoystickSetMenu[1+MAX_JOYSTICKS]; @@ -3025,7 +3029,7 @@ boolean M_Responder(event_t *ev) } else if (ev->type == ev_joystick && ev->data1 == 0 && joywait < I_GetTime()) { - const INT32 jdeadzone = JOYAXISRANGE/4; + const INT32 jdeadzone = (JOYAXISRANGE * cv_deadzone.value) / FRACUNIT; if (ev->data3 != INT32_MAX) { if (Joystick.bGamepadStyle || abs(ev->data3) > jdeadzone) From 230006553dea1907f9d6ad04e946b725a56c66a9 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Sun, 15 Dec 2019 21:43:50 +0100 Subject: [PATCH 059/195] Set mapthing z in OP_CreateNewMapThing --- src/m_cheat.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/m_cheat.c b/src/m_cheat.c index e31ce7869..0451a5fb3 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -1106,7 +1106,7 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c #else fixed_t cheight = sec->ceilingheight; #endif - mt->options = (UINT16)((cheight - player->mo->z - player->mo->height)>>FRACBITS); + mt->z = (UINT16)((cheight - player->mo->z - player->mo->height)>>FRACBITS); } else { @@ -1115,12 +1115,11 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c #else fixed_t fheight = sec->floorheight; #endif - mt->options = (UINT16)((player->mo->z - fheight)>>FRACBITS); + mt->z = (UINT16)((player->mo->z - fheight)>>FRACBITS); } - mt->options <<= ZSHIFT; mt->angle = (INT16)(FixedInt(AngleFixed(player->mo->angle))); - mt->options |= (UINT16)cv_opflags.value; + mt->options = (mt->z << ZSHIFT) | (UINT16)cv_opflags.value; return mt; } From bb3440d02127af605dbb75ccfa5c7878efebeece Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Mon, 16 Dec 2019 00:04:48 +0100 Subject: [PATCH 060/195] Minor cleanup of virtual resources code --- src/p_setup.c | 24 +++++++++--------------- src/w_wad.c | 16 ++++++++-------- src/w_wad.h | 6 +++--- 3 files changed, 20 insertions(+), 26 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index cc53f2d3d..f1607c272 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -367,12 +367,7 @@ UINT32 P_GetScoreForGrade(INT16 map, UINT8 mare, UINT8 grade) return mapheaderinfo[map-1]->grades[mare].grade[grade-1]; } -/** Loads the vertexes for a level. - * - * \param lump VERTEXES lump number. - * \sa ML_VERTEXES - */ - +// Loads the vertexes for a level. static inline void P_LoadRawVertexes(UINT8 *data) { mapvertex_t *ml = (mapvertex_t *)data; @@ -666,7 +661,6 @@ INT32 P_CheckLevelFlat(const char *flatname) } // Sets up the ingame sectors structures. -// Lumpnum is the lumpnum of a SECTORS lump. static void P_LoadRawSectors(UINT8 *data) { mapsector_t *ms = (mapsector_t *)data; @@ -1147,7 +1141,7 @@ static void P_LoadRawLineDefs(UINT8 *data) } } -static void SetupLines (void) +static void P_SetupLines(void) { line_t *ld = lines; size_t i; @@ -1933,7 +1927,7 @@ static void P_LoadRawReject(UINT8 *data, size_t count) } } -static void LoadMapBSP (const virtres_t* virt) +static void P_LoadMapBSP(const virtres_t* virt) { virtlump_t* virtssectors = vres_Find(virt, "SSECTORS"); virtlump_t* virtsegs = vres_Find(virt, "SEGS"); @@ -1945,7 +1939,7 @@ static void LoadMapBSP (const virtres_t* virt) P_LoadRawSegs(virtsegs->data, virtsegs->size); } -static void LoadMapLUT (const virtres_t* virt) +static void P_LoadMapLUT(const virtres_t* virt) { virtlump_t* virtblockmap = vres_Find(virt, "BLOCKMAP"); virtlump_t* virtreject = vres_Find(virt, "REJECT"); @@ -1960,7 +1954,7 @@ static void LoadMapLUT (const virtres_t* virt) P_CreateBlockMap(); } -static void LoadMapData (const virtres_t* virt) +static void P_LoadMapData(const virtres_t* virt) { virtlump_t* virtvertexes = NULL, * virtsectors = NULL, * virtsidedefs = NULL, * virtlinedefs = NULL, * virtthings = NULL; #ifdef UDMF @@ -2022,7 +2016,7 @@ static void LoadMapData (const virtres_t* virt) P_LoadRawVertexes(virtvertexes->data); P_LoadRawSectors(virtsectors->data); P_LoadRawLineDefs(virtlinedefs->data); - SetupLines(); + P_SetupLines(); P_LoadRawSideDefs2(virtsidedefs->data); } } @@ -2784,9 +2778,9 @@ boolean P_SetupLevel(boolean skipprecip) { virtres_t* virt = vres_GetMap(lastloadedmaplumpnum); - LoadMapData(virt); - LoadMapBSP(virt); - LoadMapLUT(virt); + P_LoadMapData(virt); + P_LoadMapBSP(virt); + P_LoadMapLUT(virt); P_LoadLineDefs2(); P_GroupLines(); diff --git a/src/w_wad.c b/src/w_wad.c index f16e8eb5b..9cedd242f 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -1895,12 +1895,12 @@ int W_VerifyNMUSlumps(const char *filename) * \return Virtual resource * */ -virtres_t* vres_GetMap (lumpnum_t lumpnum) +virtres_t* vres_GetMap(lumpnum_t lumpnum) { UINT32 i; - virtres_t* vres = NULL; - virtlump_t* vlumps = NULL; - size_t numlumps = 0; + virtres_t* vres = NULL; + virtlump_t* vlumps = NULL; + size_t numlumps = 0; if (W_IsLumpWad(lumpnum)) { @@ -1942,8 +1942,8 @@ virtres_t* vres_GetMap (lumpnum_t lumpnum) } } vres = Z_Malloc(sizeof(virtres_t), PU_LEVEL, NULL); - vres->vlumps = vlumps; - vres->numlumps = numlumps; + vres->vlumps = vlumps; + vres->numlumps = numlumps; return vres; } @@ -1952,7 +1952,7 @@ virtres_t* vres_GetMap (lumpnum_t lumpnum) * * \param Virtual resource */ -void vres_Free (virtres_t* vres) +void vres_Free(virtres_t* vres) { while (vres->numlumps--) Z_Free(vres->vlumps[vres->numlumps].data); @@ -1963,7 +1963,7 @@ void vres_Free (virtres_t* vres) /** (Debug) Prints lumps from a virtual resource into console. */ /* -static void vres_Diag (const virtres_t* vres) +static void vres_Diag(const virtres_t* vres) { UINT32 i; for (i = 0; i < vres->numlumps; i++) diff --git a/src/w_wad.h b/src/w_wad.h index a265d78a9..8008a577c 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -87,9 +87,9 @@ typedef struct { virtlump_t* vlumps; } virtres_t; -virtres_t* vres_GetMap (lumpnum_t); -void vres_Free (virtres_t*); -virtlump_t* vres_Find (const virtres_t*, const char*); +virtres_t* vres_GetMap(lumpnum_t); +void vres_Free(virtres_t*); +virtlump_t* vres_Find(const virtres_t*, const char*); // ========================================================================= // DYNAMIC WAD LOADING From 79350992dffa88f5982df44174b9a04b608b13be Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Mon, 16 Dec 2019 00:17:20 +0100 Subject: [PATCH 061/195] Some more cleanup of map loading code --- src/p_setup.c | 90 ++++++++++++++++++++++----------------------------- 1 file changed, 39 insertions(+), 51 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index f1607c272..ca99c8705 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -413,25 +413,15 @@ static inline float P_SegLengthFloat(seg_t *seg) } #endif -/** Loads the SEGS resource from a level. - * - * \param lump Lump number of the SEGS resource. - * \sa ::ML_SEGS - */ -static void P_LoadRawSegs(UINT8 *data, size_t i) +// Loads the SEGS resource from a level. +static void P_LoadRawSegs(UINT8 *data) { INT32 linedef, side; - mapseg_t *ml; - seg_t *li; + mapseg_t *ml = (mapseg_t*)data; + seg_t *li = segs; line_t *ldef; + size_t i; - numsegs = i / sizeof (mapseg_t); - if (numsegs <= 0) - I_Error("Level has no segs"); // instead of crashing - segs = Z_Calloc(numsegs * sizeof (*segs), PU_LEVEL, NULL); - - ml = (mapseg_t *)data; - li = segs; for (i = 0; i < numsegs; i++, li++, ml++) { li->v1 = &vertexes[SHORT(ml->v1)]; @@ -456,7 +446,7 @@ static void P_LoadRawSegs(UINT8 *data, size_t i) li->side = side = SHORT(ml->side); li->sidedef = &sides[ldef->sidenum[side]]; li->frontsector = sides[ldef->sidenum[side]].sector; - if (ldef-> flags & ML_TWOSIDED) + if (ldef->flags & ML_TWOSIDED) li->backsector = sides[ldef->sidenum[side^1]].sector; else li->backsector = 0; @@ -466,22 +456,12 @@ static void P_LoadRawSegs(UINT8 *data, size_t i) } } -/** Loads the SSECTORS resource from a level. - * - * \param lump Lump number of the SSECTORS resource. - * \sa ::ML_SSECTORS - */ -static inline void P_LoadRawSubsectors(void *data, size_t i) +// Loads the SSECTORS resource from a level. +static inline void P_LoadRawSubsectors(void *data) { - mapsubsector_t *ms; - subsector_t *ss; - - numsubsectors = i / sizeof (mapsubsector_t); - if (numsubsectors <= 0) - I_Error("Level has no subsectors (did you forget to run it through a nodesbuilder?)"); - ss = subsectors = Z_Calloc(numsubsectors * sizeof (*subsectors), PU_LEVEL, NULL); - - ms = (mapsubsector_t *)data; + mapsubsector_t *ms = (mapsubsector_t*)data; + subsector_t *ss = subsectors; + size_t i; for (i = 0; i < numsubsectors; i++, ss++, ms++) { @@ -761,19 +741,12 @@ static void P_LoadRawSectors(UINT8 *data) // // P_LoadNodes // -static void P_LoadRawNodes(UINT8 *data, size_t i) +static void P_LoadRawNodes(UINT8 *data) { UINT8 j, k; - mapnode_t *mn; - node_t *no; - - numnodes = i / sizeof (mapnode_t); - if (numnodes <= 0) - I_Error("Level has no nodes"); - nodes = Z_Calloc(numnodes * sizeof (*nodes), PU_LEVEL, NULL); - - mn = (mapnode_t *)data; - no = nodes; + mapnode_t *mn = (mapnode_t*)data; + node_t *no = nodes; + size_t i; for (i = 0; i < numnodes; i++, no++, mn++) { @@ -1933,10 +1906,25 @@ static void P_LoadMapBSP(const virtres_t* virt) virtlump_t* virtsegs = vres_Find(virt, "SEGS"); virtlump_t* virtnodes = vres_Find(virt, "NODES"); + numsubsectors = virtssectors->size / sizeof(mapsubsector_t); + numnodes = virtnodes->size / sizeof(mapnode_t); + numsegs = virtsegs->size / sizeof(mapseg_t); + + if (numsubsectors <= 0) + I_Error("Level has no subsectors (did you forget to run it through a nodesbuilder?)"); + if (numnodes <= 0) + I_Error("Level has no nodes"); + if (numsegs <= 0) + I_Error("Level has no segs"); + + subsectors = Z_Calloc(numsubsectors * sizeof(*subsectors), PU_LEVEL, NULL); + nodes = Z_Calloc(numnodes * sizeof(*nodes), PU_LEVEL, NULL); + segs = Z_Calloc(numsegs * sizeof(*segs), PU_LEVEL, NULL); + // Nodes - P_LoadRawSubsectors(virtssectors->data, virtssectors->size); - P_LoadRawNodes(virtnodes->data, virtnodes->size); - P_LoadRawSegs(virtsegs->data, virtsegs->size); + P_LoadRawSubsectors(virtssectors->data); + P_LoadRawNodes(virtnodes->data); + P_LoadRawSegs(virtsegs->data); } static void P_LoadMapLUT(const virtres_t* virt) @@ -1981,7 +1969,7 @@ static void P_LoadMapData(const virtres_t* virt) virtsidedefs = vres_Find(virt, "SIDEDEFS"); virtlinedefs = vres_Find(virt, "LINEDEFS"); - // Traditional doom map format just assumes the number of elements from the lump sixes. + // Traditional doom map format just assumes the number of elements from the lump sizes. numvertexes = virtvertexes->size / sizeof (mapvertex_t); numsectors = virtsectors->size / sizeof (mapsector_t); numsides = virtsidedefs->size / sizeof (mapsidedef_t); @@ -1998,11 +1986,11 @@ static void P_LoadMapData(const virtres_t* virt) if (numlines <= 0) I_Error("Level has no linedefs"); - vertexes = Z_Calloc(numvertexes * sizeof (*vertexes), PU_LEVEL, NULL); - sectors = Z_Calloc(numsectors * sizeof (*sectors), PU_LEVEL, NULL); - sides = Z_Calloc(numsides * sizeof (*sides), PU_LEVEL, NULL); - lines = Z_Calloc(numlines * sizeof (*lines), PU_LEVEL, NULL); - mapthings= Z_Calloc(nummapthings * sizeof (*mapthings), PU_LEVEL, NULL); + vertexes = Z_Calloc(numvertexes * sizeof (*vertexes), PU_LEVEL, NULL); + sectors = Z_Calloc(numsectors * sizeof (*sectors), PU_LEVEL, NULL); + sides = Z_Calloc(numsides * sizeof (*sides), PU_LEVEL, NULL); + lines = Z_Calloc(numlines * sizeof (*lines), PU_LEVEL, NULL); + mapthings = Z_Calloc(nummapthings * sizeof (*mapthings), PU_LEVEL, NULL); #ifdef UDMF if (textmap) From f028bb021947d4ab9dc69566c2f95efc41a9acdd Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Mon, 16 Dec 2019 17:46:27 +0000 Subject: [PATCH 062/195] Fix `numoflines` calculations in sectorlines_* functions by first typecasting seclines (the sector.lines address) to size_t before doing any math on it, then (after the math) typecast the result to size_t * and dereference it. And yes, this time I tested it to make sure it works :) --- src/lua_maplib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 0fe1df0b6..b35bb6a41 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -445,7 +445,7 @@ static int sectorlines_get(lua_State *L) // get the "linecount" by shifting our retrieved memory address of "lines" to where "linecount" is in the sector_t, then dereferencing the result // we need this to determine the array's actual size, and therefore also the maximum value allowed as an index // this only works if seclines is actually a pointer to a sector's lines member in memory, oh boy - numoflines = (size_t)(*(seclines - (offsetof(sector_t, lines) - offsetof(sector_t, linecount)))); + numoflines = (size_t)(*(size_t *)(((size_t)seclines) - (offsetof(sector_t, lines) - offsetof(sector_t, linecount)))); /* OLD HACK // check first linedef to figure which of its sectors owns this sector->lines pointer @@ -479,7 +479,7 @@ static int sectorlines_num(lua_State *L) return luaL_error(L, "accessed sector_t.lines doesn't exist anymore."); // see comments in the _get function above - numoflines = (size_t)(*(seclines - (offsetof(sector_t, lines) - offsetof(sector_t, linecount)))); + numoflines = (size_t)(*(size_t *)(((size_t)seclines) - (offsetof(sector_t, lines) - offsetof(sector_t, linecount)))); lua_pushinteger(L, numoflines); return 1; } From 46f431616c51c29af69dc5f42302f63be789eeae Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Mon, 16 Dec 2019 20:26:19 +0000 Subject: [PATCH 063/195] Added a lot of SOC-editable variables to Lua, as well as the tutorialmode boolean --- src/dehacked.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/dehacked.c b/src/dehacked.c index 175c1fcfa..938699516 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -10479,12 +10479,84 @@ static inline int lib_getenum(lua_State *L) } else if (fastcmp(word,"paused")) { lua_pushboolean(L, paused); return 1; + // begin map vars + } else if (fastcmp(word,"spstage_start")) { + lua_pushinteger(L, spstage_start); + return 1; + } else if (fastcmp(word,"sstage_start")) { + lua_pushinteger(L, sstage_start); + return 1; + } else if (fastcmp(word,"sstage_end")) { + lua_pushinteger(L, sstage_end); + return 1; + } else if (fastcmp(word,"smpstage_start")) { + lua_pushinteger(L, smpstage_start); + return 1; + } else if (fastcmp(word,"smpstage_end")) { + lua_pushinteger(L, smpstage_end); + return 1; } else if (fastcmp(word,"titlemap")) { lua_pushinteger(L, titlemap); return 1; } else if (fastcmp(word,"titlemapinaction")) { lua_pushboolean(L, (titlemapinaction != TITLEMAP_OFF)); return 1; + } else if (fastcmp(word,"bootmap")) { + lua_pushinteger(L, bootmap); + return 1; + } else if (fastcmp(word,"tutorialmap")) { + lua_pushinteger(L, tutorialmap); + return 1; + } else if (fastcmp(word,"tutorialmode")) { + lua_pushboolean(L, tutorialmode); + return 1; + // end map vars + // begin CTF colors + } else if (fastcmp(word,"skincolor_redteam")) { + lua_pushinteger(L, skincolor_redteam); + return 1; + } else if (fastcmp(word,"skincolor_blueteam")) { + lua_pushinteger(L, skincolor_blueteam); + return 1; + } else if (fastcmp(word,"skincolor_redring")) { + lua_pushinteger(L, skincolor_redring); + return 1; + } else if (fastcmp(word,"skincolor_bluering")) { + lua_pushinteger(L, skincolor_bluering); + return 1; + // end CTF colors + // begin timers + } else if (fastcmp(word,"invulntics")) { + lua_pushinteger(L, invulntics); + return 1; + } else if (fastcmp(word,"sneakertics")) { + lua_pushinteger(L, sneakertics); + return 1; + } else if (fastcmp(word,"flashingtics")) { + lua_pushinteger(L, flashingtics); + return 1; + } else if (fastcmp(word,"tailsflytics")) { + lua_pushinteger(L, tailsflytics); + return 1; + } else if (fastcmp(word,"underwatertics")) { + lua_pushinteger(L, underwatertics); + return 1; + } else if (fastcmp(word,"spacetimetics")) { + lua_pushinteger(L, spacetimetics); + return 1; + } else if (fastcmp(word,"extralifetics")) { + lua_pushinteger(L, extralifetics); + return 1; + } else if (fastcmp(word,"nightslinktics")) { + lua_pushinteger(L, nightslinktics); + return 1; + } else if (fastcmp(word,"gameovertics")) { + lua_pushinteger(L, gameovertics); + return 1; + } else if (fastcmp(word,"ammoremovaltics")) { + lua_pushinteger(L, ammoremovaltics); + return 1; + // end timers } else if (fastcmp(word,"gametype")) { lua_pushinteger(L, gametype); return 1; From 0ab31b3de0136aa66b553ddd2b07c6df6c5cd588 Mon Sep 17 00:00:00 2001 From: Tatsuru Date: Mon, 16 Dec 2019 17:58:00 -0300 Subject: [PATCH 064/195] Let Lua toggle Match/CTF team scores HUD element --- src/lua_hud.h | 1 + src/lua_hudlib.c | 1 + src/st_stuff.c | 45 ++++++++++++++++++++++++++++++++++++++------- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/lua_hud.h b/src/lua_hud.h index abfbba441..23e3ef834 100644 --- a/src/lua_hud.h +++ b/src/lua_hud.h @@ -21,6 +21,7 @@ enum hud { // Match / CTF / Tag / Ringslinger hud_weaponrings, hud_powerstones, + hud_teamscores, // NiGHTS mode hud_nightslink, hud_nightsdrill, diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index a2f48c4ad..5b5aa3b4b 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -48,6 +48,7 @@ static const char *const hud_disable_options[] = { "weaponrings", "powerstones", + "teamscores", "nightslink", "nightsdrill", diff --git a/src/st_stuff.c b/src/st_stuff.c index 1b8107edb..1b116a7f3 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -2320,14 +2320,20 @@ static void ST_drawTeamHUD(void) p = bflagico; else p = bmatcico; - + +#ifdef HAVE_BLUA + if (LUA_HudEnabled(hud_teamscores)) +#endif V_DrawSmallScaledPatch(BASEVIDWIDTH/2 - SEP - SHORT(p->width)/4, 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p); - + if (gametype == GT_CTF) p = rflagico; else p = rmatcico; - + +#ifdef HAVE_BLUA + if (LUA_HudEnabled(hud_teamscores)) +#endif V_DrawSmallScaledPatch(BASEVIDWIDTH/2 + SEP - SHORT(p->width)/4, 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p); if (gametype != GT_CTF) @@ -2339,28 +2345,53 @@ static void ST_drawTeamHUD(void) // Show which flags aren't at base. for (i = 0; i < MAXPLAYERS; i++) { - if (players[i].gotflag & GF_BLUEFLAG) // Blue flag isn't at base + if (players[i].gotflag & GF_BLUEFLAG // Blue flag isn't at base +#ifdef HAVE_BLUA + && LUA_HudEnabled(hud_teamscores) +#endif + ) V_DrawScaledPatch(BASEVIDWIDTH/2 - SEP - SHORT(nonicon->width)/2, 0, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, nonicon); - if (players[i].gotflag & GF_REDFLAG) // Red flag isn't at base + + if (players[i].gotflag & GF_REDFLAG // Red flag isn't at base +#ifdef HAVE_BLUA + && LUA_HudEnabled(hud_teamscores) +#endif + ) V_DrawScaledPatch(BASEVIDWIDTH/2 + SEP - SHORT(nonicon2->width)/2, 0, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, nonicon2); whichflag |= players[i].gotflag; + if ((whichflag & (GF_REDFLAG|GF_BLUEFLAG)) == (GF_REDFLAG|GF_BLUEFLAG)) break; // both flags were found, let's stop early } // Display a countdown timer showing how much time left until the flag returns to base. { - if (blueflag && blueflag->fuse > 1) + if (blueflag && blueflag->fuse > 1 +#ifdef HAVE_BLUA + && LUA_HudEnabled(hud_teamscores) +#endif + ) V_DrawCenteredString(BASEVIDWIDTH/2 - SEP, 8, V_YELLOWMAP|V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", (blueflag->fuse / TICRATE))); - if (redflag && redflag->fuse > 1) + if (redflag && redflag->fuse > 1 +#ifdef HAVE_BLUA + && LUA_HudEnabled(hud_teamscores) +#endif + ) V_DrawCenteredString(BASEVIDWIDTH/2 + SEP, 8, V_YELLOWMAP|V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", (redflag->fuse / TICRATE))); } } num: +#ifdef HAVE_BLUA + if (LUA_HudEnabled(hud_teamscores)) +#endif V_DrawCenteredString(BASEVIDWIDTH/2 - SEP, 16, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", bluescore)); + +#ifdef HAVE_BLUA + if (LUA_HudEnabled(hud_teamscores)) +#endif V_DrawCenteredString(BASEVIDWIDTH/2 + SEP, 16, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", redscore)); #undef SEP From 0e371774c828bd401af02d4f801a2802532a3bb2 Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Mon, 16 Dec 2019 21:25:41 -0500 Subject: [PATCH 065/195] Fix crash on mapload when removing Dragonbomber with Lua --- src/p_enemy.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index 74a11fe67..5361f453b 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -14712,20 +14712,35 @@ void A_DragonWing(mobj_t *actor) void A_DragonSegment(mobj_t *actor) { mobj_t *target = actor->target; - fixed_t dist = P_AproxDistance(P_AproxDistance(actor->x - target->x, actor->y - target->y), actor->z - target->z); - fixed_t radius = actor->radius + target->radius; - angle_t hangle = R_PointToAngle2(target->x, target->y, actor->x, actor->y); - angle_t zangle = R_PointToAngle2(0, target->z, dist, actor->z); - fixed_t hdist = P_ReturnThrustX(target, zangle, radius); - fixed_t xdist = P_ReturnThrustX(target, hangle, hdist); - fixed_t ydist = P_ReturnThrustY(target, hangle, hdist); - fixed_t zdist = P_ReturnThrustY(target, zangle, radius); + fixed_t dist; + fixed_t radius; + angle_t hangle; + angle_t zangle; + fixed_t hdist; + fixed_t xdist; + fixed_t ydist; + fixed_t zdist; #ifdef HAVE_BLUA if (LUA_CallAction("A_DragonSegment", actor)) return; #endif + if (target == NULL || !target->health) + { + P_RemoveMobj(actor); + return; + } + + dist = P_AproxDistance(P_AproxDistance(actor->x - target->x, actor->y - target->y), actor->z - target->z); + radius = actor->radius + target->radius; + hangle = R_PointToAngle2(target->x, target->y, actor->x, actor->y); + zangle = R_PointToAngle2(0, target->z, dist, actor->z); + hdist = P_ReturnThrustX(target, zangle, radius); + xdist = P_ReturnThrustX(target, hangle, hdist); + ydist = P_ReturnThrustY(target, hangle, hdist); + zdist = P_ReturnThrustY(target, zangle, radius); + actor->angle = hangle; P_TeleportMove(actor, target->x + xdist, target->y + ydist, target->z + zdist); } From 369563ad923af4948ab74c1c821c5dae481fdab2 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Tue, 17 Dec 2019 12:50:41 -0300 Subject: [PATCH 066/195] allow models to change colors more than once. --- src/hardware/hw_md2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 13ba007ee..ba7b70333 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -963,7 +963,7 @@ static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, INT for (grmip = gpatch->mipmap; grmip->nextcolormap; ) { grmip = grmip->nextcolormap; - if (grmip->colormap == colormap || grmip->tcindex == skinnum) + if (grmip->colormap == colormap || (skinnum < 1 && grmip->tcindex == skinnum)) { if (grmip->downloaded && grmip->grInfo.data) { From 7e55dd31f5489fd4119781a7eccb0310abf7974c Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Tue, 17 Dec 2019 12:53:26 -0300 Subject: [PATCH 067/195] fix menu spacing --- src/m_menu.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 23dc10701..ab30d0707 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1305,18 +1305,18 @@ static menuitem_t OP_OpenGLOptionsMenu[] = {IT_STRING|IT_CVAR, NULL, "Model lighting", &cv_grmodellighting, 32}, {IT_HEADER, NULL, "General", NULL, 51}, - {IT_STRING|IT_CVAR, NULL, "Field of view", &cv_grfov, 62}, - {IT_STRING|IT_CVAR, NULL, "Quality", &cv_scr_depth, 72}, - {IT_STRING|IT_CVAR, NULL, "Texture Filter", &cv_grfiltermode, 82}, - {IT_STRING|IT_CVAR, NULL, "Anisotropic", &cv_granisotropicmode,92}, + {IT_STRING|IT_CVAR, NULL, "Field of view", &cv_grfov, 63}, + {IT_STRING|IT_CVAR, NULL, "Quality", &cv_scr_depth, 73}, + {IT_STRING|IT_CVAR, NULL, "Texture Filter", &cv_grfiltermode, 83}, + {IT_STRING|IT_CVAR, NULL, "Anisotropic", &cv_granisotropicmode,93}, - {IT_HEADER, NULL, "Miscellaneous", NULL, 111}, - {IT_SUBMENU|IT_STRING, NULL, "Fog...", &OP_OpenGLFogDef, 123}, + {IT_HEADER, NULL, "Miscellaneous", NULL, 112}, + {IT_SUBMENU|IT_STRING, NULL, "Fog...", &OP_OpenGLFogDef, 124}, #ifdef ALAM_LIGHTING - {IT_SUBMENU|IT_STRING, NULL, "Lighting...", &OP_OpenGLLightingDef, 133}, + {IT_SUBMENU|IT_STRING, NULL, "Lighting...", &OP_OpenGLLightingDef, 134}, #endif #if defined (_WINDOWS) && (!((defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL))) - {IT_STRING|IT_CVAR, NULL, "Fullscreen", &cv_fullscreen, 143}, + {IT_STRING|IT_CVAR, NULL, "Fullscreen", &cv_fullscreen, 144}, #endif }; From 0af71fafc57fb842a8c7a9a4853d8c7fbb2bf7fc Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Tue, 17 Dec 2019 15:20:22 -0300 Subject: [PATCH 068/195] Don't use the local palette, because OpenGL mixes it into the textures themselves --- src/m_anigif.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/m_anigif.c b/src/m_anigif.c index aec53b874..91f70dcfe 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -432,8 +432,11 @@ static void GIF_headwrite(void) // write color table { - RGBA_t *pal = ((cv_screenshot_colorprofile.value) - ? pLocalPalette + RGBA_t *pal = ((cv_screenshot_colorprofile.value +#ifdef HWRENDER + && (rendermode == render_soft) +#endif + ) ? pLocalPalette : pMasterPalette); for (i = 0; i < 256; i++) From c3f0e6aa4472f0754a7f392759b9f93cb3c7651b Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Tue, 17 Dec 2019 15:37:43 -0300 Subject: [PATCH 069/195] Avoid recreating the color LUT mid-recording-frame --- src/m_anigif.c | 21 +++++++++++++-------- src/v_video.c | 6 +++--- src/v_video.h | 2 +- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/m_anigif.c b/src/m_anigif.c index 91f70dcfe..f761db143 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -33,6 +33,7 @@ consvar_t cv_gif_downscale = {"gif_downscale", "On", CV_SAVE, CV_OnOff, NULL, 0 #ifdef HAVE_ANIGIF static boolean gif_optimize = false; // So nobody can do something dumb static boolean gif_downscale = false; // like changing cvars mid output +static RGBA_t *gif_palette = NULL; static FILE *gif_out = NULL; static INT32 gif_frames = 0; @@ -432,13 +433,7 @@ static void GIF_headwrite(void) // write color table { - RGBA_t *pal = ((cv_screenshot_colorprofile.value -#ifdef HWRENDER - && (rendermode == render_soft) -#endif - ) ? pLocalPalette - : pMasterPalette); - + RGBA_t *pal = gif_palette; for (i = 0; i < 256; i++) { WRITEUINT8(p, pal[i].s.red); @@ -473,7 +468,7 @@ static void hwrconvert(void) INT32 x, y; size_t i = 0; - InitColorLUT(); + InitColorLUT(gif_palette); for (y = 0; y < vid.height; y++) { @@ -643,6 +638,16 @@ INT32 GIF_open(const char *filename) gif_optimize = (!!cv_gif_optimize.value); gif_downscale = (!!cv_gif_downscale.value); + + // GIF color table + // In hardware mode, uses the master palette + gif_palette = ((cv_screenshot_colorprofile.value +#ifdef HWRENDER + && (rendermode == render_soft) +#endif + ) ? pLocalPalette + : pMasterPalette); + GIF_headwrite(); gif_frames = 0; return 1; diff --git a/src/v_video.c b/src/v_video.c index 1e901f2b3..c91e5f213 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -3251,19 +3251,19 @@ Unoptimized version UINT8 colorlookup[CLUTSIZE][CLUTSIZE][CLUTSIZE]; -void InitColorLUT(void) +void InitColorLUT(RGBA_t *palette) { UINT8 r, g, b; static boolean clutinit = false; static RGBA_t *lastpalette = NULL; - if ((!clutinit) || (lastpalette != pLocalPalette)) + if ((!clutinit) || (lastpalette != palette)) { for (r = 0; r < CLUTSIZE; r++) for (g = 0; g < CLUTSIZE; g++) for (b = 0; b < CLUTSIZE; b++) colorlookup[r][g][b] = NearestColor(r << SHIFTCOLORBITS, g << SHIFTCOLORBITS, b << SHIFTCOLORBITS); clutinit = true; - lastpalette = pLocalPalette; + lastpalette = palette; } } diff --git a/src/v_video.h b/src/v_video.h index 0cd78d2e5..36d1914af 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -47,7 +47,7 @@ void V_Init(void); extern UINT8 colorlookup[CLUTSIZE][CLUTSIZE][CLUTSIZE]; -void InitColorLUT(void); +void InitColorLUT(RGBA_t *palette); // Set the current RGB palette lookup to use for palettized graphics void V_SetPalette(INT32 palettenum); From d1b944121ae68de10f6ef02207f26ac0e76ae2fa Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 17 Dec 2019 14:11:45 -0800 Subject: [PATCH 070/195] Fix "SRB2" SOC directive, though its usefulness is debatable --- src/dehacked.c | 30 ++++++++++++++++++++++-------- src/dehacked.h | 2 +- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 175c1fcfa..9abb708a9 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -4462,20 +4462,34 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) ignorelines(f); } } - // Last I heard this crashes the game if you try to use it - // so this is disabled for now - // -- Monster Iestyn -/* else if (fastcmp(word, "SRB2")) + else if (fastcmp(word, "SRB2")) { - INT32 ver = searchvalue(strtok(NULL, "\n")); - if (ver != PATCHVERSION) - deh_warning("Patch is for SRB2 version %d,\nonly version %d is supported", ver, PATCHVERSION); + if (isdigit(word2[0])) + { + i = atoi(word2); + if (i != PATCHVERSION) + { + deh_warning( + "Patch is for SRB2 version %d, " + "only version %d is supported", + i, + PATCHVERSION + ); + } + } + else + { + deh_warning( + "SRB2 version definition has incorrect format, " + "use \"SRB2 %d\"", + PATCHVERSION + ); + } } // Clear all data in certain locations (mostly for unlocks) // Unless you REALLY want to piss people off, // define a custom gamedata /before/ doing this!! // (then again, modifiedgame will prevent game data saving anyway) -*/ else if (fastcmp(word, "CLEAR")) { boolean clearall = (fastcmp(word2, "ALL")); diff --git a/src/dehacked.h b/src/dehacked.h index d4fb07df0..2b34377fd 100644 --- a/src/dehacked.h +++ b/src/dehacked.h @@ -47,7 +47,7 @@ extern const char *superactions[MAXRECURSION]; extern UINT8 superstack; // If the dehacked patch does not match this version, we throw a warning -#define PATCHVERSION 210 +#define PATCHVERSION 220 #define MAXLINELEN 1024 From 254d812901c6ba5c2ba53d70f4d0e8e0d9c14dc2 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 00:28:58 -0300 Subject: [PATCH 071/195] More customisable title card Add TitleCardZigZag, TitleCardZigZagText and TitleCardActDiamond fields to SOC. Add the same fields to Lua under their internal names. Turn map header level flags into an UINT16, so that NoTitleCard works. (NOBODY caught this, I'm actually disappointed.) --- src/dehacked.c | 19 ++++++++++++++++++- src/doomstat.h | 7 ++++++- src/lua_maplib.c | 6 ++++++ src/p_setup.c | 3 +++ src/st_stuff.c | 36 ++++++++++++++++++++++++------------ 5 files changed, 57 insertions(+), 14 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 175c1fcfa..c66f3589d 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1520,10 +1520,27 @@ static void readlevelheader(MYFILE *f, INT32 num) deh_warning("Level header %d: invalid bonus type number %d", num, i); } + // Title card + else if (fastcmp(word, "TITLECARDZIGZAG")) + { + deh_strlcpy(mapheaderinfo[num-1]->ltzzpatch, word2, + sizeof(mapheaderinfo[num-1]->ltzzpatch), va("Level header %d: title card zigzag patch name", num)); + } + else if (fastcmp(word, "TITLECARDZIGZAGTEXT")) + { + deh_strlcpy(mapheaderinfo[num-1]->ltzztext, word2, + sizeof(mapheaderinfo[num-1]->ltzztext), va("Level header %d: title card zigzag text patch name", num)); + } + else if (fastcmp(word, "TITLECARDACTDIAMOND")) + { + deh_strlcpy(mapheaderinfo[num-1]->ltactdiamond, word2, + sizeof(mapheaderinfo[num-1]->ltactdiamond), va("Level header %d: title card act diamond patch name", num)); + } + else if (fastcmp(word, "MAXBONUSLIVES")) mapheaderinfo[num-1]->maxbonuslives = (SINT8)i; else if (fastcmp(word, "LEVELFLAGS")) - mapheaderinfo[num-1]->levelflags = (UINT8)i; + mapheaderinfo[num-1]->levelflags = (UINT16)i; else if (fastcmp(word, "MENUFLAGS")) mapheaderinfo[num-1]->menuflags = (UINT8)i; diff --git a/src/doomstat.h b/src/doomstat.h index 3c0b4773a..a42591f47 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -310,12 +310,17 @@ typedef struct SINT8 bonustype; ///< What type of bonus does this level have? (-1 for null.) SINT8 maxbonuslives; ///< How many bonus lives to award at Intermission? (-1 for unlimited.) - UINT8 levelflags; ///< LF_flags: merged booleans into one UINT8 for space, see below + UINT16 levelflags; ///< LF_flags: merged booleans into one UINT16 for space, see below UINT8 menuflags; ///< LF2_flags: options that affect record attack / nights mode menus char selectheading[22]; ///< Level select heading. Allows for controllable grouping. UINT16 startrings; ///< Number of rings players start with. + // Title card. + char ltzzpatch[8]; ///< Zig zag patch. + char ltzztext[8]; ///< Zig zag text. + char ltactdiamond[8]; ///< Act diamond. + // Freed animals stuff. UINT8 numFlickies; ///< Internal. For freed flicky support. mobjtype_t *flickies; ///< List of freeable flickies in this level. Allocated dynamically for space reasons. Be careful. diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 0fe1df0b6..dd939c31b 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -2071,6 +2071,12 @@ static int mapheaderinfo_get(lua_State *L) lua_pushinteger(L, header->levelselect); else if (fastcmp(field,"bonustype")) lua_pushinteger(L, header->bonustype); + else if (fastcmp(field,"ltzzpatch")) + lua_pushstring(L, header->ltzzpatch); + else if (fastcmp(field,"ltzztext")) + lua_pushstring(L, header->ltzztext); + else if (fastcmp(field,"ltactdiamond")) + lua_pushstring(L, header->ltactdiamond); else if (fastcmp(field,"maxbonuslives")) lua_pushinteger(L, header->maxbonuslives); else if (fastcmp(field,"levelflags")) diff --git a/src/p_setup.c b/src/p_setup.c index bf3493d8c..2bbfe3924 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -210,6 +210,9 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) mapheaderinfo[num]->lvlttl[0] = '\0'; mapheaderinfo[num]->selectheading[0] = '\0'; mapheaderinfo[num]->subttl[0] = '\0'; + mapheaderinfo[num]->ltzzpatch[0] = '\0'; + mapheaderinfo[num]->ltzztext[0] = '\0'; + mapheaderinfo[num]->ltactdiamond[0] = '\0'; mapheaderinfo[num]->actnum = 0; mapheaderinfo[num]->typeoflevel = 0; mapheaderinfo[num]->nextlevel = (INT16)(i + 1); diff --git a/src/st_stuff.c b/src/st_stuff.c index 1b8107edb..ec0590419 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1177,21 +1177,33 @@ tic_t lt_exitticker = 0, lt_endtime = 0; // // Load the graphics for the title card. +// Don't let LJ see this // static void ST_cacheLevelTitle(void) { - if (!(mapheaderinfo[gamemap-1]->levelflags & LF_WARNINGTITLE)) - { - lt_patches[0] = (patch_t *)W_CachePatchName("LTACTBLU", PU_HUDGFX); - lt_patches[1] = (patch_t *)W_CachePatchName("LTZIGZAG", PU_HUDGFX); - lt_patches[2] = (patch_t *)W_CachePatchName("LTZZTEXT", PU_HUDGFX); - } - else // boss map - { - lt_patches[0] = (patch_t *)W_CachePatchName("LTACTRED", PU_HUDGFX); - lt_patches[1] = (patch_t *)W_CachePatchName("LTZIGRED", PU_HUDGFX); - lt_patches[2] = (patch_t *)W_CachePatchName("LTZZWARN", PU_HUDGFX); - } +#define SETPATCH(default, warning, custom, idx) \ +{ \ + lumpnum_t patlumpnum = LUMPERROR; \ + if (mapheaderinfo[gamemap-1]->custom[0] != '\0') \ + { \ + patlumpnum = W_CheckNumForName(mapheaderinfo[gamemap-1]->custom); \ + if (patlumpnum != LUMPERROR) \ + lt_patches[idx] = (patch_t *)W_CachePatchNum(patlumpnum, PU_HUDGFX); \ + } \ + if (patlumpnum == LUMPERROR) \ + { \ + if (!(mapheaderinfo[gamemap-1]->levelflags & LF_WARNINGTITLE)) \ + lt_patches[idx] = (patch_t *)W_CachePatchName(default, PU_HUDGFX); \ + else \ + lt_patches[idx] = (patch_t *)W_CachePatchName(warning, PU_HUDGFX); \ + } \ +} + + SETPATCH("LTACTBLU", "LTACTRED", ltactdiamond, 0) + SETPATCH("LTZIGZAG", "LTZIGRED", ltzzpatch, 1) + SETPATCH("LTZZTEXT", "LTZZWARN", ltzztext, 2) + +#undef SETPATCH } // From 317191ec7c5416374c79dcc5531bda3dd072029a Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 00:52:50 -0300 Subject: [PATCH 072/195] Freeslot moment! --- src/doomstat.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/doomstat.h b/src/doomstat.h index 3c0b4773a..772f6b3fb 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -386,6 +386,7 @@ enum TypeOfLevel }; // Gametypes +#define NUMGAMETYPEFREESLOTS 512 enum GameType { GT_COOP = 0, // also used in single player @@ -400,6 +401,8 @@ enum GameType GT_CTF, // capture the flag + GT_FIRSTFREESLOT, + GT_LASTFREESLOT = GT_FIRSTFREESLOT + NUMGAMETYPEFREESLOTS - 1, NUMGAMETYPES }; // If you alter this list, update dehacked.c, MISC_ChangeGameTypeMenu in m_menu.c, and Gametype_Names in g_game.c From 7bfdc2caa0f9473069767aa5e405623940c70841 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 01:25:57 -0300 Subject: [PATCH 073/195] Gametype rules draft, mind the debug command --- src/d_clisrv.c | 4 ++-- src/d_main.c | 4 ++-- src/d_netcmd.c | 12 +++++++++++- src/doomstat.h | 12 ++++++++++++ src/g_game.c | 46 ++++++++++++++++++++++++++++++++++++++++------ src/g_game.h | 1 + 6 files changed, 68 insertions(+), 11 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 7b6c35eb6..14901360d 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3461,7 +3461,7 @@ void SV_StartSinglePlayerServer(void) server = true; netgame = false; multiplayer = false; - gametype = GT_COOP; + G_SetGametype(GT_COOP); // no more tic the game with this settings! SV_StopServer(); @@ -3740,7 +3740,7 @@ static void HandlePacketFromAwayNode(SINT8 node) if (client) { maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic); - gametype = netbuffer->u.servercfg.gametype; + G_SetGametype(netbuffer->u.servercfg.gametype); modifiedgame = netbuffer->u.servercfg.modifiedgame; for (j = 0; j < MAXPLAYERS; j++) adminplayers[j] = netbuffer->u.servercfg.adminplayers[j]; diff --git a/src/d_main.c b/src/d_main.c index ef6502aec..815136440 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -753,7 +753,7 @@ void D_StartTitle(void) gameaction = ga_nothing; displayplayer = consoleplayer = 0; - gametype = GT_COOP; + G_SetGametype(GT_COOP); paused = false; advancedemo = false; F_InitMenuPresValues(); @@ -1416,7 +1416,7 @@ void D_SRB2Main(void) if (newgametype != -1) { j = gametype; - gametype = newgametype; + G_SetGametype(newgametype); D_GameTypeChanged(j); } } diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 00cb6e65e..40d626185 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -125,6 +125,7 @@ static void Command_Version_f(void); static void Command_ModDetails_f(void); #endif static void Command_ShowGametype_f(void); +static void Command_SetGametype_f(void); FUNCNORETURN static ATTRNORETURN void Command_Quit_f(void); static void Command_Playintro_f(void); @@ -381,6 +382,7 @@ char timedemo_csv_id[256]; boolean timedemo_quit; INT16 gametype = GT_COOP; +INT16 gametyperules = 0; boolean splitscreen = false; boolean circuitmap = false; INT32 adminplayers[MAXPLAYERS]; @@ -480,6 +482,7 @@ void D_RegisterServerCommands(void) COM_AddCommand("suicide", Command_Suicide); COM_AddCommand("gametype", Command_ShowGametype_f); + COM_AddCommand("setgametype", Command_SetGametype_f); COM_AddCommand("version", Command_Version_f); #ifdef UPDATE_ALERT COM_AddCommand("mod_details", Command_ModDetails_f); @@ -2065,6 +2068,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) lastgametype = gametype; gametype = READUINT8(*cp); + G_SetGametype(gametype); // I fear putting that macro as an argument if (gametype < 0 || gametype >= NUMGAMETYPES) gametype = lastgametype; @@ -3623,6 +3627,12 @@ static void Command_ShowGametype_f(void) CONS_Printf(M_GetText("Unknown gametype set (%d)\n"), gametype); } +static void Command_SetGametype_f(void) +{ + if (COM_Argc() > 1) + G_SetGametype(atoi(COM_Argv(1))); +} + /** Plays the intro. */ static void Command_Playintro_f(void) @@ -3935,7 +3945,7 @@ void D_GameTypeChanged(INT32 lastgametype) } else if (!multiplayer && !netgame) { - gametype = GT_COOP; + G_SetGametype(GT_COOP); // These shouldn't matter anymore //CV_Set(&cv_itemrespawntime, cv_itemrespawntime.defaultvalue); //CV_SetValue(&cv_itemrespawn, 0); diff --git a/src/doomstat.h b/src/doomstat.h index 772f6b3fb..2b493c917 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -84,6 +84,7 @@ extern boolean addedtogame; // true after the server has added you extern boolean multiplayer; extern INT16 gametype; +extern INT16 gametyperules; extern boolean splitscreen; extern boolean circuitmap; // Does this level have 'circuit mode'? extern boolean fromlevelselect; @@ -407,6 +408,17 @@ enum GameType }; // If you alter this list, update dehacked.c, MISC_ChangeGameTypeMenu in m_menu.c, and Gametype_Names in g_game.c +// Game type rules +enum GameTypeRules +{ + GTR_PLATFORM = 1, // Co-op, Competition, Race + GTR_TAG = 1<<1, // Tag, Hide and Seek + GTR_RINGSLINGER = 1<<2, // Not Co-op, not Competition, and not Race (overriden by cv_ringslinger) + GTR_SPECTATORS = 1<<3, // Not Co-op, not Competition, and not Race + GTR_TEAMS = 1<<4, // Team Match, CTF + GTR_LIVES = 1<<5, // A lot of special cases in G_GametypeUsesLives actually, but just Co-op and Competition +}; + // String names for gametypes extern const char *Gametype_Names[NUMGAMETYPES]; diff --git a/src/g_game.c b/src/g_game.c index 2a12dd298..d1fc61c35 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3058,6 +3058,34 @@ const char *Gametype_Names[NUMGAMETYPES] = "CTF" // GT_CTF }; +// Game type rules +INT16 gametypedefaultrules[NUMGAMETYPES] = +{ + GTR_PLATFORM|GTR_LIVES, // GT_COOP + GTR_PLATFORM|GTR_LIVES, // GT_COMPETITION + GTR_PLATFORM, // GT_RACE + + GTR_RINGSLINGER|GTR_SPECTATORS, // GT_MATCH + GTR_RINGSLINGER|GTR_TEAMS|GTR_SPECTATORS, // GT_TEAMMATCH + + GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS, // GT_TAG + GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS, // GT_HIDEANDSEEK + + GTR_RINGSLINGER|GTR_TEAMS|GTR_SPECTATORS // GT_CTF +}; + +// +// G_SetGametype +// +// Set a new gametype, also setting gametype rules accordingly. Yay! +// +void G_SetGametype(INT16 gtype) +{ + gametype = gtype; + gametyperules = gametypedefaultrules[gametype]; + CONS_Printf("Gametype set to %s (%d)\n", Gametype_Names[gametype], gametype); +} + // // G_GetGametypeByName // @@ -3101,7 +3129,8 @@ boolean G_IsSpecialStage(INT32 mapnum) boolean G_GametypeUsesLives(void) { // Coop, Competitive - if ((gametype == GT_COOP || gametype == GT_COMPETITION) + //if ((gametype == GT_COOP || gametype == GT_COMPETITION) + if ((gametyperules & GTR_LIVES) && !(modeattacking || metalrecording) // No lives in Time Attack && !G_IsSpecialStage(gamemap) && !(maptol & TOL_NIGHTS)) // No lives in NiGHTS @@ -3117,7 +3146,8 @@ boolean G_GametypeUsesLives(void) // boolean G_GametypeHasTeams(void) { - return (gametype == GT_TEAMMATCH || gametype == GT_CTF); + return (gametyperules & GTR_TEAMS); + //return (gametype == GT_TEAMMATCH || gametype == GT_CTF); } // @@ -3128,7 +3158,8 @@ boolean G_GametypeHasTeams(void) // boolean G_GametypeHasSpectators(void) { - return (gametype != GT_COOP && gametype != GT_COMPETITION && gametype != GT_RACE); + return (gametyperules & GTR_SPECTATORS); + //return (gametype != GT_COOP && gametype != GT_COMPETITION && gametype != GT_RACE); } // @@ -3139,7 +3170,8 @@ boolean G_GametypeHasSpectators(void) // boolean G_RingSlingerGametype(void) { - return ((gametype != GT_COOP && gametype != GT_COMPETITION && gametype != GT_RACE) || (cv_ringslinger.value)); + return ((gametyperules & GTR_RINGSLINGER) || (cv_ringslinger.value)); + //return ((gametype != GT_COOP && gametype != GT_COMPETITION && gametype != GT_RACE) || (cv_ringslinger.value)); } // @@ -3149,7 +3181,8 @@ boolean G_RingSlingerGametype(void) // boolean G_PlatformGametype(void) { - return (gametype == GT_COOP || gametype == GT_RACE || gametype == GT_COMPETITION); + return (gametyperules & GTR_PLATFORM); + //return (gametype == GT_COOP || gametype == GT_RACE || gametype == GT_COMPETITION); } // @@ -3159,7 +3192,8 @@ boolean G_PlatformGametype(void) // boolean G_TagGametype(void) { - return (gametype == GT_TAG || gametype == GT_HIDEANDSEEK); + return (gametyperules & GTR_TAG); + //return (gametype == GT_TAG || gametype == GT_HIDEANDSEEK); } /** Get the typeoflevel flag needed to indicate support of a gametype. diff --git a/src/g_game.h b/src/g_game.h index e7f4a4677..a925e14c1 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -201,6 +201,7 @@ ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(boolean kill); void G_StopDemo(void); boolean G_CheckDemoStatus(void); +void G_SetGametype(INT16 gametype); INT32 G_GetGametypeByName(const char *gametypestr); boolean G_IsSpecialStage(INT32 mapnum); boolean G_GametypeUsesLives(void); From ea5e0d28ed117292a64a491c6de7bdc60df81c13 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 01:54:45 -0300 Subject: [PATCH 074/195] More gametype rules yay!! --- src/d_clisrv.c | 2 +- src/d_netcmd.c | 12 ++++++++---- src/doomstat.h | 26 ++++++++++++++++++++------ src/g_game.c | 28 ++++++++++++++++++---------- src/p_inter.c | 2 +- src/p_map.c | 2 +- src/p_mobj.c | 4 ++-- src/p_setup.c | 3 +-- src/p_spec.c | 2 +- src/p_user.c | 24 ++++++++++++------------ src/st_stuff.c | 18 +++++++++--------- 11 files changed, 74 insertions(+), 49 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 14901360d..3786c75d6 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2512,7 +2512,7 @@ static void CL_RemovePlayer(INT32 playernum, INT32 reason) if (G_TagGametype()) //Check if you still have a game. Location flexible. =P P_CheckSurvivors(); - else if (gametype == GT_RACE || gametype == GT_COMPETITION) + else if (gametyperules & GTR_RACE) P_CheckRacers(); } diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 40d626185..0b7e3de18 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1125,7 +1125,7 @@ UINT8 CanChangeSkin(INT32 playernum) return true; // Can change skin during initial countdown. - if ((gametype == GT_RACE || gametype == GT_COMPETITION) && leveltime < 4*TICRATE) + if ((gametyperules & GTR_RACE) && leveltime < 4*TICRATE) return true; if (G_TagGametype()) @@ -2413,7 +2413,7 @@ static void Command_Teamchange_f(void) } //additional check for hide and seek. Don't allow change of status after hidetime ends. - if (gametype == GT_HIDEANDSEEK && leveltime >= (hidetime * TICRATE)) + if ((gametyperules & GTR_HIDETIMEFROZEN) && leveltime >= (hidetime * TICRATE)) { CONS_Alert(CONS_NOTICE, M_GetText("Hiding time expired; no Hide and Seek status changes allowed!\n")); return; @@ -2510,7 +2510,7 @@ static void Command_Teamchange2_f(void) } //additional check for hide and seek. Don't allow change of status after hidetime ends. - if (gametype == GT_HIDEANDSEEK && leveltime >= (hidetime * TICRATE)) + if ((gametyperules & GTR_HIDETIMEFROZEN) && leveltime >= (hidetime * TICRATE)) { CONS_Alert(CONS_NOTICE, M_GetText("Hiding time expired; no Hide and Seek status changes allowed!\n")); return; @@ -2639,7 +2639,7 @@ static void Command_ServerTeamChange_f(void) } //additional check for hide and seek. Don't allow change of status after hidetime ends. - if (gametype == GT_HIDEANDSEEK && leveltime >= (hidetime * TICRATE)) + if ((gametyperules & GTR_HIDETIMEFROZEN) && leveltime >= (hidetime * TICRATE)) { CONS_Alert(CONS_NOTICE, M_GetText("Hiding time expired; no Hide and Seek status changes allowed!\n")); return; @@ -2728,6 +2728,10 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) return; } + //no status changes after hidetime + if ((gametyperules & GTR_HIDETIMEFROZEN) && (leveltime >= (hidetime * TICRATE))) + error = true; + //Make sure that the right team number is sent. Keep in mind that normal clients cannot change to certain teams in certain gametypes. switch (gametype) { diff --git a/src/doomstat.h b/src/doomstat.h index 2b493c917..90aa185b7 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -411,12 +411,26 @@ enum GameType // Game type rules enum GameTypeRules { - GTR_PLATFORM = 1, // Co-op, Competition, Race - GTR_TAG = 1<<1, // Tag, Hide and Seek - GTR_RINGSLINGER = 1<<2, // Not Co-op, not Competition, and not Race (overriden by cv_ringslinger) - GTR_SPECTATORS = 1<<3, // Not Co-op, not Competition, and not Race - GTR_TEAMS = 1<<4, // Team Match, CTF - GTR_LIVES = 1<<5, // A lot of special cases in G_GametypeUsesLives actually, but just Co-op and Competition + GTR_PLATFORM = 1, // Co-op, Competition, and Race + GTR_TAG = 1<<1, // Tag and Hide and Seek + GTR_RINGSLINGER = 1<<2, // Not Co-op, not Competition, and not Race (overriden by cv_ringslinger) + GTR_SPECTATORS = 1<<3, // Not Co-op, not Competition, and not Race + GTR_TEAMS = 1<<4, // Team Match, CTF + GTR_LIVES = 1<<5, // A lot of special cases in G_GametypeUsesLives actually, but just Co-op and Competition + GTR_RACE = 1<<6, // Race and Competition + + // Lactozilla + // Awesome! Those are new game type rules + // provided by yours truly to allow for more + // flexibility! Those will replace some + // straight-up gametype checks scattered + // around the source code! + GTR_CHASECAM = 1<<7, // Prefer chasecam at map load + GTR_TIMELIMIT = 1<<8, // Ringslinger time limit + GTR_HIDETIME = 1<<9, // Tag and Hide and Seek + GTR_HIDETIMEFROZEN = 1<<10, // Hide and Seek, but not Tag + GTR_BLINDFOLDED = 1<<11, // Blindfolded view for Tag and Hide and Seek + GTR_EMERALDS = 1<<12, // Ringslinger emeralds }; // String names for gametypes diff --git a/src/g_game.c b/src/g_game.c index d1fc61c35..59764e0fc 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1002,7 +1002,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) // why build a ticcmd if we're paused? // Or, for that matter, if we're being reborn. // ...OR if we're blindfolded. No looking into the floor. - if (paused || P_AutoPause() || (gamestate == GS_LEVEL && (player->playerstate == PST_REBORN || ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) + if (paused || P_AutoPause() || (gamestate == GS_LEVEL && (player->playerstate == PST_REBORN || ((gametyperules & GTR_TAG) && (leveltime < hidetime * TICRATE) && (player->pflags & PF_TAGIT))))) { cmd->angleturn = (INT16)(localangle >> 16); @@ -3061,17 +3061,25 @@ const char *Gametype_Names[NUMGAMETYPES] = // Game type rules INT16 gametypedefaultrules[NUMGAMETYPES] = { - GTR_PLATFORM|GTR_LIVES, // GT_COOP - GTR_PLATFORM|GTR_LIVES, // GT_COMPETITION - GTR_PLATFORM, // GT_RACE + // Co-op + GTR_PLATFORM|GTR_LIVES|GTR_CHASECAM, + // Competition + GTR_PLATFORM|GTR_LIVES|GTR_RACE|GTR_CHASECAM, + // Race + GTR_PLATFORM|GTR_RACE|GTR_CHASECAM, - GTR_RINGSLINGER|GTR_SPECTATORS, // GT_MATCH - GTR_RINGSLINGER|GTR_TEAMS|GTR_SPECTATORS, // GT_TEAMMATCH + // Match + GTR_RINGSLINGER|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_EMERALDS, + // Team Match + GTR_RINGSLINGER|GTR_TEAMS|GTR_SPECTATORS|GTR_TIMELIMIT, - GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS, // GT_TAG - GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS, // GT_HIDEANDSEEK + // Tag + GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED, + // Hide and Seek + GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED, - GTR_RINGSLINGER|GTR_TEAMS|GTR_SPECTATORS // GT_CTF + // CTF + GTR_RINGSLINGER|GTR_TEAMS|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_EMERALDS, }; // @@ -3384,7 +3392,7 @@ static void G_DoCompleted(void) I_Error("Followed map %d to invalid map %d\n", prevmap + 1, nextmap + 1); // wrap around in race - if (nextmap >= 1100-1 && nextmap <= 1102-1 && (gametype == GT_RACE || gametype == GT_COMPETITION)) + if (nextmap >= 1100-1 && nextmap <= 1102-1 && (gametyperules & GTR_RACE)) nextmap = (INT16)(spstage_start-1); if ((gottoken = (gametype == GT_COOP && token))) diff --git a/src/p_inter.c b/src/p_inter.c index 70fb01fd0..7b5839e03 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2978,7 +2978,7 @@ static inline void P_NiGHTSDamage(mobj_t *target, mobj_t *source) player->flyangle += 180; // Shuffle's BETTERNIGHTSMOVEMENT? player->flyangle %= 360; - if (gametype == GT_RACE || gametype == GT_COMPETITION) + if (gametyperules & GTR_RACE) player->drillmeter -= 5*20; else { diff --git a/src/p_map.c b/src/p_map.c index 2d36f747c..1b6f23cde 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -615,7 +615,7 @@ static void P_DoTailsCarry(player_t *sonic, player_t *tails) // Why block opposing teams from tailsflying each other? // Sneaking into the hands of a flying tails player in Race might be a viable strategy, who knows. /* - if (gametype == GT_RACE || gametype == GT_COMPETITION + if ((gametyperules & GTR_RACE) || (netgame && (tails->spectator || sonic->spectator)) || (G_TagGametype() && (!(tails->pflags & PF_TAGIT) != !(sonic->pflags & PF_TAGIT))) || (gametype == GT_MATCH) diff --git a/src/p_mobj.c b/src/p_mobj.c index dea4a7a4d..df89fbfde 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11702,7 +11702,7 @@ You should think about modifying the deathmatch starts to take full advantage of if (!cv_powerstones.value) return; - if (!(gametype == GT_MATCH || gametype == GT_CTF)) + if (!(gametyperules & GTR_EMERALDS)) return; runemeraldmanager = true; @@ -11722,7 +11722,7 @@ You should think about modifying the deathmatch starts to take full advantage of // Yeah, this is a dirty hack. if ((mobjinfo[i].flags & (MF_MONITOR|MF_GRENADEBOUNCE)) == MF_MONITOR) { - if (gametype == GT_COMPETITION || gametype == GT_RACE) + if (gametyperules & GTR_RACE) { // Set powerup boxes to user settings for competition. if (cv_competitionboxes.value == 1) // Mystery diff --git a/src/p_setup.c b/src/p_setup.c index bf3493d8c..7e6bdcc67 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2683,8 +2683,7 @@ boolean P_SetupLevel(boolean skipprecip) // chasecam on in chaos, race, coop // chasecam off in match, tag, capture the flag - chase = (gametype == GT_RACE || gametype == GT_COMPETITION || gametype == GT_COOP) - || (maptol & TOL_2D); + chase = (gametyperules & GTR_CHASECAM) || (maptol & TOL_2D); if (!dedicated) { diff --git a/src/p_spec.c b/src/p_spec.c index dba4e17b5..4bdb99520 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -7224,7 +7224,7 @@ void P_SpawnSpecials(INT32 fromnetsave) break; case 308: // Race-only linedef executor. Triggers once. - if (gametype != GT_RACE && gametype != GT_COMPETITION) + if (!(gametyperules & GTR_RACE)) lines[i].special = 0; break; diff --git a/src/p_user.c b/src/p_user.c index ea42a2c36..a8ae383cf 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -387,7 +387,7 @@ UINT8 P_FindLowestMare(void) mobj_t *mo2; UINT8 mare = UINT8_MAX; - if (gametype == GT_RACE || gametype == GT_COMPETITION) + if (gametyperules & GTR_RACE) return 0; // scan the thinkers @@ -793,7 +793,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) P_RestoreMusic(player); } - if (gametype == GT_RACE || gametype == GT_COMPETITION) + if (gametyperules & GTR_RACE) { if (player->drillmeter < 48*20) player->drillmeter = 48*20; @@ -2181,7 +2181,7 @@ void P_DoPlayerExit(player_t *player) if (cv_allowexitlevel.value == 0 && !G_PlatformGametype()) return; - else if (gametype == GT_RACE || gametype == GT_COMPETITION) // If in Race Mode, allow + else if (gametyperules & GTR_RACE) // If in Race Mode, allow { if (!countdown) // a 60-second wait ala Sonic 2. countdown = (cv_countdowntime.value - 1)*TICRATE + 1; // Use cv_countdowntime @@ -4670,7 +4670,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) if (player->powers[pw_carry] == CR_BRAKGOOP) player->dashspeed = 0; - if (!((gametype == GT_RACE || gametype == GT_COMPETITION) && leveltime < 4*TICRATE)) + if (!((gametyperules & GTR_RACE) && leveltime < 4*TICRATE)) { if (player->dashspeed) { @@ -7137,7 +7137,7 @@ static void P_NiGHTSMovement(player_t *player) && !player->exiting) player->nightstime--; } - else if (gametype != GT_RACE && gametype != GT_COMPETITION + else if (!(gametyperules & GTR_RACE) && !(player->mo->state >= &states[S_PLAY_NIGHTS_TRANS1] && player->mo->state <= &states[S_PLAY_NIGHTS_TRANS6]) && !(player->capsule && player->capsule->reactiontime) @@ -7293,7 +7293,7 @@ static void P_NiGHTSMovement(player_t *player) { player->mo->momx = player->mo->momy = 0; - if (gametype != GT_RACE && gametype != GT_COMPETITION) + if (!(gametyperules & GTR_RACE)) P_SetObjectMomZ(player->mo, FRACUNIT/2, (P_MobjFlip(player->mo)*player->mo->momz >= 0)); else player->mo->momz = 0; @@ -9535,12 +9535,12 @@ static void P_DeathThink(player_t *player) player->playerstate = PST_REBORN; } - if (gametype == GT_RACE || gametype == GT_COMPETITION || (gametype == GT_COOP && (multiplayer || netgame))) + if ((gametyperules & GTR_RACE) || (gametype == GT_COOP && (multiplayer || netgame))) { // Keep time rolling in race mode if (!(countdown2 && !countdown) && !player->exiting && !(player->pflags & PF_GAMETYPEOVER) && !stoppedclock) { - if (gametype == GT_RACE || gametype == GT_COMPETITION) + if (gametyperules & GTR_RACE) { if (leveltime >= 4*TICRATE) player->realtime = leveltime - 4*TICRATE; @@ -11372,7 +11372,7 @@ void P_PlayerThink(player_t *player) I_Error("player %s is in PST_REBORN\n", sizeu1(playeri)); #endif - if (gametype == GT_RACE || gametype == GT_COMPETITION) + if (gametyperules & GTR_RACE) { INT32 i; @@ -11435,7 +11435,7 @@ void P_PlayerThink(player_t *player) player->exiting > 0 && player->exiting <= 1*TICRATE && (!multiplayer || gametype == GT_COOP ? !mapheaderinfo[gamemap-1]->musinterfadeout : true) && // don't fade if we're fading during intermission. follows Y_StartIntermission intertype = int_coop - (gametype == GT_RACE || gametype == GT_COMPETITION ? countdown2 == 0 : true) && // don't fade on timeout + ((gametyperules & GTR_RACE) ? countdown2 == 0 : true) && // don't fade on timeout player->lives > 0 && // don't fade on game over (competition) P_IsLocalPlayer(player)) { @@ -11550,7 +11550,7 @@ void P_PlayerThink(player_t *player) player->lives = cv_startinglives.value; } - if ((gametype == GT_RACE || gametype == GT_COMPETITION) && leveltime < 4*TICRATE) + if ((gametyperules & GTR_RACE) && leveltime < 4*TICRATE) { cmd->buttons &= BT_USE; // Remove all buttons except BT_USE cmd->forwardmove = 0; @@ -11560,7 +11560,7 @@ void P_PlayerThink(player_t *player) // Synchronizes the "real" amount of time spent in the level. if (!player->exiting && !stoppedclock) { - if (gametype == GT_RACE || gametype == GT_COMPETITION) + if (gametyperules & GTR_RACE) { if (leveltime >= 4*TICRATE) player->realtime = leveltime - 4*TICRATE; diff --git a/src/st_stuff.c b/src/st_stuff.c index 1b8107edb..6e8c64127 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -694,7 +694,7 @@ static void ST_drawTime(void) else { // Counting down the hidetime? - if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (stplyr->realtime <= (hidetime*TICRATE))) + if ((gametyperules & GTR_HIDETIME) && (stplyr->realtime <= (hidetime*TICRATE))) { tics = (hidetime*TICRATE - stplyr->realtime); if (tics < 3*TICRATE) @@ -705,11 +705,11 @@ static void ST_drawTime(void) else { // Hidetime finish! - if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (stplyr->realtime < ((hidetime+1)*TICRATE))) + if ((gametyperules & GTR_HIDETIME) && (stplyr->realtime < ((hidetime+1)*TICRATE))) ST_drawRaceNum(hidetime*TICRATE - stplyr->realtime); // Time limit? - if (gametype != GT_COOP && gametype != GT_RACE && gametype != GT_COMPETITION && cv_timelimit.value && timelimitintics > 0) + if ((gametyperules & GTR_TIMELIMIT) && cv_timelimit.value && timelimitintics > 0) { if (timelimitintics > stplyr->realtime) { @@ -723,7 +723,7 @@ static void ST_drawTime(void) downwards = true; } // Post-hidetime normal. - else if (gametype == GT_TAG || gametype == GT_HIDEANDSEEK) + else if (gametyperules & GTR_TAG) tics = stplyr->realtime - hidetime*TICRATE; // "Shadow! What are you doing? Hurry and get back here // right now before the island blows up with you on it!" @@ -912,7 +912,7 @@ static void ST_drawLivesArea(void) else if (stplyr->spectator) v_colmap = V_GRAYMAP; // Tag - else if (gametype == GT_TAG || gametype == GT_HIDEANDSEEK) + else if (gametyperules & GTR_TAG) { if (stplyr->pflags & PF_TAGIT) { @@ -1762,7 +1762,7 @@ static void ST_drawNiGHTSHUD(void) ST_drawNiGHTSLink(); } - if (gametype == GT_RACE || gametype == GT_COMPETITION) + if (gametyperules & GTR_RACE) { ST_drawScore(); ST_drawTime(); @@ -2273,7 +2273,7 @@ static void ST_drawTextHUD(void) } } } - else if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (!stplyr->spectator)) + else if ((gametyperules & GTR_TAG) && (!stplyr->spectator)) { if (leveltime < hidetime * TICRATE) { @@ -2648,7 +2648,7 @@ static void ST_overlayDrawer(void) ST_drawMatchHUD(); // Race HUD Stuff - if (gametype == GT_RACE || gametype == GT_COMPETITION) + if (gametyperules & GTR_RACE) ST_drawRaceHUD(); // Emerald Hunt Indicators @@ -2753,7 +2753,7 @@ void ST_Drawer(void) if (rendermode != render_none) ST_doPaletteStuff(); // Blindfold! - if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) + if ((gametyperules & GTR_BLINDFOLDED) && (leveltime < hidetime * TICRATE)) { if (players[displayplayer].pflags & PF_TAGIT) From 185fa2799de073fcea7cc0afeb1667a9d5f0741c Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 11:33:56 -0300 Subject: [PATCH 075/195] Update comments --- src/doomstat.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index 90aa185b7..5569e3197 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -425,12 +425,12 @@ enum GameTypeRules // flexibility! Those will replace some // straight-up gametype checks scattered // around the source code! - GTR_CHASECAM = 1<<7, // Prefer chasecam at map load - GTR_TIMELIMIT = 1<<8, // Ringslinger time limit + GTR_CHASECAM = 1<<7, // Prefer chasecam at map load (All platform gametypes) + GTR_TIMELIMIT = 1<<8, // Ringslinger time limit (Tag and Hide and Seek) GTR_HIDETIME = 1<<9, // Tag and Hide and Seek GTR_HIDETIMEFROZEN = 1<<10, // Hide and Seek, but not Tag - GTR_BLINDFOLDED = 1<<11, // Blindfolded view for Tag and Hide and Seek - GTR_EMERALDS = 1<<12, // Ringslinger emeralds + GTR_BLINDFOLDED = 1<<11, // Blindfolded view (Tag and Hide and Seek) + GTR_EMERALDS = 1<<12, // Ringslinger emeralds (Match and CTF) }; // String names for gametypes From 299f2bd8cdafcfdfff889c40cb33f7e6975c6b53 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 11:43:50 -0300 Subject: [PATCH 076/195] GTR_TEAMFLAGS --- src/d_clisrv.c | 6 +++--- src/doomstat.h | 1 + src/g_game.c | 4 ++-- src/hu_stuff.c | 4 ++-- src/m_cheat.c | 2 +- src/p_enemy.c | 8 ++++---- src/p_inter.c | 8 ++++---- src/p_mobj.c | 8 ++++---- src/p_spec.c | 6 +++--- src/p_user.c | 8 ++++---- src/st_stuff.c | 12 +++++++----- 11 files changed, 35 insertions(+), 32 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 3786c75d6..bfc478bd5 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1025,7 +1025,7 @@ static void SV_SendResynch(INT32 node) netbuffer->packettype = PT_RESYNCHEND; netbuffer->u.resynchend.randomseed = P_GetRandSeed(); - if (gametype == GT_CTF) + if (gametyperules & GTR_TEAMFLAGS) resynch_write_ctf(&netbuffer->u.resynchend); resynch_write_others(&netbuffer->u.resynchend); @@ -2430,7 +2430,7 @@ static void CL_RemovePlayer(INT32 playernum, INT32 reason) } } - if (gametype == GT_CTF) + if (gametyperules & GTR_TEAMFLAGS) P_PlayerFlagBurst(&players[playernum], false); // Don't take the flag with you! // If in a special stage, redistribute the player's spheres across @@ -4124,7 +4124,7 @@ static void HandlePacketFromPlayer(SINT8 node) P_SetRandSeed(netbuffer->u.resynchend.randomseed); - if (gametype == GT_CTF) + if (gametyperules & GTR_TEAMFLAGS) resynch_read_ctf(&netbuffer->u.resynchend); resynch_read_others(&netbuffer->u.resynchend); diff --git a/src/doomstat.h b/src/doomstat.h index 5569e3197..06e114eb1 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -431,6 +431,7 @@ enum GameTypeRules GTR_HIDETIMEFROZEN = 1<<10, // Hide and Seek, but not Tag GTR_BLINDFOLDED = 1<<11, // Blindfolded view (Tag and Hide and Seek) GTR_EMERALDS = 1<<12, // Ringslinger emeralds (Match and CTF) + GTR_TEAMFLAGS = 1<<13, // Gametype has team flags (CTF) }; // String names for gametypes diff --git a/src/g_game.c b/src/g_game.c index 59764e0fc..1f6bde833 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2564,7 +2564,7 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost) // -- CTF -- // Order: CTF->DM->Coop - if (gametype == GT_CTF && players[playernum].ctfteam) + if ((gametyperules & GTR_TEAMFLAGS) && players[playernum].ctfteam) { if (!(spawnpoint = G_FindCTFStart(playernum)) // find a CTF start && !(spawnpoint = G_FindMatchStart(playernum))) // find a DM start @@ -3079,7 +3079,7 @@ INT16 gametypedefaultrules[NUMGAMETYPES] = GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED, // CTF - GTR_RINGSLINGER|GTR_TEAMS|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_EMERALDS, + GTR_RINGSLINGER|GTR_TEAMS|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_EMERALDS|GTR_TEAMFLAGS, }; // diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 91a167a60..e67249953 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2541,7 +2541,7 @@ static void HU_Draw32TeamTabRankings(playersort_t *tab, INT32 whiteplayer) | (greycheck ? 0 : V_TRANSLUCENT) | V_ALLOWLOWERCASE, name); - if (gametype == GT_CTF) + if (gametyperules & GTR_TEAMFLAGS) { if (players[tab[i].num].gotflag & GF_REDFLAG) // Red V_DrawFixedPatch((x-10)*FRACUNIT, (y)*FRACUNIT, FRACUNIT/4, 0, rflagico, 0); @@ -2669,7 +2669,7 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer) | (greycheck ? V_TRANSLUCENT : 0) | V_ALLOWLOWERCASE, name); - if (gametype == GT_CTF) + if (gametyperules & GTR_TEAMFLAGS) { if (players[tab[i].num].gotflag & GF_REDFLAG) // Red V_DrawSmallScaledPatch(x-28, y-4, 0, rflagico); diff --git a/src/m_cheat.c b/src/m_cheat.c index e31ce7869..1d4fa3b5d 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -778,7 +778,7 @@ void Command_CauseCfail_f(void) P_SetThingPosition(players[consoleplayer].mo); // CTF consistency test - if (gametype == GT_CTF) + if (gametyperules & GTR_TEAMFLAGS) { if (blueflag) { P_RemoveMobj(blueflag); diff --git a/src/p_enemy.c b/src/p_enemy.c index 74a11fe67..30284a2dd 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -4985,7 +4985,7 @@ void A_ThrownRing(mobj_t *actor) continue; // Don't home in on teammates. - if (gametype == GT_CTF + if ((gametyperules & GTR_TEAMFLAGS) && actor->target->player->ctfteam == player->ctfteam) continue; } @@ -6591,7 +6591,7 @@ void A_OldRingExplode(mobj_t *actor) { if (changecolor) { - if (gametype != GT_CTF) + if (!(gametyperules & GTR_TEAMFLAGS)) mo->color = actor->target->color; //copy color else if (actor->target->player->ctfteam == 2) mo->color = skincolor_bluering; @@ -6607,7 +6607,7 @@ void A_OldRingExplode(mobj_t *actor) { if (changecolor) { - if (gametype != GT_CTF) + if (!(gametyperules & GTR_TEAMFLAGS)) mo->color = actor->target->color; //copy color else if (actor->target->player->ctfteam == 2) mo->color = skincolor_bluering; @@ -6622,7 +6622,7 @@ void A_OldRingExplode(mobj_t *actor) { if (changecolor) { - if (gametype != GT_CTF) + if (!(gametyperules & GTR_TEAMFLAGS)) mo->color = actor->target->color; //copy color else if (actor->target->player->ctfteam == 2) mo->color = skincolor_bluering; diff --git a/src/p_inter.c b/src/p_inter.c index 7b5839e03..33a124133 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -3224,7 +3224,7 @@ static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage) player->mo->flags2 &= ~MF2_DONTDRAW; P_SetPlayerMobjState(player->mo, player->mo->info->deathstate); - if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) + if ((gametyperules & GTR_TEAMFLAGS) && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) { P_PlayerFlagBurst(player, false); if (source && source->player) @@ -3349,7 +3349,7 @@ static void P_ShieldDamage(player_t *player, mobj_t *inflictor, mobj_t *source, else S_StartSound (player->mo, sfx_shldls); // Ba-Dum! Shield loss. - if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) + if ((gametyperules & GTR_TEAMFLAGS) && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) { P_PlayerFlagBurst(player, false); if (source && source->player) @@ -3383,7 +3383,7 @@ static void P_RingDamage(player_t *player, mobj_t *inflictor, mobj_t *source, IN P_AddPlayerScore(source->player, 50); } - if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) + if ((gametyperules & GTR_TEAMFLAGS) && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) { P_PlayerFlagBurst(player, false); if (source && source->player) @@ -3442,7 +3442,7 @@ void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source) P_DoPlayerPain(player, inflictor, source); - if (gametype == GT_CTF && player->gotflag & (GF_REDFLAG|GF_BLUEFLAG)) + if ((gametyperules & GTR_TEAMFLAGS) && player->gotflag & (GF_REDFLAG|GF_BLUEFLAG)) P_PlayerFlagBurst(player, false); if (oldnightstime > 10*TICRATE diff --git a/src/p_mobj.c b/src/p_mobj.c index df89fbfde..193746db8 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11179,7 +11179,7 @@ void P_RespawnSpecials(void) } //CTF rings should continue to respawn as normal rings outside of CTF. - if (gametype != GT_CTF) + if (!(gametyperules & GTR_TEAMFLAGS)) { if (i == MT_REDTEAMRING || i == MT_BLUETEAMRING) i = MT_RING; @@ -11750,7 +11750,7 @@ You should think about modifying the deathmatch starts to take full advantage of } } - if (gametype != GT_CTF) // CTF specific things + if (!(gametyperules & GTR_TEAMFLAGS)) // CTF specific things { if (i == MT_RING_BLUEBOX || i == MT_RING_REDBOX) i = MT_RING_BOX; @@ -13597,9 +13597,9 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) else if (mthing->type == mobjinfo[MT_COIN].doomednum) ringthing = MT_COIN; else if (mthing->type == mobjinfo[MT_REDTEAMRING].doomednum) // No team rings in non-CTF - ringthing = (gametype == GT_CTF) ? MT_REDTEAMRING : MT_RING; + ringthing = (gametyperules & GTR_TEAMFLAGS) ? MT_REDTEAMRING : MT_RING; else if (mthing->type == mobjinfo[MT_BLUETEAMRING].doomednum) // Ditto - ringthing = (gametype == GT_CTF) ? MT_BLUETEAMRING : MT_RING; + ringthing = (gametyperules & GTR_TEAMFLAGS) ? MT_BLUETEAMRING : MT_RING; } // Set proper height diff --git a/src/p_spec.c b/src/p_spec.c index 4bdb99520..161d73e0e 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -4713,7 +4713,7 @@ DoneSection2: break; case 3: // Red Team's Base - if (gametype == GT_CTF && P_IsObjectOnGround(player->mo)) + if ((gametyperules & GTR_TEAMFLAGS) && P_IsObjectOnGround(player->mo)) { if (player->ctfteam == 1 && (player->gotflag & GF_BLUEFLAG)) { @@ -4746,7 +4746,7 @@ DoneSection2: break; case 4: // Blue Team's Base - if (gametype == GT_CTF && P_IsObjectOnGround(player->mo)) + if ((gametyperules & GTR_TEAMFLAGS) && P_IsObjectOnGround(player->mo)) { if (player->ctfteam == 2 && (player->gotflag & GF_REDFLAG)) { @@ -7231,7 +7231,7 @@ void P_SpawnSpecials(INT32 fromnetsave) // Linedef executor triggers for CTF teams. case 309: case 311: - if (gametype != GT_CTF) + if (!(gametyperules & GTR_TEAMFLAGS)) lines[i].special = 0; break; diff --git a/src/p_user.c b/src/p_user.c index a8ae383cf..c94f18af1 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3110,7 +3110,7 @@ static void P_DoPlayerHeadSigns(player_t *player) } } } - else if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) // If you have the flag (duh). + else if ((gametyperules & GTR_TEAMFLAGS) && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) // If you have the flag (duh). { // Spawn a got-flag message over the head of the player that // has it (but not on your own screen if you have the flag). @@ -5048,7 +5048,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) { if (onground || player->climbing || player->powers[pw_carry]) ; - else if (gametype == GT_CTF && player->gotflag) + else if ((gametyperules & GTR_TEAMFLAGS) && player->gotflag) ; else if (player->pflags & (PF_GLIDING|PF_SLIDING|PF_SHIELDABILITY)) // If the player has used an ability previously ; @@ -5273,7 +5273,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) player->secondjump = 0; player->pflags &= ~PF_THOKKED; } - else if (player->pflags & PF_SLIDING || (gametype == GT_CTF && player->gotflag)) + else if (player->pflags & PF_SLIDING || ((gametyperules & GTR_TEAMFLAGS) && player->gotflag)) ; /*else if (P_SuperReady(player)) { @@ -5560,7 +5560,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) { player->pflags |= PF_JUMPDOWN; - if ((gametype != GT_CTF || !player->gotflag) && !player->exiting) + if ((!(gametyperules & GTR_TEAMFLAGS) || !player->gotflag) && !player->exiting) { if (player->secondjump == 1 && player->charability != CA_DOUBLEJUMP) { diff --git a/src/st_stuff.c b/src/st_stuff.c index 6e8c64127..061189f53 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -2279,7 +2279,8 @@ static void ST_drawTextHUD(void) { if (stplyr->pflags & PF_TAGIT) { - textHUDdraw(M_GetText("\x82""You are blindfolded!")) + if (gametyperules & GTR_BLINDFOLDED) + textHUDdraw(M_GetText("\x82""You are blindfolded!")) textHUDdraw(M_GetText("Waiting for players to hide...")) } else if (gametype == GT_HIDEANDSEEK) @@ -2294,7 +2295,8 @@ static void ST_drawTextHUD(void) textHUDdraw(M_GetText("\x82""VIEWPOINT:""\x80 Switch view")) donef12 = true; } - textHUDdraw(M_GetText("You cannot move while hiding.")) + if (gametyperules & GTR_HIDETIMEFROZEN) + textHUDdraw(M_GetText("You cannot move while hiding.")) } } @@ -2316,21 +2318,21 @@ static void ST_drawTeamHUD(void) if (F_GetPromptHideHud(0)) // y base is 0 return; - if (gametype == GT_CTF) + if (gametyperules & GTR_TEAMFLAGS) p = bflagico; else p = bmatcico; V_DrawSmallScaledPatch(BASEVIDWIDTH/2 - SEP - SHORT(p->width)/4, 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p); - if (gametype == GT_CTF) + if (gametyperules & GTR_TEAMFLAGS) p = rflagico; else p = rmatcico; V_DrawSmallScaledPatch(BASEVIDWIDTH/2 + SEP - SHORT(p->width)/4, 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p); - if (gametype != GT_CTF) + if (!(gametyperules & GTR_TEAMFLAGS)) goto num; { INT32 i; From 1b81232d32a696e3aba9d40be3290fe6f65075e6 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 11:47:26 -0300 Subject: [PATCH 077/195] sike --- src/hardware/hw_md2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index ba7b70333..630c1e181 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -963,7 +963,7 @@ static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, INT for (grmip = gpatch->mipmap; grmip->nextcolormap; ) { grmip = grmip->nextcolormap; - if (grmip->colormap == colormap || (skinnum < 1 && grmip->tcindex == skinnum)) + if (grmip->colormap == colormap || (skinnum < TC_DEFAULT && grmip->tcindex == skinnum)) { if (grmip->downloaded && grmip->grInfo.data) { From 83732f38a9cb8668c0346552e5d28c6fc94b339c Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 12:09:44 -0300 Subject: [PATCH 078/195] GTR_PITYSHIELD --- src/doomstat.h | 1 + src/g_game.c | 6 +++--- src/p_user.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index 06e114eb1..743d64282 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -432,6 +432,7 @@ enum GameTypeRules GTR_BLINDFOLDED = 1<<11, // Blindfolded view (Tag and Hide and Seek) GTR_EMERALDS = 1<<12, // Ringslinger emeralds (Match and CTF) GTR_TEAMFLAGS = 1<<13, // Gametype has team flags (CTF) + GTR_PITYSHIELD = 1<<14, // Award pity shield }; // String names for gametypes diff --git a/src/g_game.c b/src/g_game.c index 1f6bde833..a9474eb4f 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3069,9 +3069,9 @@ INT16 gametypedefaultrules[NUMGAMETYPES] = GTR_PLATFORM|GTR_RACE|GTR_CHASECAM, // Match - GTR_RINGSLINGER|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_EMERALDS, + GTR_RINGSLINGER|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_EMERALDS|GTR_PITYSHIELD, // Team Match - GTR_RINGSLINGER|GTR_TEAMS|GTR_SPECTATORS|GTR_TIMELIMIT, + GTR_RINGSLINGER|GTR_TEAMS|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_PITYSHIELD, // Tag GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED, @@ -3079,7 +3079,7 @@ INT16 gametypedefaultrules[NUMGAMETYPES] = GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED, // CTF - GTR_RINGSLINGER|GTR_TEAMS|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_EMERALDS|GTR_TEAMFLAGS, + GTR_RINGSLINGER|GTR_TEAMS|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_EMERALDS|GTR_TEAMFLAGS|GTR_PITYSHIELD, }; // diff --git a/src/p_user.c b/src/p_user.c index c94f18af1..b8164c173 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -10539,7 +10539,7 @@ void P_DoPityCheck(player_t *player) { // No pity outside of match or CTF. if (player->spectator - || !(gametype == GT_MATCH || gametype == GT_TEAMMATCH || gametype == GT_CTF)) + || !(gametyperules & GTR_PITYSHIELD)) return; // Apply pity shield if available. From da4e759a73928ab9ffdc55874914a2e65396e407 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 12:13:24 -0300 Subject: [PATCH 079/195] GTR_DEATHPENALTY --- src/doomstat.h | 1 + src/g_game.c | 2 +- src/p_inter.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index 743d64282..3f76e770e 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -433,6 +433,7 @@ enum GameTypeRules GTR_EMERALDS = 1<<12, // Ringslinger emeralds (Match and CTF) GTR_TEAMFLAGS = 1<<13, // Gametype has team flags (CTF) GTR_PITYSHIELD = 1<<14, // Award pity shield + GTR_DEATHPENALTY = 1<<15, // Death score penalty }; // String names for gametypes diff --git a/src/g_game.c b/src/g_game.c index a9474eb4f..cb25dd954 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3069,7 +3069,7 @@ INT16 gametypedefaultrules[NUMGAMETYPES] = GTR_PLATFORM|GTR_RACE|GTR_CHASECAM, // Match - GTR_RINGSLINGER|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_EMERALDS|GTR_PITYSHIELD, + GTR_RINGSLINGER|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_EMERALDS|GTR_PITYSHIELD|GTR_DEATHPENALTY, // Team Match GTR_RINGSLINGER|GTR_TEAMS|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_PITYSHIELD, diff --git a/src/p_inter.c b/src/p_inter.c index 33a124133..21c3d4049 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2389,7 +2389,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget { if (metalrecording) // Ack! Metal Sonic shouldn't die! Cut the tape, end recording! G_StopMetalRecording(true); - if (gametype == GT_MATCH // note, no team match suicide penalty + if ((gametyperules & GTR_DEATHPENALTY) // note, no team match suicide penalty && ((target == source) || (source == NULL && inflictor == NULL) || (source && !source->player))) { // Suicide penalty if (target->player->score >= 50) From 6660d6302896b54e37a5bdd832e869037955eb73 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 12:14:18 -0300 Subject: [PATCH 080/195] There are only so many bits --- src/d_netcmd.c | 2 +- src/doomstat.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 0b7e3de18..a806a1052 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -382,7 +382,7 @@ char timedemo_csv_id[256]; boolean timedemo_quit; INT16 gametype = GT_COOP; -INT16 gametyperules = 0; +UINT32 gametyperules = 0; boolean splitscreen = false; boolean circuitmap = false; INT32 adminplayers[MAXPLAYERS]; diff --git a/src/doomstat.h b/src/doomstat.h index 3f76e770e..c51b98c3f 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -84,7 +84,7 @@ extern boolean addedtogame; // true after the server has added you extern boolean multiplayer; extern INT16 gametype; -extern INT16 gametyperules; +extern UINT32 gametyperules; extern boolean splitscreen; extern boolean circuitmap; // Does this level have 'circuit mode'? extern boolean fromlevelselect; From 15862ed02c888feb74cc2cabd64c546cd503df73 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 12:23:42 -0300 Subject: [PATCH 081/195] G_NewGametype --- src/d_netcmd.c | 2 ++ src/doomstat.h | 2 ++ src/g_game.c | 27 +++++++++++++++++++++++++++ src/g_game.h | 2 ++ 4 files changed, 33 insertions(+) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index a806a1052..7b8095555 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -383,6 +383,8 @@ boolean timedemo_quit; INT16 gametype = GT_COOP; UINT32 gametyperules = 0; +INT16 numgametypes = (GT_CTF + 1); + boolean splitscreen = false; boolean circuitmap = false; INT32 adminplayers[MAXPLAYERS]; diff --git a/src/doomstat.h b/src/doomstat.h index c51b98c3f..66f7f3008 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -85,6 +85,8 @@ extern boolean multiplayer; extern INT16 gametype; extern UINT32 gametyperules; +extern INT16 numgametypes; + extern boolean splitscreen; extern boolean circuitmap; // Does this level have 'circuit mode'? extern boolean fromlevelselect; diff --git a/src/g_game.c b/src/g_game.c index cb25dd954..e70d4a6d1 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3094,6 +3094,33 @@ void G_SetGametype(INT16 gtype) CONS_Printf("Gametype set to %s (%d)\n", Gametype_Names[gametype], gametype); } +// +// G_NewGametype +// +// Create a new gametype. Returns the new gametype number. +// +INT16 G_NewGametype(UINT32 rules) +{ + INT32 i; + INT16 newgtype = numgametypes; + numgametypes++; + + // Set gametype rules. + gametypedefaultrules[newgtype] = numgametypes; + Gametype_Names[newgtype] = "???"; + + // Update gametype_cons_t accordingly. + for (i = 0; i < numgametypes; i++) + { + gametype_cons_t[i].value = i; + gametype_cons_t[i].strvalue = Gametype_Names[i]; + } + gametype_cons_t[NUMGAMETYPES].value = 0; + gametype_cons_t[NUMGAMETYPES].strvalue = NULL; + + return newgtype; +} + // // G_GetGametypeByName // diff --git a/src/g_game.h b/src/g_game.h index a925e14c1..ef3e9ffab 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -202,6 +202,8 @@ void G_StopDemo(void); boolean G_CheckDemoStatus(void); void G_SetGametype(INT16 gametype); +INT16 G_NewGametype(UINT32 rules); + INT32 G_GetGametypeByName(const char *gametypestr); boolean G_IsSpecialStage(INT32 mapnum); boolean G_GametypeUsesLives(void); From 86ac94817af5940a351a2546d632c4f37137086a Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 12:28:01 -0300 Subject: [PATCH 082/195] Spectator HUD tweaks --- src/st_stuff.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/st_stuff.c b/src/st_stuff.c index 061189f53..54bd36ac0 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -2203,9 +2203,10 @@ static void ST_drawTextHUD(void) if (G_IsSpecialStage(gamemap)) textHUDdraw(M_GetText("\x82""Wait for the stage to end...")) - else if (gametype == GT_COOP) + else if (G_PlatformGametype()) { - if (stplyr->lives <= 0 + if (gametype == GT_COOP + && stplyr->lives <= 0 && cv_cooplives.value == 2 && (netgame || multiplayer)) { @@ -2230,7 +2231,7 @@ static void ST_drawTextHUD(void) else textHUDdraw(M_GetText("Wait to respawn...")) } - else + else if (G_GametypeHasSpectators()) textHUDdraw(M_GetText("\x82""FIRE:""\x80 Enter game")) } From 78074246335834088fc14a3f80ad133f095a1476 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 12:30:01 -0300 Subject: [PATCH 083/195] NUMGAMETYPES vs gametypecount --- src/d_clisrv.c | 2 +- src/d_main.c | 2 +- src/d_netcmd.c | 14 +++++++------- src/doomstat.h | 2 +- src/g_game.c | 8 ++++---- src/hu_stuff.c | 2 +- src/m_menu.c | 2 +- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index bfc478bd5..4468502d0 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2114,7 +2114,7 @@ static void CL_ConnectToServer(boolean viams) UINT8 num = serverlist[i].info.gametype; const char *gametypestr = NULL; CONS_Printf(M_GetText("Connecting to: %s\n"), serverlist[i].info.servername); - if (num < NUMGAMETYPES) + if (num < gametypecount) gametypestr = Gametype_Names[num]; if (gametypestr) CONS_Printf(M_GetText("Gametype: %s\n"), gametypestr); diff --git a/src/d_main.c b/src/d_main.c index 815136440..50da0a629 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1409,7 +1409,7 @@ void D_SRB2Main(void) if (newgametype == -1) // reached end of the list with no match { j = atoi(sgametype); // assume they gave us a gametype number, which is okay too - if (j >= 0 && j < NUMGAMETYPES) + if (j >= 0 && j < gametypecount) newgametype = (INT16)j; } diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 7b8095555..e0cc32914 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -383,7 +383,7 @@ boolean timedemo_quit; INT16 gametype = GT_COOP; UINT32 gametyperules = 0; -INT16 numgametypes = (GT_CTF + 1); +INT16 gametypecount = (GT_CTF + 1); boolean splitscreen = false; boolean circuitmap = false; @@ -1943,7 +1943,7 @@ static void Command_Map_f(void) if (isdigit(gametypename[0])) { d = atoi(gametypename); - if (d >= 0 && d < NUMGAMETYPES) + if (d >= 0 && d < gametypecount) newgametype = d; else { @@ -1951,7 +1951,7 @@ static void Command_Map_f(void) "Gametype number %d is out of range. Use a number between" " 0 and %d inclusive. ...Or just use the name. :v\n", d, - NUMGAMETYPES-1); + gametypecount-1); Z_Free(realmapname); Z_Free(mapname); return; @@ -2072,7 +2072,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) gametype = READUINT8(*cp); G_SetGametype(gametype); // I fear putting that macro as an argument - if (gametype < 0 || gametype >= NUMGAMETYPES) + if (gametype < 0 || gametype >= gametypecount) gametype = lastgametype; else if (gametype != lastgametype) D_GameTypeChanged(lastgametype); // emulate consvar_t behavior for gametype @@ -3624,7 +3624,7 @@ static void Command_ShowGametype_f(void) } // get name string for current gametype - if (gametype >= 0 && gametype < NUMGAMETYPES) + if (gametype >= 0 && gametype < gametypecount) gametypestr = Gametype_Names[gametype]; if (gametypestr) @@ -3891,9 +3891,9 @@ void D_GameTypeChanged(INT32 lastgametype) { const char *oldgt = NULL, *newgt = NULL; - if (lastgametype >= 0 && lastgametype < NUMGAMETYPES) + if (lastgametype >= 0 && lastgametype < gametypecount) oldgt = Gametype_Names[lastgametype]; - if (gametype >= 0 && lastgametype < NUMGAMETYPES) + if (gametype >= 0 && lastgametype < gametypecount) newgt = Gametype_Names[gametype]; if (oldgt && newgt) diff --git a/src/doomstat.h b/src/doomstat.h index 66f7f3008..f51f75fb8 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -85,7 +85,7 @@ extern boolean multiplayer; extern INT16 gametype; extern UINT32 gametyperules; -extern INT16 numgametypes; +extern INT16 gametypecount; extern boolean splitscreen; extern boolean circuitmap; // Does this level have 'circuit mode'? diff --git a/src/g_game.c b/src/g_game.c index e70d4a6d1..619950882 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3102,15 +3102,15 @@ void G_SetGametype(INT16 gtype) INT16 G_NewGametype(UINT32 rules) { INT32 i; - INT16 newgtype = numgametypes; - numgametypes++; + INT16 newgtype = gametypecount; + gametypecount++; // Set gametype rules. - gametypedefaultrules[newgtype] = numgametypes; + gametypedefaultrules[newgtype] = gametypecount; Gametype_Names[newgtype] = "???"; // Update gametype_cons_t accordingly. - for (i = 0; i < numgametypes; i++) + for (i = 0; i < gametypecount; i++) { gametype_cons_t[i].value = i; gametype_cons_t[i].strvalue = Gametype_Names[i]; diff --git a/src/hu_stuff.c b/src/hu_stuff.c index e67249953..1e9b4f14a 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2066,7 +2066,7 @@ static void HU_drawGametype(void) { const char *strvalue = NULL; - if (gametype < 0 || gametype >= NUMGAMETYPES) + if (gametype < 0 || gametype >= gametypecount) return; // not a valid gametype??? strvalue = Gametype_Names[gametype]; diff --git a/src/m_menu.c b/src/m_menu.c index 23dc10701..c257adfd6 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -9932,7 +9932,7 @@ static void M_DrawConnectMenu(void) va("Ping: %u", (UINT32)LONG(serverlist[slindex].info.time))); gt = "Unknown"; - if (serverlist[slindex].info.gametype < NUMGAMETYPES) + if (serverlist[slindex].info.gametype < gametypecount) gt = Gametype_Names[serverlist[slindex].info.gametype]; V_DrawSmallString(currentMenu->x+46,S_LINEY(i)+8, globalflags, From aa619e1b34c6d0481096c4e98e980f5662f27421 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 12:36:02 -0300 Subject: [PATCH 084/195] Rankings tweaks --- src/d_clisrv.c | 2 +- src/hu_stuff.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 4468502d0..d1dee3985 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2111,7 +2111,7 @@ static void CL_ConnectToServer(boolean viams) if (i != -1) { - UINT8 num = serverlist[i].info.gametype; + UINT16 num = serverlist[i].info.gametype; const char *gametypestr = NULL; CONS_Printf(M_GetText("Connecting to: %s\n"), serverlist[i].info.servername); if (num < gametypecount) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 1e9b4f14a..8cbfa77d3 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -3026,7 +3026,7 @@ static void HU_DrawRankings(void) // draw the current gametype in the lower right HU_drawGametype(); - if (gametype != GT_RACE && gametype != GT_COMPETITION && gametype != GT_COOP) + if (!G_PlatformGametype()) { if (cv_timelimit.value && timelimitintics > 0) { @@ -3083,7 +3083,7 @@ static void HU_DrawRankings(void) if (!playeringame[j]) continue; - if (gametype != GT_COOP && players[j].spectator) + if (!G_PlatformGametype() && players[j].spectator) continue; for (i = 0; i < MAXPLAYERS; i++) @@ -3091,7 +3091,7 @@ static void HU_DrawRankings(void) if (!playeringame[i]) continue; - if (gametype != GT_COOP && players[i].spectator) + if (!G_PlatformGametype() && players[i].spectator) continue; if (gametype == GT_RACE) From 45580ce5576acc7b59e8b67008483e52bb41b050 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 12:36:54 -0300 Subject: [PATCH 085/195] Make NUMGAMETYPEFREESLOTS lower because netcode --- src/doomstat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doomstat.h b/src/doomstat.h index f51f75fb8..4d17b5c79 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -389,7 +389,7 @@ enum TypeOfLevel }; // Gametypes -#define NUMGAMETYPEFREESLOTS 512 +#define NUMGAMETYPEFREESLOTS 128 enum GameType { GT_COOP = 0, // also used in single player From b759ebf62292a2833df742562aea78d66c5fc6b8 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 12:40:46 -0300 Subject: [PATCH 086/195] Death of TOL_CUSTOM --- src/dehacked.c | 3 --- src/doomstat.h | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 175c1fcfa..5cfe953b8 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1114,8 +1114,6 @@ static const struct { {"TAG",TOL_TAG}, {"CTF",TOL_CTF}, - {"CUSTOM",TOL_CUSTOM}, - {"2D",TOL_2D}, {"MARIO",TOL_MARIO}, {"NIGHTS",TOL_NIGHTS}, @@ -9042,7 +9040,6 @@ struct { {"TOL_MATCH",TOL_MATCH}, {"TOL_TAG",TOL_TAG}, {"TOL_CTF",TOL_CTF}, - {"TOL_CUSTOM",TOL_CUSTOM}, {"TOL_2D",TOL_2D}, {"TOL_MARIO",TOL_MARIO}, {"TOL_NIGHTS",TOL_NIGHTS}, diff --git a/src/doomstat.h b/src/doomstat.h index 4d17b5c79..5bc64ae7e 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -287,7 +287,7 @@ typedef struct char lvlttl[22]; ///< Level name without "Zone". (21 character limit instead of 32, 21 characters can display on screen max anyway) char subttl[33]; ///< Subtitle for level UINT8 actnum; ///< Act number or 0 for none. - UINT16 typeoflevel; ///< Combination of typeoflevel flags. + UINT32 typeoflevel; ///< Combination of typeoflevel flags. INT16 nextlevel; ///< Map number of next level, or 1100-1102 to end. char musname[7]; ///< Music track to play. "" for no music. UINT16 mustrack; ///< Subsong to play. Only really relevant for music modules and specific formats supported by GME. 0 to ignore. @@ -379,7 +379,7 @@ enum TypeOfLevel TOL_CTF = 0x40, ///< Capture the Flag // CTF default = 64 - TOL_CUSTOM = 0x80, ///< Custom (Lua-scripted, etc.) + //TOL_CUSTOM = 0x80, ///< Custom (Lua-scripted, etc.) TOL_2D = 0x0100, ///< 2D TOL_MARIO = 0x0200, ///< Mario From 79d5192b7c8de8d8afe27b431e714d9f76020e3f Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 13:24:10 -0300 Subject: [PATCH 087/195] TOL/Level platter stuff --- src/dehacked.c | 6 ++--- src/doomstat.h | 61 +++++++++++++++++++++++++++-------------------- src/g_game.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++---- src/g_game.h | 7 +++++- src/m_menu.c | 5 +++- src/m_menu.h | 1 + 6 files changed, 109 insertions(+), 35 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 5cfe953b8..3f018bee8 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1095,10 +1095,8 @@ static void readsprite2(MYFILE *f, INT32 num) Z_Free(s); } -static const struct { - const char *name; - const UINT16 flag; -} TYPEOFLEVEL[] = { +INT32 numtolinfo = NUMBASETOL; +tolinfo_t TYPEOFLEVEL[NUMMAXTOL] = { {"SOLO",TOL_SP}, {"SP",TOL_SP}, {"SINGLEPLAYER",TOL_SP}, diff --git a/src/doomstat.h b/src/doomstat.h index 5bc64ae7e..f143151af 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -39,7 +39,7 @@ extern UINT32 mapmusposition; #define MUSIC_FORCERESET 0x4000 // -*-------------- // Use other bits if necessary. -extern INT16 maptol; +extern UINT32 maptol; extern UINT8 globalweather; extern INT32 curWeather; extern INT32 cursaveslot; @@ -364,30 +364,6 @@ typedef struct extern mapheader_t* mapheaderinfo[NUMMAPS]; -enum TypeOfLevel -{ - TOL_SP = 0x01, ///< Single Player - TOL_COOP = 0x02, ///< Cooperative - TOL_COMPETITION = 0x04, ///< Competition - TOL_RACE = 0x08, ///< Race -// Single Player default = 15 - - TOL_MATCH = 0x10, ///< Match - TOL_TAG = 0x20, ///< Tag -// Match/Tag default = 48 - - TOL_CTF = 0x40, ///< Capture the Flag -// CTF default = 64 - - //TOL_CUSTOM = 0x80, ///< Custom (Lua-scripted, etc.) - - TOL_2D = 0x0100, ///< 2D - TOL_MARIO = 0x0200, ///< Mario - TOL_NIGHTS = 0x0400, ///< NiGHTS - TOL_ERZ3 = 0x0800, ///< ERZ3 - TOL_XMAS = 0x1000 ///< Christmas NiGHTS -}; - // Gametypes #define NUMGAMETYPEFREESLOTS 128 enum GameType @@ -441,6 +417,41 @@ enum GameTypeRules // String names for gametypes extern const char *Gametype_Names[NUMGAMETYPES]; +enum TypeOfLevel +{ + TOL_SP = 0x01, ///< Single Player + TOL_COOP = 0x02, ///< Cooperative + TOL_COMPETITION = 0x04, ///< Competition + TOL_RACE = 0x08, ///< Race +// Single Player default = 15 + + TOL_MATCH = 0x10, ///< Match + TOL_TAG = 0x20, ///< Tag +// Match/Tag default = 48 + + TOL_CTF = 0x40, ///< Capture the Flag +// CTF default = 64 + + // 0x80 was here + + TOL_2D = 0x0100, ///< 2D + TOL_MARIO = 0x0200, ///< Mario + TOL_NIGHTS = 0x0400, ///< NiGHTS + TOL_ERZ3 = 0x0800, ///< ERZ3 + TOL_XMAS = 0x1000, ///< Christmas NiGHTS +}; + +#define NUMBASETOL 18 +#define NUMMAXTOL (18 + NUMGAMETYPEFREESLOTS) + +typedef struct +{ + const char *name; + UINT32 flag; +} tolinfo_t; +extern tolinfo_t TYPEOFLEVEL[NUMMAXTOL]; +extern INT32 numtolinfo; + extern tic_t totalplaytime; extern UINT8 stagefailed; diff --git a/src/g_game.c b/src/g_game.c index 619950882..d66a7454f 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -79,7 +79,7 @@ UINT16 mapmusflags; // Track and reset bit UINT32 mapmusposition; // Position to jump to INT16 gamemap = 1; -INT16 maptol; +UINT32 maptol; UINT8 globalweather = 0; INT32 curWeather = PRECIP_NONE; INT32 cursaveslot = 0; // Auto-save 1p savegame slot @@ -3095,11 +3095,11 @@ void G_SetGametype(INT16 gtype) } // -// G_NewGametype +// G_AddGametype // -// Create a new gametype. Returns the new gametype number. +// Add a gametype. Returns the new gametype number. // -INT16 G_NewGametype(UINT32 rules) +INT16 G_AddGametype(UINT32 rules) { INT32 i; INT16 newgtype = gametypecount; @@ -3121,6 +3121,59 @@ INT16 G_NewGametype(UINT32 rules) return newgtype; } +// +// G_SetGametypeDescription +// +// Set a description for the specified gametype. +// (Level platter) +// +void G_SetGametypeDescription(INT16 gtype, const char *description, UINT8 leftcolor, UINT8 rightcolor) +{ + strncpy(gametypedesc[gtype].notes, description, 441); + gametypedesc[gtype].col[0] = leftcolor; + gametypedesc[gtype].col[1] = rightcolor; +} + +UINT32 gametypetol[NUMGAMETYPES] = +{ + TOL_COOP, // Co-op + TOL_COMPETITION, // Competition + TOL_RACE, // Race + + TOL_MATCH, // Match + TOL_MATCH, // Team Match + + TOL_TAG, // Tag + TOL_TAG, // Hide and Seek + + TOL_CTF, // CTF +}; + +// +// G_AddTOL +// +// Adds a type of level. +// +void G_AddTOL(UINT32 newtol, const char *tolname) +{ + TYPEOFLEVEL[numtolinfo].name = tolname; + TYPEOFLEVEL[numtolinfo].flag = newtol; + numtolinfo++; + + TYPEOFLEVEL[numtolinfo].name = NULL; + TYPEOFLEVEL[numtolinfo].flag = 0; +} + +// +// G_AddTOL +// +// Assigns a type of level to a gametype. +// +void G_AddGametypeTOL(INT16 gametype, UINT32 newtol) +{ + gametypetol[gametype] = newtol; +} + // // G_GetGametypeByName // @@ -3240,6 +3293,8 @@ boolean G_TagGametype(void) INT16 G_TOLFlag(INT32 pgametype) { if (!multiplayer) return TOL_SP; + return gametypetol[pgametype]; +#if 0 if (pgametype == GT_COOP) return TOL_COOP; if (pgametype == GT_COMPETITION) return TOL_COMPETITION; if (pgametype == GT_RACE) return TOL_RACE; @@ -3251,6 +3306,7 @@ INT16 G_TOLFlag(INT32 pgametype) CONS_Alert(CONS_ERROR, M_GetText("Unknown gametype! %d\n"), pgametype); return INT16_MAX; +#endif } /** Select a random map with the given typeoflevel flags. diff --git a/src/g_game.h b/src/g_game.h index ef3e9ffab..fa2ba95fb 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -201,8 +201,13 @@ ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(boolean kill); void G_StopDemo(void); boolean G_CheckDemoStatus(void); +extern INT16 gametypedefaultrules[NUMGAMETYPES]; +extern UINT32 gametypetol[NUMGAMETYPES]; + void G_SetGametype(INT16 gametype); -INT16 G_NewGametype(UINT32 rules); +INT16 G_AddGametype(UINT32 rules); +void G_AddTOL(UINT32 newtol, const char *tolname); +void G_AddGametypeTOL(INT16 gametype, UINT32 newtol); INT32 G_GetGametypeByName(const char *gametypestr); boolean G_IsSpecialStage(INT32 mapnum); diff --git a/src/m_menu.c b/src/m_menu.c index c257adfd6..6699ed924 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -605,7 +605,7 @@ static menuitem_t MISC_ChangeTeamMenu[] = {IT_WHITESTRING|IT_CALL, NULL, "Confirm", M_ConfirmTeamChange, 90}, }; -static const gtdesc_t gametypedesc[] = +gtdesc_t gametypedesc[NUMGAMETYPES] = { {{ 54, 54}, "Play through the single-player campaign with your friends, teaming up to beat Dr Eggman's nefarious challenges!"}, {{103, 103}, "Speed your way through the main acts, competing in several different categories to see who's the best."}, @@ -4684,6 +4684,9 @@ static boolean M_CanShowLevelOnPlatter(INT32 mapnum, INT32 gt) if (gt == GT_RACE && (mapheaderinfo[mapnum]->typeoflevel & TOL_RACE)) return true; + if (gt > 0 && gt < gametypecount && (mapheaderinfo[mapnum]->typeoflevel & gametypetol[gt])) + return true; + return false; case LLM_LEVELSELECT: diff --git a/src/m_menu.h b/src/m_menu.h index ce9b422dc..19858e2fc 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -371,6 +371,7 @@ typedef struct UINT8 col[2]; char notes[441]; } gtdesc_t; +extern gtdesc_t gametypedesc[NUMGAMETYPES]; // mode descriptions for video mode menu typedef struct From 1e2331d672f7ca349efe9624a7b9e37526eeeb22 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 14:37:48 -0300 Subject: [PATCH 088/195] SOC stuff --- src/dehacked.c | 246 ++++++++++++++++++++++++++++++++++++++++++++++++- src/doomstat.h | 1 + src/g_game.c | 34 ++++++- src/g_game.h | 2 + 4 files changed, 278 insertions(+), 5 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 3f018bee8..5ade1b2bd 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -76,6 +76,7 @@ static UINT16 get_mus(const char *word, UINT8 dehacked_mode); static hudnum_t get_huditem(const char *word); static menutype_t get_menutype(const char *word); #ifndef HAVE_BLUA +static INT16 get_gametype(const char *word); static powertype_t get_power(const char *word); #endif @@ -1124,6 +1125,145 @@ tolinfo_t TYPEOFLEVEL[NUMMAXTOL] = { {NULL, 0} }; +// copypasted from readPlayer :sleep: +static void readgametype(MYFILE *f, char *gtname) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word; + char *word2; + char *tmp; + INT32 i; + + INT16 newgtidx = 0; + UINT32 newgtrules = 0; + UINT32 newgttol = 0; + UINT8 newgtleftcolor = 0; + UINT8 newgtrightcolor = 0; + char gtdescription[441]; + const char *gtnamestring; + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + word = strtok(s, " "); + if (word) + strupr(word); + else + break; + + if (fastcmp(word, "DESCRIPTION")) + { + char *descr = NULL; + + for (i = 0; i < MAXLINELEN-3; i++) + { + if (s[i] == '=') + { + descr = &s[i+2]; + break; + } + } + if (descr) + { + strcpy(gtdescription, descr); + strcat(gtdescription, myhashfgets(descr, sizeof (gtdescription), f)); + } + else + strcpy(gtdescription, ""); + + // For some reason, cutting the string did not work above. Most likely due to strcpy or strcat... + // It works down here, though. + { + INT32 numline = 0; + for (i = 0; i < MAXLINELEN-1; i++) + { + if (numline < 20 && gtdescription[i] == '\n') + numline++; + + if (numline >= 20 || gtdescription[i] == '\0' || gtdescription[i] == '#') + break; + } + } + gtdescription[strlen(gtdescription)-1] = '\0'; + gtdescription[i] = '\0'; + continue; + } + + word2 = strtok(NULL, " = "); + if (word2) + strupr(word2); + else + break; + + if (word2[strlen(word2)-1] == '\n') + word2[strlen(word2)-1] = '\0'; + i = atoi(word2); + + if (fastcmp(word, "RULES")) + { + // Game type rules (GTR_) + newgtrules = (UINT32)get_number(word2); + } + else if (fastcmp(word, "HEADERCOLOR") || fastcmp(word, "HEADERCOLOUR")) + { + // Level platter + newgtleftcolor = newgtrightcolor = (UINT8)get_number(word2); + } + else if (fastcmp(word, "HEADERLEFTCOLOR") || fastcmp(word, "HEADERLEFTCOLOUR")) + { + // Level platter + newgtleftcolor = (UINT8)get_number(word2); + } + else if (fastcmp(word, "HEADERRIGHTCOLOR") || fastcmp(word, "HEADERRIGHTCOLOUR")) + { + // Level platter + newgtrightcolor = (UINT8)get_number(word2); + } + else if (fastcmp(word, "TYPEOFLEVEL")) + { + if (i) // it's just a number + newgttol = (UINT16)i; + else + { + UINT16 tol = 0; + tmp = strtok(word2,","); + do { + for (i = 0; TYPEOFLEVEL[i].name; i++) + if (fastcmp(tmp, TYPEOFLEVEL[i].name)) + break; + if (!TYPEOFLEVEL[i].name) + deh_warning("readgametype %s: unknown typeoflevel flag %s\n", gtname, tmp); + tol |= TYPEOFLEVEL[i].flag; + } while((tmp = strtok(NULL,",")) != NULL); + newgttol = tol; + } + } + else + deh_warning("readgametype %s: unknown word '%s'", gtname, word); + } + } while (!myfeof(f)); // finish when the line is empty + Z_Free(s); + + // Add the new gametype + newgtidx = G_AddGametype(newgtrules); + G_AddGametypeTOL(newgtidx, newgttol); + G_SetGametypeDescription(newgtidx, gtdescription, newgtleftcolor, newgtrightcolor); + + // Write the new gametype name. + gtnamestring = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + memcpy((void *)gtnamestring, gtname, MAXLINELEN); + Gametype_Names[newgtidx] = gtnamestring; + + // Update gametype_cons_t accordingly. + G_UpdateGametypeSelections(); + + CONS_Printf("Added gametype %s\n", Gametype_Names[newgtidx]); +} + static const struct { const char *name; const mobjtype_t type; @@ -4151,6 +4291,7 @@ static void ignorelines(MYFILE *f) static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) { char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char textline[MAXLINELEN]; char *word; char *word2; INT32 i; @@ -4171,6 +4312,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) char *traverse; myfgets(s, MAXLINELEN, f); + memcpy(textline, s, MAXLINELEN); if (s[0] == '\n' || s[0] == '#') continue; @@ -4359,6 +4501,36 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) ignorelines(f); } } + else if (fastcmp(word, "GAMETYPE")) + { + // Get the gametype name from textline + // instead of word2, so that gametype names + // aren't allcaps + INT32 i; + for (i = 0; i < MAXLINELEN; i++) + { + if (textline[i] == '\0') + break; + if (textline[i] == ' ') + { + char *gtname = (textline+i+1); + if (gtname) + { + // remove funny characters + INT32 j; + for (j = 0; j < (MAXLINELEN - i); j++) + { + if (gtname[j] == '\0') + break; + if (gtname[j] < 32 || gtname[j] > 127) + gtname[j] = '\0'; + } + readgametype(f, gtname); + } + break; + } + } + } else if (fastcmp(word, "CUTSCENE")) { if (i > 0 && i < 129) @@ -8615,6 +8787,26 @@ static const char *const PLAYERFLAG_LIST[] = { NULL // stop loop here. }; +static const char *const GAMETYPERULE_LIST[] = { + "PLATFORM", + "TAG", + "RINGSLINGER", + "SPECTATORS", + "TEAMS", + "LIVES", + "RACE", + "CHASECAM", + "TIMELIMIT", + "HIDETIME", + "HIDETIMEFROZEN", + "BLINDFOLDED", + "EMERALDS", + "TEAMFLAGS", + "PITYSHIELD", + "DEATHPENALTY", + NULL +}; + #ifdef HAVE_BLUA // Linedef flags static const char *const ML_LIST[16] = { @@ -9227,6 +9419,7 @@ struct { {"DMG_DEATHMASK",DMG_DEATHMASK}, // Gametypes, for use with global var "gametype" + // Left them here just in case?? {"GT_COOP",GT_COOP}, {"GT_COMPETITION",GT_COMPETITION}, {"GT_RACE",GT_RACE}, @@ -9679,6 +9872,20 @@ static menutype_t get_menutype(const char *word) } #ifndef HAVE_BLUA +static INT16 get_gametype(const char *word) +{ // Returns the value of GT_ enumerations + INT16 i; + if (*word >= '0' && *word <= '9') + return atoi(word); + if (fastncmp("GT_",word,3)) + word += 3; // take off the GT_ + for (i = 0; i < NUMGAMETYPES; i++) + if (fastcmp(word, Gametype_ConstantNames[i]+3)) + return i; + deh_warning("Couldn't find gametype named 'GT_%s'",word); + return GT_COOP; +} + static powertype_t get_power(const char *word) { // Returns the vlaue of pw_ enumerations powertype_t i; @@ -9842,6 +10049,19 @@ static fixed_t find_const(const char **rword) free(word); return 0; } + else if (fastncmp("GTR_", word, 4)) { + char *p = word+4; + for (i = 0; GAMETYPERULE_LIST[i]; i++) + if (fastcmp(p, GAMETYPERULE_LIST[i])) { + free(word); + return (1< Date: Wed, 18 Dec 2019 14:47:39 -0300 Subject: [PATCH 089/195] GTR_NOSPECTATORSPAWN --- src/d_netcmd.c | 7 ++++++- src/dehacked.c | 1 + src/doomstat.h | 41 ++++++++++++++++++++--------------------- 3 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index e0cc32914..959ed875f 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3636,7 +3636,11 @@ static void Command_ShowGametype_f(void) static void Command_SetGametype_f(void) { if (COM_Argc() > 1) + { + INT16 oldgametype = gametype; G_SetGametype(atoi(COM_Argv(1))); + D_GameTypeChanged(oldgametype); + } } /** Plays the intro. @@ -3978,6 +3982,7 @@ void D_GameTypeChanged(INT32 lastgametype) // When swapping to a gametype that supports spectators, // make everyone a spectator initially. + // Averted with GTR_NOSPECTATORSPAWN. if (!splitscreen && (G_GametypeHasSpectators())) { INT32 i; @@ -3985,7 +3990,7 @@ void D_GameTypeChanged(INT32 lastgametype) if (playeringame[i]) { players[i].ctfteam = 0; - players[i].spectator = true; + players[i].spectator = (gametyperules & GTR_NOSPECTATORSPAWN) ? false : true; } } diff --git a/src/dehacked.c b/src/dehacked.c index 5ade1b2bd..b316fb40e 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8804,6 +8804,7 @@ static const char *const GAMETYPERULE_LIST[] = { "TEAMFLAGS", "PITYSHIELD", "DEATHPENALTY", + "NOSPECTATORSPAWN", NULL }; diff --git a/src/doomstat.h b/src/doomstat.h index 1d6d85017..7d6839e52 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -389,29 +389,28 @@ enum GameType // Game type rules enum GameTypeRules { - GTR_PLATFORM = 1, // Co-op, Competition, and Race - GTR_TAG = 1<<1, // Tag and Hide and Seek - GTR_RINGSLINGER = 1<<2, // Not Co-op, not Competition, and not Race (overriden by cv_ringslinger) - GTR_SPECTATORS = 1<<3, // Not Co-op, not Competition, and not Race - GTR_TEAMS = 1<<4, // Team Match, CTF - GTR_LIVES = 1<<5, // A lot of special cases in G_GametypeUsesLives actually, but just Co-op and Competition - GTR_RACE = 1<<6, // Race and Competition + GTR_PLATFORM = 1, // Co-op, Competition, and Race + GTR_TAG = 1<<1, // Tag and Hide and Seek + GTR_RINGSLINGER = 1<<2, // Not Co-op, not Competition, and not Race (overriden by cv_ringslinger) + GTR_SPECTATORS = 1<<3, // Not Co-op, not Competition, and not Race + GTR_TEAMS = 1<<4, // Team Match, CTF + GTR_LIVES = 1<<5, // A lot of special cases in G_GametypeUsesLives actually, but just Co-op and Competition + GTR_RACE = 1<<6, // Race and Competition // Lactozilla - // Awesome! Those are new game type rules - // provided by yours truly to allow for more - // flexibility! Those will replace some - // straight-up gametype checks scattered - // around the source code! - GTR_CHASECAM = 1<<7, // Prefer chasecam at map load (All platform gametypes) - GTR_TIMELIMIT = 1<<8, // Ringslinger time limit (Tag and Hide and Seek) - GTR_HIDETIME = 1<<9, // Tag and Hide and Seek - GTR_HIDETIMEFROZEN = 1<<10, // Hide and Seek, but not Tag - GTR_BLINDFOLDED = 1<<11, // Blindfolded view (Tag and Hide and Seek) - GTR_EMERALDS = 1<<12, // Ringslinger emeralds (Match and CTF) - GTR_TEAMFLAGS = 1<<13, // Gametype has team flags (CTF) - GTR_PITYSHIELD = 1<<14, // Award pity shield - GTR_DEATHPENALTY = 1<<15, // Death score penalty + // Awesome! Those are new game type rules provided by yours truly to allow for more + // flexibility! Those will replace some straight-up gametype checks scattered around the source code! + + GTR_CHASECAM = 1<<7, // Prefer chasecam at map load (All platform gametypes) + GTR_TIMELIMIT = 1<<8, // Ringslinger time limit (Tag and Hide and Seek) + GTR_HIDETIME = 1<<9, // Tag and Hide and Seek + GTR_HIDETIMEFROZEN = 1<<10, // Hide and Seek, but not Tag + GTR_BLINDFOLDED = 1<<11, // Blindfolded view (Tag and Hide and Seek) + GTR_EMERALDS = 1<<12, // Ringslinger emeralds (Match and CTF) + GTR_TEAMFLAGS = 1<<13, // Gametype has team flags (CTF) + GTR_PITYSHIELD = 1<<14, // Award pity shield + GTR_DEATHPENALTY = 1<<15, // Death score penalty + GTR_NOSPECTATORSPAWN = 1<<16, // For use with GTR_SPECTATORS - spawn in the map instead of with the spectators }; // String names for gametypes From d3d91726f54184969a69463b8fedf70417224af5 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 14:57:42 -0300 Subject: [PATCH 090/195] GTR_EMERALDHUNT and GTR_SPAWNENEMIES --- src/dehacked.c | 2 ++ src/doomstat.h | 2 ++ src/g_game.c | 9 ++++----- src/g_game.h | 2 +- src/p_mobj.c | 4 ++-- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index b316fb40e..7e584cbf8 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8805,6 +8805,8 @@ static const char *const GAMETYPERULE_LIST[] = { "PITYSHIELD", "DEATHPENALTY", "NOSPECTATORSPAWN", + "EMERALDHUNT", + "SPAWNENEMIES", NULL }; diff --git a/src/doomstat.h b/src/doomstat.h index 7d6839e52..a1c347b62 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -411,6 +411,8 @@ enum GameTypeRules GTR_PITYSHIELD = 1<<14, // Award pity shield GTR_DEATHPENALTY = 1<<15, // Death score penalty GTR_NOSPECTATORSPAWN = 1<<16, // For use with GTR_SPECTATORS - spawn in the map instead of with the spectators + GTR_EMERALDHUNT = 1<<17, // Emerald Hunt + GTR_SPAWNENEMIES = 1<<18, // Spawn enemies }; // String names for gametypes diff --git a/src/g_game.c b/src/g_game.c index 07a6034bb..1974c271f 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3075,14 +3075,14 @@ const char *Gametype_ConstantNames[NUMGAMETYPES] = }; // Game type rules -INT16 gametypedefaultrules[NUMGAMETYPES] = +UINT32 gametypedefaultrules[NUMGAMETYPES] = { // Co-op - GTR_PLATFORM|GTR_LIVES|GTR_CHASECAM, + GTR_PLATFORM|GTR_LIVES|GTR_CHASECAM|GTR_EMERALDHUNT|GTR_SPAWNENEMIES, // Competition - GTR_PLATFORM|GTR_LIVES|GTR_RACE|GTR_CHASECAM, + GTR_PLATFORM|GTR_LIVES|GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES, // Race - GTR_PLATFORM|GTR_RACE|GTR_CHASECAM, + GTR_PLATFORM|GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES, // Match GTR_RINGSLINGER|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_EMERALDS|GTR_PITYSHIELD|GTR_DEATHPENALTY, @@ -3116,7 +3116,6 @@ void G_SetGametype(INT16 gtype) // INT16 G_AddGametype(UINT32 rules) { - INT32 i; INT16 newgtype = gametypecount; gametypecount++; diff --git a/src/g_game.h b/src/g_game.h index e2eea52c1..81998b6e6 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -201,7 +201,7 @@ ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(boolean kill); void G_StopDemo(void); boolean G_CheckDemoStatus(void); -extern INT16 gametypedefaultrules[NUMGAMETYPES]; +extern UINT32 gametypedefaultrules[NUMGAMETYPES]; extern UINT32 gametypetol[NUMGAMETYPES]; void G_SetGametype(INT16 gametype); diff --git a/src/p_mobj.c b/src/p_mobj.c index 193746db8..1913ef91f 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11682,7 +11682,7 @@ You should think about modifying the deathmatch starts to take full advantage of if (i == MT_EMERHUNT) { // Emerald Hunt is Coop only. - if (gametype != GT_COOP) + if (!(gametyperules & GTR_EMERALDHUNT)) return; ss = R_PointInSubsector(mthing->x << FRACBITS, mthing->y << FRACBITS); @@ -11708,7 +11708,7 @@ You should think about modifying the deathmatch starts to take full advantage of runemeraldmanager = true; } - if (!G_PlatformGametype()) // No enemies in match or CTF modes + if (!(gametyperules & GTR_SPAWNENEMIES)) // No enemies in match or CTF modes if ((mobjinfo[i].flags & MF_ENEMY) || (mobjinfo[i].flags & MF_BOSS)) return; From 7768e2c7f9ff46fcd82bf7bbd3e270fec34b29d2 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 15:14:24 -0300 Subject: [PATCH 091/195] More spectator tweaks --- src/p_mobj.c | 6 +++++- src/st_stuff.c | 36 +++++++++++++++++++----------------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 1913ef91f..12409a18a 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11249,8 +11249,12 @@ void P_SpawnPlayer(INT32 playernum) else { p->outofcoop = false; + p->spectator = false; if (netgame && p->jointime < 1) - p->spectator = true; + { + // Averted by GTR_NOSPECTATORSPAWN. + p->spectator = (gametyperules & GTR_NOSPECTATORSPAWN) ? false : true; + } else if (multiplayer && !netgame) { // If you're in a team game and you don't have a team assigned yet... diff --git a/src/st_stuff.c b/src/st_stuff.c index 54bd36ac0..1c9b4614e 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -2205,31 +2205,33 @@ static void ST_drawTextHUD(void) textHUDdraw(M_GetText("\x82""Wait for the stage to end...")) else if (G_PlatformGametype()) { - if (gametype == GT_COOP - && stplyr->lives <= 0 - && cv_cooplives.value == 2 - && (netgame || multiplayer)) + if (gametype == GT_COOP) { - INT32 i; - for (i = 0; i < MAXPLAYERS; i++) + if (stplyr->lives <= 0 + && cv_cooplives.value == 2 + && (netgame || multiplayer)) { - if (!playeringame[i]) - continue; + INT32 i; + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; - if (&players[i] == stplyr) - continue; + if (&players[i] == stplyr) + continue; - if (players[i].lives > 1) - break; - } + if (players[i].lives > 1) + break; + } - if (i != MAXPLAYERS) - textHUDdraw(M_GetText("You'll steal a life on respawn...")) + if (i != MAXPLAYERS) + textHUDdraw(M_GetText("You'll steal a life on respawn...")) + else + textHUDdraw(M_GetText("Wait to respawn...")) + } else textHUDdraw(M_GetText("Wait to respawn...")) } - else - textHUDdraw(M_GetText("Wait to respawn...")) } else if (G_GametypeHasSpectators()) textHUDdraw(M_GetText("\x82""FIRE:""\x80 Enter game")) From 7c3cde4564c84475514689d0998e75d8e08db12e Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 15:23:41 -0300 Subject: [PATCH 092/195] How did I mess this up? --- src/g_game.c | 2 +- src/p_mobj.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 1974c271f..fe4c93de9 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3120,7 +3120,7 @@ INT16 G_AddGametype(UINT32 rules) gametypecount++; // Set gametype rules. - gametypedefaultrules[newgtype] = gametypecount; + gametypedefaultrules[newgtype] = rules; Gametype_Names[newgtype] = "???"; // Update gametype_cons_t accordingly. diff --git a/src/p_mobj.c b/src/p_mobj.c index 12409a18a..8c5497e26 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11249,7 +11249,6 @@ void P_SpawnPlayer(INT32 playernum) else { p->outofcoop = false; - p->spectator = false; if (netgame && p->jointime < 1) { // Averted by GTR_NOSPECTATORSPAWN. From 94f2b8f9709d1e15fc4a6edb60c78c14a196d8b2 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 15:41:03 -0300 Subject: [PATCH 093/195] Fix warnings --- src/dehacked.c | 19 ++++++++----------- src/g_game.c | 10 +++++----- src/g_game.h | 6 +++--- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 7e584cbf8..b62f0cfbe 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1140,7 +1140,6 @@ static void readgametype(MYFILE *f, char *gtname) UINT8 newgtleftcolor = 0; UINT8 newgtrightcolor = 0; char gtdescription[441]; - const char *gtnamestring; do { @@ -1254,9 +1253,7 @@ static void readgametype(MYFILE *f, char *gtname) G_SetGametypeDescription(newgtidx, gtdescription, newgtleftcolor, newgtrightcolor); // Write the new gametype name. - gtnamestring = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); - memcpy((void *)gtnamestring, gtname, MAXLINELEN); - Gametype_Names[newgtidx] = gtnamestring; + Gametype_Names[newgtidx] = Z_StrDup((const char *)gtname); // Update gametype_cons_t accordingly. G_UpdateGametypeSelections(); @@ -4506,23 +4503,23 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) // Get the gametype name from textline // instead of word2, so that gametype names // aren't allcaps - INT32 i; - for (i = 0; i < MAXLINELEN; i++) + INT32 c; + for (c = 0; c < MAXLINELEN; c++) { - if (textline[i] == '\0') + if (textline[c] == '\0') break; - if (textline[i] == ' ') + if (textline[c] == ' ') { - char *gtname = (textline+i+1); + char *gtname = (textline+c+1); if (gtname) { // remove funny characters INT32 j; - for (j = 0; j < (MAXLINELEN - i); j++) + for (j = 0; j < (MAXLINELEN - c); j++) { if (gtname[j] == '\0') break; - if (gtname[j] < 32 || gtname[j] > 127) + if (gtname[j] < 32) gtname[j] = '\0'; } readgametype(f, gtname); diff --git a/src/g_game.c b/src/g_game.c index fe4c93de9..aa1d2a174 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3152,9 +3152,9 @@ void G_UpdateGametypeSelections(void) // Set a description for the specified gametype. // (Level platter) // -void G_SetGametypeDescription(INT16 gtype, char *description, UINT8 leftcolor, UINT8 rightcolor) +void G_SetGametypeDescription(INT16 gtype, char *descriptiontext, UINT8 leftcolor, UINT8 rightcolor) { - strncpy(gametypedesc[gtype].notes, description, 441); + strncpy(gametypedesc[gtype].notes, descriptiontext, 441); gametypedesc[gtype].col[0] = leftcolor; gametypedesc[gtype].col[1] = rightcolor; } @@ -3194,9 +3194,9 @@ void G_AddTOL(UINT32 newtol, const char *tolname) // // Assigns a type of level to a gametype. // -void G_AddGametypeTOL(INT16 gametype, UINT32 newtol) +void G_AddGametypeTOL(INT16 gtype, UINT32 newtol) { - gametypetol[gametype] = newtol; + gametypetol[gtype] = newtol; } // @@ -3342,7 +3342,7 @@ INT16 G_TOLFlag(INT32 pgametype) * has those flags. * \author Graue */ -static INT16 RandMap(INT16 tolflags, INT16 pprevmap) +static INT16 RandMap(UINT32 tolflags, INT16 pprevmap) { INT16 *okmaps = Z_Malloc(NUMMAPS * sizeof(INT16), PU_STATIC, NULL); INT32 numokmaps = 0; diff --git a/src/g_game.h b/src/g_game.h index 81998b6e6..6b29ef836 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -206,10 +206,10 @@ extern UINT32 gametypetol[NUMGAMETYPES]; void G_SetGametype(INT16 gametype); INT16 G_AddGametype(UINT32 rules); -void G_UpdateGametypeSelections(); +void G_UpdateGametypeSelections(void); void G_AddTOL(UINT32 newtol, const char *tolname); -void G_AddGametypeTOL(INT16 gametype, UINT32 newtol); -void G_SetGametypeDescription(INT16 gtype, char *description, UINT8 leftcolor, UINT8 rightcolor); +void G_AddGametypeTOL(INT16 gtype, UINT32 newtol); +void G_SetGametypeDescription(INT16 gtype, char *descriptiontext, UINT8 leftcolor, UINT8 rightcolor); INT32 G_GetGametypeByName(const char *gametypestr); boolean G_IsSpecialStage(INT32 mapnum); From 5b0a094f67fe881934f788b40702c6e186be0e5e Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 16:00:02 -0300 Subject: [PATCH 094/195] TOL stuff --- src/dehacked.c | 9 ++++++++- src/doomstat.h | 1 + src/g_game.c | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index b62f0cfbe..e3685e77c 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -591,6 +591,11 @@ static void readfreeslots(MYFILE *f) } else CONS_Alert(CONS_WARNING, "Ran out of free SPR2 slots!\n"); } + else if (fastcmp(type, "TOL")) + { + G_AddTOL(lastcustomtol, word); + lastcustomtol <<= 1; + } else deh_warning("Freeslots: unknown enum class '%s' for '%s_%s'", type, type, word); } @@ -1097,6 +1102,8 @@ static void readsprite2(MYFILE *f, INT32 num) } INT32 numtolinfo = NUMBASETOL; +UINT32 lastcustomtol = (TOL_XMAS << 1); + tolinfo_t TYPEOFLEVEL[NUMMAXTOL] = { {"SOLO",TOL_SP}, {"SP",TOL_SP}, @@ -1232,7 +1239,7 @@ static void readgametype(MYFILE *f, char *gtname) tmp = strtok(word2,","); do { for (i = 0; TYPEOFLEVEL[i].name; i++) - if (fastcmp(tmp, TYPEOFLEVEL[i].name)) + if (fasticmp(tmp, TYPEOFLEVEL[i].name)) break; if (!TYPEOFLEVEL[i].name) deh_warning("readgametype %s: unknown typeoflevel flag %s\n", gtname, tmp); diff --git a/src/doomstat.h b/src/doomstat.h index a1c347b62..daf36647c 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -453,6 +453,7 @@ typedef struct } tolinfo_t; extern tolinfo_t TYPEOFLEVEL[NUMMAXTOL]; extern INT32 numtolinfo; +extern UINT32 lastcustomtol; extern tic_t totalplaytime; diff --git a/src/g_game.c b/src/g_game.c index aa1d2a174..a2f95b5d9 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3181,7 +3181,7 @@ UINT32 gametypetol[NUMGAMETYPES] = // void G_AddTOL(UINT32 newtol, const char *tolname) { - TYPEOFLEVEL[numtolinfo].name = tolname; + TYPEOFLEVEL[numtolinfo].name = Z_StrDup(tolname); TYPEOFLEVEL[numtolinfo].flag = newtol; numtolinfo++; From e3584e82302da82a18c372fa23789fb55979b382 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 16:52:05 -0300 Subject: [PATCH 095/195] GTR_ALLOWEXIT --- src/dehacked.c | 1 + src/doomstat.h | 1 + src/g_game.c | 6 +++--- src/p_spec.c | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index e3685e77c..9b2c07838 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8811,6 +8811,7 @@ static const char *const GAMETYPERULE_LIST[] = { "NOSPECTATORSPAWN", "EMERALDHUNT", "SPAWNENEMIES", + "ALLOWEXIT", NULL }; diff --git a/src/doomstat.h b/src/doomstat.h index daf36647c..dc551536e 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -413,6 +413,7 @@ enum GameTypeRules GTR_NOSPECTATORSPAWN = 1<<16, // For use with GTR_SPECTATORS - spawn in the map instead of with the spectators GTR_EMERALDHUNT = 1<<17, // Emerald Hunt GTR_SPAWNENEMIES = 1<<18, // Spawn enemies + GTR_ALLOWEXIT = 1<<19, // Allow exit sectors }; // String names for gametypes diff --git a/src/g_game.c b/src/g_game.c index a2f95b5d9..4110bd37e 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3078,11 +3078,11 @@ const char *Gametype_ConstantNames[NUMGAMETYPES] = UINT32 gametypedefaultrules[NUMGAMETYPES] = { // Co-op - GTR_PLATFORM|GTR_LIVES|GTR_CHASECAM|GTR_EMERALDHUNT|GTR_SPAWNENEMIES, + GTR_PLATFORM|GTR_LIVES|GTR_CHASECAM|GTR_EMERALDHUNT|GTR_SPAWNENEMIES|GTR_ALLOWEXIT, // Competition - GTR_PLATFORM|GTR_LIVES|GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES, + GTR_PLATFORM|GTR_LIVES|GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT, // Race - GTR_PLATFORM|GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES, + GTR_PLATFORM|GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT, // Match GTR_RINGSLINGER|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_EMERALDS|GTR_PITYSHIELD|GTR_DEATHPENALTY, diff --git a/src/p_spec.c b/src/p_spec.c index 161d73e0e..2aa91e95e 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -4678,7 +4678,7 @@ DoneSection2: } case 2: // Special stage GOAL sector / Exit Sector / CTF Flag Return - if (player->bot || !G_PlatformGametype()) + if (player->bot || !(gametyperules & GTR_ALLOWEXIT)) break; if (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap) && player->nightstime > 6) { From 5f73d4861490ad336d8ee27042aea55790574740 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 17:13:05 -0300 Subject: [PATCH 096/195] Some sort of intermission tally support. --- src/dehacked.c | 119 ++++++++++++++++++++++++++++++++----------------- src/doomstat.h | 1 + src/g_game.c | 16 +++---- src/y_inter.c | 5 ++- src/y_inter.h | 1 + 5 files changed, 91 insertions(+), 51 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 9b2c07838..4bf0f31ae 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -22,6 +22,7 @@ #include "m_menu.h" #include "m_misc.h" #include "f_finale.h" +#include "y_inter.h" #include "dehacked.h" #include "st_stuff.h" #include "i_system.h" @@ -1137,7 +1138,7 @@ static void readgametype(MYFILE *f, char *gtname) { char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); char *word; - char *word2; + char *word2, *word2lwr = NULL; char *tmp; INT32 i; @@ -1146,6 +1147,7 @@ static void readgametype(MYFILE *f, char *gtname) UINT32 newgttol = 0; UINT8 newgtleftcolor = 0; UINT8 newgtrightcolor = 0; + int newgtinttype = 0; char gtdescription[441]; do @@ -1201,7 +1203,12 @@ static void readgametype(MYFILE *f, char *gtname) word2 = strtok(NULL, " = "); if (word2) + { + if (!word2lwr) + word2lwr = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + strcpy(word2lwr, word2); strupr(word2); + } else break; @@ -1229,10 +1236,15 @@ static void readgametype(MYFILE *f, char *gtname) // Level platter newgtrightcolor = (UINT8)get_number(word2); } + else if (fastcmp(word, "INTERMISSIONTYPE")) + { + // Case sensitive + newgtinttype = (int)get_number(word2lwr); + } else if (fastcmp(word, "TYPEOFLEVEL")) { if (i) // it's just a number - newgttol = (UINT16)i; + newgttol = (UINT32)i; else { UINT16 tol = 0; @@ -1253,11 +1265,14 @@ static void readgametype(MYFILE *f, char *gtname) } } while (!myfeof(f)); // finish when the line is empty Z_Free(s); + if (word2lwr) + Z_Free(word2lwr); // Add the new gametype newgtidx = G_AddGametype(newgtrules); G_AddGametypeTOL(newgtidx, newgttol); G_SetGametypeDescription(newgtidx, gtdescription, newgtleftcolor, newgtrightcolor); + intermissiontypes[newgtidx] = newgtinttype; // Write the new gametype name. Gametype_Names[newgtidx] = Z_StrDup((const char *)gtname); @@ -1535,7 +1550,7 @@ static void readlevelheader(MYFILE *f, INT32 num) else if (fastcmp(word, "TYPEOFLEVEL")) { if (i) // it's just a number - mapheaderinfo[num-1]->typeoflevel = (UINT16)i; + mapheaderinfo[num-1]->typeoflevel = (UINT32)i; else { UINT16 tol = 0; @@ -8812,6 +8827,7 @@ static const char *const GAMETYPERULE_LIST[] = { "EMERALDHUNT", "SPAWNENEMIES", "ALLOWEXIT", + "ROUNDENDMESSAGE", NULL }; @@ -9230,20 +9246,6 @@ struct { {"tr_trans90",tr_trans90}, {"NUMTRANSMAPS",NUMTRANSMAPS}, - // Type of levels - {"TOL_SP",TOL_SP}, - {"TOL_COOP",TOL_COOP}, - {"TOL_COMPETITION",TOL_COMPETITION}, - {"TOL_RACE",TOL_RACE}, - {"TOL_MATCH",TOL_MATCH}, - {"TOL_TAG",TOL_TAG}, - {"TOL_CTF",TOL_CTF}, - {"TOL_2D",TOL_2D}, - {"TOL_MARIO",TOL_MARIO}, - {"TOL_NIGHTS",TOL_NIGHTS}, - {"TOL_ERZ3",TOL_ERZ3}, - {"TOL_XMAS",TOL_XMAS}, - // Level flags {"LF_SCRIPTISFILE",LF_SCRIPTISFILE}, {"LF_SPEEDMUSIC",LF_SPEEDMUSIC}, @@ -9426,16 +9428,16 @@ struct { {"DMG_CANHURTSELF",DMG_CANHURTSELF}, {"DMG_DEATHMASK",DMG_DEATHMASK}, - // Gametypes, for use with global var "gametype" - // Left them here just in case?? - {"GT_COOP",GT_COOP}, - {"GT_COMPETITION",GT_COMPETITION}, - {"GT_RACE",GT_RACE}, - {"GT_MATCH",GT_MATCH}, - {"GT_TEAMMATCH",GT_TEAMMATCH}, - {"GT_TAG",GT_TAG}, - {"GT_HIDEANDSEEK",GT_HIDEANDSEEK}, - {"GT_CTF",GT_CTF}, + // Intermission types + {"int_none",int_none}, + {"int_coop",int_coop}, + {"int_match",int_match}, + {"int_teammatch",int_teammatch}, + //{"int_tag",int_tag}, + {"int_ctf",int_ctf}, + {"int_spec",int_spec}, + {"int_race",int_race}, + {"int_comp",int_comp}, // Jingles (jingletype_t) {"JT_NONE",JT_NONE}, @@ -9728,7 +9730,7 @@ struct { }; static mobjtype_t get_mobjtype(const char *word) -{ // Returns the vlaue of MT_ enumerations +{ // Returns the value of MT_ enumerations mobjtype_t i; if (*word >= '0' && *word <= '9') return atoi(word); @@ -9895,7 +9897,7 @@ static INT16 get_gametype(const char *word) } static powertype_t get_power(const char *word) -{ // Returns the vlaue of pw_ enumerations +{ // Returns the value of pw_ enumerations powertype_t i; if (*word >= '0' && *word <= '9') return atoi(word); @@ -10057,19 +10059,6 @@ static fixed_t find_const(const char **rword) free(word); return 0; } - else if (fastncmp("GTR_", word, 4)) { - char *p = word+4; - for (i = 0; GAMETYPERULE_LIST[i]; i++) - if (fastcmp(p, GAMETYPERULE_LIST[i])) { - free(word); - return (1< Date: Wed, 18 Dec 2019 18:09:56 -0300 Subject: [PATCH 097/195] Intermission HUD hook for Lua --- src/lua_hud.h | 6 +++++- src/lua_hudlib.c | 30 ++++++++++++++++++++++++++++++ src/y_inter.c | 26 +++++++++++++++++++++++++- 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/src/lua_hud.h b/src/lua_hud.h index abfbba441..396ca8988 100644 --- a/src/lua_hud.h +++ b/src/lua_hud.h @@ -33,6 +33,9 @@ enum hud { hud_coopemeralds, hud_tokens, hud_tabemblems, + // Intermission + hud_intermissiontally, + hud_intermissionmessages, hud_MAX }; @@ -43,4 +46,5 @@ boolean LUA_HudEnabled(enum hud option); void LUAh_GameHUD(player_t *stplyr); void LUAh_ScoresHUD(void); void LUAh_TitleHUD(void); -void LUAh_TitleCardHUD(player_t *stplyr); +void LUAh_TitleCardHUD(player_t *stplayr); +void LUAh_IntermissionHUD(void); diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index a2f48c4ad..211c8a828 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -60,6 +60,9 @@ static const char *const hud_disable_options[] = { "coopemeralds", "tokens", "tabemblems", + + "intermissiontally", + "intermissionmessages", NULL}; enum hudinfo { @@ -92,12 +95,14 @@ static const char *const patch_opt[] = { enum hudhook { hudhook_game = 0, hudhook_scores, + hudhook_intermission, hudhook_title, hudhook_titlecard }; static const char *const hudhook_opt[] = { "game", "scores", + "intermission", "title", "titlecard", NULL}; @@ -1228,4 +1233,29 @@ void LUAh_TitleCardHUD(player_t *stplayr) hud_running = false; } +void LUAh_IntermissionHUD(void) +{ + if (!gL || !(hudAvailable & (1< Date: Wed, 18 Dec 2019 18:30:24 -0300 Subject: [PATCH 098/195] Fix lib_getenum. Also, adding gametypes also creates constant names for them. --- src/dehacked.c | 63 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 4bf0f31ae..474ad2de3 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1140,6 +1140,7 @@ static void readgametype(MYFILE *f, char *gtname) char *word; char *word2, *word2lwr = NULL; char *tmp; + char *gtconst; INT32 i; INT16 newgtidx = 0; @@ -1277,6 +1278,53 @@ static void readgametype(MYFILE *f, char *gtname) // Write the new gametype name. Gametype_Names[newgtidx] = Z_StrDup((const char *)gtname); + // Write the constant name. + gtconst = Z_Malloc(strlen((const char *)gtname) + 3, PU_STATIC, NULL); + // Copy GT_ and the gametype name. + strcpy(gtconst, "GT_"); + strcat(gtconst, (const char *)gtname); + // Make uppercase. + strupr(gtconst); + // Remove characters. +#define REMOVECHAR(chr) \ + word = strchr(gtconst, chr); \ + while (word) \ + { \ + *word = '_'; \ + word = strchr(word, chr); \ + } + + // Space + REMOVECHAR(' ') + // Used for operations + REMOVECHAR('+') + REMOVECHAR('-') + REMOVECHAR('*') + REMOVECHAR('/') + REMOVECHAR('%') + REMOVECHAR('^') + // Part of Lua's syntax + REMOVECHAR('#') + REMOVECHAR('=') + REMOVECHAR('~') + REMOVECHAR('<') + REMOVECHAR('>') + REMOVECHAR('(') + REMOVECHAR(')') + REMOVECHAR('{') + REMOVECHAR('}') + REMOVECHAR('[') + REMOVECHAR(']') + REMOVECHAR(':') + REMOVECHAR(';') + REMOVECHAR(',') + REMOVECHAR('.') + +#undef REMOVECHAR + + // Finally, set the constant string. + Gametype_ConstantNames[newgtidx] = gtconst; + // Update gametype_cons_t accordingly. G_UpdateGametypeSelections(); @@ -10441,13 +10489,13 @@ static inline int lib_getenum(lua_State *L) return 0; } else if (fastncmp("GT_", word, 3)) { - p = word+3; + p = word; for (i = 0; Gametype_ConstantNames[i]; i++) if (fastcmp(p, Gametype_ConstantNames[i])) { - lua_pushinteger(L, ((lua_Integer)1< Date: Wed, 18 Dec 2019 18:39:59 -0300 Subject: [PATCH 099/195] GTR_NOTITLECARD --- src/dehacked.c | 1 + src/doomstat.h | 1 + src/g_game.c | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/dehacked.c b/src/dehacked.c index 474ad2de3..5309058c4 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8876,6 +8876,7 @@ static const char *const GAMETYPERULE_LIST[] = { "SPAWNENEMIES", "ALLOWEXIT", "ROUNDENDMESSAGE", + "NOTITLECARD", NULL }; diff --git a/src/doomstat.h b/src/doomstat.h index d9c93553c..ffce0c814 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -415,6 +415,7 @@ enum GameTypeRules GTR_SPAWNENEMIES = 1<<18, // Spawn enemies GTR_ALLOWEXIT = 1<<19, // Allow exit sectors GTR_ROUNDENDMESSAGE = 1<<20, // Prints "The round has ended." into the console + GTR_NOTITLECARD = 1<<21, // Don't show the title card }; // String names for gametypes diff --git a/src/g_game.c b/src/g_game.c index 62b2eed82..005d37702 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1809,7 +1809,7 @@ void G_StartTitleCard(void) // The title card has been disabled for this map. // Oh well. - if (mapheaderinfo[gamemap-1]->levelflags & LF_NOTITLECARD) + if ((mapheaderinfo[gamemap-1]->levelflags & LF_NOTITLECARD) || (gametyperules & GTR_NOTITLECARD)) { WipeStageTitle = false; return; From b8d47dbc60baa88b4748804facf3b061dd28816f Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 18:50:04 -0300 Subject: [PATCH 100/195] Accept gametype rules in SOC by just their names as parameters. --- src/dehacked.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 5309058c4..1ea3dd0c4 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1134,6 +1134,7 @@ tolinfo_t TYPEOFLEVEL[NUMMAXTOL] = { }; // copypasted from readPlayer :sleep: +static const char *const GAMETYPERULE_LIST[]; static void readgametype(MYFILE *f, char *gtname) { char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); @@ -1141,7 +1142,7 @@ static void readgametype(MYFILE *f, char *gtname) char *word2, *word2lwr = NULL; char *tmp; char *gtconst; - INT32 i; + INT32 i, j; INT16 newgtidx = 0; UINT32 newgtrules = 0; @@ -1261,8 +1262,26 @@ static void readgametype(MYFILE *f, char *gtname) newgttol = tol; } } + // The SOC probably provided gametype rules as words, + // instead of using the RULES keyword. + // Like for example "NOSPECTATORSPAWN = 1". + // This is completely valid, and looks better anyway. else - deh_warning("readgametype %s: unknown word '%s'", gtname, word); + { + UINT32 wordgt = 0; + for (j = 0; GAMETYPERULE_LIST[j]; j++) + if (fastcmp(word, GAMETYPERULE_LIST[j])) { + if (!j) // GTR_PLATFORM + wordgt |= 1; + else + wordgt |= (1< Date: Wed, 18 Dec 2019 18:52:10 -0300 Subject: [PATCH 101/195] Fix comment --- src/dehacked.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dehacked.c b/src/dehacked.c index 1ea3dd0c4..670a16e69 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1264,7 +1264,7 @@ static void readgametype(MYFILE *f, char *gtname) } // The SOC probably provided gametype rules as words, // instead of using the RULES keyword. - // Like for example "NOSPECTATORSPAWN = 1". + // Like for example "NOSPECTATORSPAWN = TRUE". // This is completely valid, and looks better anyway. else { From eadb3dec9e4344e59cbbfe37a4d0b20a35c86ee2 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 18:59:47 -0300 Subject: [PATCH 102/195] Limits checking --- src/dehacked.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 670a16e69..29dbd0b19 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -594,8 +594,13 @@ static void readfreeslots(MYFILE *f) } else if (fastcmp(type, "TOL")) { - G_AddTOL(lastcustomtol, word); - lastcustomtol <<= 1; + if (lastcustomtol > 31) + CONS_Alert(CONS_WARNING, "Ran out of free typeoflevel slots!\n"); + else + { + G_AddTOL((1< Date: Wed, 18 Dec 2019 19:26:45 -0300 Subject: [PATCH 103/195] Ringslinger tweaks --- src/d_netcmd.c | 6 +++--- src/dehacked.c | 5 ++++- src/doomstat.h | 5 ++++- src/g_game.c | 10 +++++----- src/hu_stuff.c | 2 +- src/p_inter.c | 6 +++--- src/st_stuff.c | 2 +- 7 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 959ed875f..67a230289 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3696,7 +3696,7 @@ void ItemFinder_OnChange(void) static void PointLimit_OnChange(void) { // Don't allow pointlimit in Single Player/Co-Op/Race! - if (server && Playing() && G_PlatformGametype()) + if (server && Playing() && !(gametyperules & GTR_POINTLIMIT)) { if (cv_pointlimit.value) CV_StealthSetValue(&cv_pointlimit, 0); @@ -3859,7 +3859,7 @@ UINT32 timelimitintics = 0; static void TimeLimit_OnChange(void) { // Don't allow timelimit in Single Player/Co-Op/Race! - if (server && Playing() && cv_timelimit.value != 0 && G_PlatformGametype()) + if (server && Playing() && cv_timelimit.value != 0 && !(gametyperules & GTR_TIMELIMIT)) { CV_SetValue(&cv_timelimit, 0); return; @@ -3964,7 +3964,7 @@ void D_GameTypeChanged(INT32 lastgametype) // reset timelimit and pointlimit in race/coop, prevent stupid cheats if (server) { - if (G_PlatformGametype()) + if (!(gametyperules & GTR_POINTLIMIT)) { if (cv_timelimit.value) CV_SetValue(&cv_timelimit, 0); diff --git a/src/dehacked.c b/src/dehacked.c index 29dbd0b19..abd0cad7c 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8894,7 +8894,7 @@ static const char *const GAMETYPERULE_LIST[] = { "LIVES", "RACE", "CHASECAM", - "TIMELIMIT", + "\x01", // 1<<8, empty "HIDETIME", "HIDETIMEFROZEN", "BLINDFOLDED", @@ -8908,6 +8908,9 @@ static const char *const GAMETYPERULE_LIST[] = { "ALLOWEXIT", "ROUNDENDMESSAGE", "NOTITLECARD", + "POINTLIMIT", + "TIMELIMIT", + "OVERTIME", NULL }; diff --git a/src/doomstat.h b/src/doomstat.h index ffce0c814..de0058766 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -402,7 +402,7 @@ enum GameTypeRules // flexibility! Those will replace some straight-up gametype checks scattered around the source code! GTR_CHASECAM = 1<<7, // Prefer chasecam at map load (All platform gametypes) - GTR_TIMELIMIT = 1<<8, // Ringslinger time limit (Tag and Hide and Seek) + // 1<<8, empty GTR_HIDETIME = 1<<9, // Tag and Hide and Seek GTR_HIDETIMEFROZEN = 1<<10, // Hide and Seek, but not Tag GTR_BLINDFOLDED = 1<<11, // Blindfolded view (Tag and Hide and Seek) @@ -416,6 +416,9 @@ enum GameTypeRules GTR_ALLOWEXIT = 1<<19, // Allow exit sectors GTR_ROUNDENDMESSAGE = 1<<20, // Prints "The round has ended." into the console GTR_NOTITLECARD = 1<<21, // Don't show the title card + GTR_POINTLIMIT = 1<<22, // Ringslinger point limit + GTR_TIMELIMIT = 1<<23, // Ringslinger time limit + GTR_OVERTIME = 1<<24, // Allow overtime }; // String names for gametypes diff --git a/src/g_game.c b/src/g_game.c index 005d37702..443ea69a7 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3085,17 +3085,17 @@ UINT32 gametypedefaultrules[NUMGAMETYPES] = GTR_PLATFORM|GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_ROUNDENDMESSAGE, // Match - GTR_RINGSLINGER|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_EMERALDS|GTR_PITYSHIELD|GTR_DEATHPENALTY|GTR_ROUNDENDMESSAGE, + GTR_RINGSLINGER|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_EMERALDS|GTR_PITYSHIELD|GTR_DEATHPENALTY|GTR_ROUNDENDMESSAGE, // Team Match - GTR_RINGSLINGER|GTR_TEAMS|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_PITYSHIELD|GTR_ROUNDENDMESSAGE, + GTR_RINGSLINGER|GTR_TEAMS|GTR_POINTLIMIT|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_PITYSHIELD|GTR_ROUNDENDMESSAGE, // Tag - GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED|GTR_ROUNDENDMESSAGE, + GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED|GTR_ROUNDENDMESSAGE, // Hide and Seek - GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED|GTR_ROUNDENDMESSAGE, + GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT||GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED|GTR_ROUNDENDMESSAGE, // CTF - GTR_RINGSLINGER|GTR_TEAMS|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_EMERALDS|GTR_TEAMFLAGS|GTR_PITYSHIELD|GTR_ROUNDENDMESSAGE, + GTR_RINGSLINGER|GTR_TEAMS|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_EMERALDS|GTR_TEAMFLAGS|GTR_PITYSHIELD|GTR_ROUNDENDMESSAGE, }; // diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 8cbfa77d3..bcad6ebef 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -3026,7 +3026,7 @@ static void HU_DrawRankings(void) // draw the current gametype in the lower right HU_drawGametype(); - if (!G_PlatformGametype()) + if (gametyperules & GTR_POINTLIMIT) { if (cv_timelimit.value && timelimitintics > 0) { diff --git a/src/p_inter.c b/src/p_inter.c index 21c3d4049..1f2390de0 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2093,7 +2093,7 @@ void P_CheckTimeLimit(void) if (!(multiplayer || netgame)) return; - if (G_PlatformGametype()) + if (!(gametyperules & GTR_TIMELIMIT)) return; if (leveltime < timelimitintics) @@ -2124,7 +2124,7 @@ void P_CheckTimeLimit(void) } //Optional tie-breaker for Match/CTF - else if (cv_overtime.value) + else if ((cv_overtime.value) && (gametyperules & GTR_OVERTIME)) { INT32 playerarray[MAXPLAYERS]; INT32 tempplayer = 0; @@ -2206,7 +2206,7 @@ void P_CheckPointLimit(void) if (!(multiplayer || netgame)) return; - if (G_PlatformGametype()) + if (!(gametyperules & GTR_POINTLIMIT)) return; // pointlimit is nonzero, check if it's been reached by this player diff --git a/src/st_stuff.c b/src/st_stuff.c index 1c9b4614e..4c3f57412 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -2638,7 +2638,7 @@ static void ST_overlayDrawer(void) } // If you are in overtime, put a big honkin' flashin' message on the screen. - if (G_RingSlingerGametype() && cv_overtime.value + if (((gametyperules & GTR_TIMELIMIT) && (gametyperules & GTR_OVERTIME)) && cv_overtime.value && (leveltime > (timelimitintics + TICRATE/2)) && cv_timelimit.value && (leveltime/TICRATE % 2 == 0)) V_DrawCenteredString(BASEVIDWIDTH/2, 184, V_PERPLAYER, M_GetText("OVERTIME!")); From 04ee98a1a179793835a799b285c4c03ac7148276 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 19:43:12 -0300 Subject: [PATCH 104/195] point limit/time limit --- src/d_netcmd.c | 13 +++++++++++++ src/d_netcmd.h | 5 ++++- src/dehacked.c | 26 ++++++++++++++++---------- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 67a230289..aaaf33cb5 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -328,6 +328,10 @@ consvar_t cv_numlaps = {"numlaps", "4", CV_NETVAR|CV_CALL|CV_NOINIT, numlaps_con static CV_PossibleValue_t basenumlaps_cons_t[] = {{1, "MIN"}, {50, "MAX"}, {0, "Map default"}, {0, NULL}}; consvar_t cv_basenumlaps = {"basenumlaps", "Map default", CV_NETVAR|CV_CALL|CV_CHEAT, basenumlaps_cons_t, BaseNumLaps_OnChange, 0, NULL, NULL, 0, 0, NULL}; +// Point and time limits for every gametype +INT32 pointlimits[NUMGAMETYPES]; +INT32 timelimits[NUMGAMETYPES]; + // log elemental hazards -- not a netvar, is local to current player consvar_t cv_hazardlog = {"hazardlog", "Yes", 0, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -3951,6 +3955,15 @@ void D_GameTypeChanged(INT32 lastgametype) if (!cv_itemrespawntime.changed) CV_Set(&cv_itemrespawntime, cv_itemrespawntime.defaultvalue); // respawn normally break; + default: + if (!cv_timelimit.changed && !cv_pointlimit.changed) // user hasn't changed limits + { + CV_SetValue(&cv_timelimit, timelimits[gametype]); + CV_SetValue(&cv_pointlimit, pointlimits[gametype]); + } + if (!cv_itemrespawntime.changed) + CV_Set(&cv_itemrespawntime, cv_itemrespawntime.defaultvalue); // respawn normally + break; } } else if (!multiplayer && !netgame) diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 8f857c6db..cd2efe2e3 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -60,9 +60,12 @@ extern consvar_t cv_flagtime; extern consvar_t cv_touchtag; extern consvar_t cv_hidetime; -extern consvar_t cv_friendlyfire; extern consvar_t cv_pointlimit; extern consvar_t cv_timelimit; +extern INT32 pointlimits[NUMGAMETYPES]; +extern INT32 timelimits[NUMGAMETYPES]; + +extern consvar_t cv_friendlyfire; extern consvar_t cv_numlaps; extern consvar_t cv_basenumlaps; extern UINT32 timelimitintics; diff --git a/src/dehacked.c b/src/dehacked.c index abd0cad7c..cbbbe8d77 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1152,6 +1152,8 @@ static void readgametype(MYFILE *f, char *gtname) INT16 newgtidx = 0; UINT32 newgtrules = 0; UINT32 newgttol = 0; + INT32 newgtpointlimit = 0; + INT32 newgttimelimit = 0; UINT8 newgtleftcolor = 0; UINT8 newgtrightcolor = 0; int newgtinttype = 0; @@ -1223,31 +1225,31 @@ static void readgametype(MYFILE *f, char *gtname) word2[strlen(word2)-1] = '\0'; i = atoi(word2); + // Game type rules if (fastcmp(word, "RULES")) { - // Game type rules (GTR_) + // GTR_ newgtrules = (UINT32)get_number(word2); } + // Point and time limits + else if (fastcmp(word, "DEFAULTPOINTLIMIT")) + newgtpointlimit = (INT32)i; + else if (fastcmp(word, "DEFAULTTIMELIMIT")) + newgttimelimit = (INT32)i; + // Level platter else if (fastcmp(word, "HEADERCOLOR") || fastcmp(word, "HEADERCOLOUR")) - { - // Level platter newgtleftcolor = newgtrightcolor = (UINT8)get_number(word2); - } else if (fastcmp(word, "HEADERLEFTCOLOR") || fastcmp(word, "HEADERLEFTCOLOUR")) - { - // Level platter newgtleftcolor = (UINT8)get_number(word2); - } else if (fastcmp(word, "HEADERRIGHTCOLOR") || fastcmp(word, "HEADERRIGHTCOLOUR")) - { - // Level platter newgtrightcolor = (UINT8)get_number(word2); - } + // Type of intermission else if (fastcmp(word, "INTERMISSIONTYPE")) { // Case sensitive newgtinttype = (int)get_number(word2lwr); } + // Type of level else if (fastcmp(word, "TYPEOFLEVEL")) { if (i) // it's just a number @@ -1304,7 +1306,11 @@ static void readgametype(MYFILE *f, char *gtname) newgtidx = G_AddGametype(newgtrules); G_AddGametypeTOL(newgtidx, newgttol); G_SetGametypeDescription(newgtidx, gtdescription, newgtleftcolor, newgtrightcolor); + + // Not covered by G_AddGametype alone. intermissiontypes[newgtidx] = newgtinttype; + pointlimits[newgtidx] = newgtpointlimit; + timelimits[newgtidx] = newgttimelimit; // Write the new gametype name. Gametype_Names[newgtidx] = Z_StrDup((const char *)gtname); From d0e18444fbc5ba14119b0bfaf53a3e4a18b791e8 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 20:12:52 -0300 Subject: [PATCH 105/195] GTR_FRIENDLYFIRE, renamed GTR_HIDETIMEFROZEN, fixed other mistakes --- src/d_netcmd.c | 8 ++++---- src/d_netcmd.h | 5 +---- src/dehacked.c | 4 ++-- src/doomstat.h | 10 +++++++--- src/g_game.c | 2 +- src/p_inter.c | 12 ++++++------ src/st_stuff.c | 2 +- 7 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index aaaf33cb5..158b1f802 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2419,7 +2419,7 @@ static void Command_Teamchange_f(void) } //additional check for hide and seek. Don't allow change of status after hidetime ends. - if ((gametyperules & GTR_HIDETIMEFROZEN) && leveltime >= (hidetime * TICRATE)) + if ((gametyperules & GTR_HIDEFROZEN) && leveltime >= (hidetime * TICRATE)) { CONS_Alert(CONS_NOTICE, M_GetText("Hiding time expired; no Hide and Seek status changes allowed!\n")); return; @@ -2516,7 +2516,7 @@ static void Command_Teamchange2_f(void) } //additional check for hide and seek. Don't allow change of status after hidetime ends. - if ((gametyperules & GTR_HIDETIMEFROZEN) && leveltime >= (hidetime * TICRATE)) + if ((gametyperules & GTR_HIDEFROZEN) && leveltime >= (hidetime * TICRATE)) { CONS_Alert(CONS_NOTICE, M_GetText("Hiding time expired; no Hide and Seek status changes allowed!\n")); return; @@ -2645,7 +2645,7 @@ static void Command_ServerTeamChange_f(void) } //additional check for hide and seek. Don't allow change of status after hidetime ends. - if ((gametyperules & GTR_HIDETIMEFROZEN) && leveltime >= (hidetime * TICRATE)) + if ((gametyperules & GTR_HIDEFROZEN) && leveltime >= (hidetime * TICRATE)) { CONS_Alert(CONS_NOTICE, M_GetText("Hiding time expired; no Hide and Seek status changes allowed!\n")); return; @@ -2735,7 +2735,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) } //no status changes after hidetime - if ((gametyperules & GTR_HIDETIMEFROZEN) && (leveltime >= (hidetime * TICRATE))) + if ((gametyperules & GTR_HIDEFROZEN) && (leveltime >= (hidetime * TICRATE))) error = true; //Make sure that the right team number is sent. Keep in mind that normal clients cannot change to certain teams in certain gametypes. diff --git a/src/d_netcmd.h b/src/d_netcmd.h index cd2efe2e3..8f857c6db 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -60,12 +60,9 @@ extern consvar_t cv_flagtime; extern consvar_t cv_touchtag; extern consvar_t cv_hidetime; +extern consvar_t cv_friendlyfire; extern consvar_t cv_pointlimit; extern consvar_t cv_timelimit; -extern INT32 pointlimits[NUMGAMETYPES]; -extern INT32 timelimits[NUMGAMETYPES]; - -extern consvar_t cv_friendlyfire; extern consvar_t cv_numlaps; extern consvar_t cv_basenumlaps; extern UINT32 timelimitintics; diff --git a/src/dehacked.c b/src/dehacked.c index cbbbe8d77..676d0e144 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8900,9 +8900,9 @@ static const char *const GAMETYPERULE_LIST[] = { "LIVES", "RACE", "CHASECAM", - "\x01", // 1<<8, empty + "FRIENDLYFIRE", "HIDETIME", - "HIDETIMEFROZEN", + "HIDEFROZEN", "BLINDFOLDED", "EMERALDS", "TEAMFLAGS", diff --git a/src/doomstat.h b/src/doomstat.h index de0058766..459bfc88f 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -402,9 +402,9 @@ enum GameTypeRules // flexibility! Those will replace some straight-up gametype checks scattered around the source code! GTR_CHASECAM = 1<<7, // Prefer chasecam at map load (All platform gametypes) - // 1<<8, empty - GTR_HIDETIME = 1<<9, // Tag and Hide and Seek - GTR_HIDETIMEFROZEN = 1<<10, // Hide and Seek, but not Tag + GTR_FRIENDLYFIRE = 1<<8, // Always allow friendly fire + GTR_HIDETIME = 1<<9, // Hide time (Tag and Hide and Seek) + GTR_HIDEFROZEN = 1<<10, // Frozen after hide time (Hide and Seek, but not Tag) GTR_BLINDFOLDED = 1<<11, // Blindfolded view (Tag and Hide and Seek) GTR_EMERALDS = 1<<12, // Ringslinger emeralds (Match and CTF) GTR_TEAMFLAGS = 1<<13, // Gametype has team flags (CTF) @@ -425,6 +425,10 @@ enum GameTypeRules extern const char *Gametype_Names[NUMGAMETYPES]; extern const char *Gametype_ConstantNames[NUMGAMETYPES]; +// Point and time limits for every gametype +extern INT32 pointlimits[NUMGAMETYPES]; +extern INT32 timelimits[NUMGAMETYPES]; + enum TypeOfLevel { TOL_SP = 0x01, ///< Single Player diff --git a/src/g_game.c b/src/g_game.c index 443ea69a7..02b32bd48 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3092,7 +3092,7 @@ UINT32 gametypedefaultrules[NUMGAMETYPES] = // Tag GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED|GTR_ROUNDENDMESSAGE, // Hide and Seek - GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT||GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED|GTR_ROUNDENDMESSAGE, + GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED|GTR_ROUNDENDMESSAGE, // CTF GTR_RINGSLINGER|GTR_TEAMS|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_EMERALDS|GTR_TEAMFLAGS|GTR_PITYSHIELD|GTR_ROUNDENDMESSAGE, diff --git a/src/p_inter.c b/src/p_inter.c index 1f2390de0..900435a99 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -3042,7 +3042,7 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou return false; // Ignore IT players shooting each other, unless friendlyfire is on. - if ((player->pflags & PF_TAGIT && !((cv_friendlyfire.value || (damagetype & DMG_CANHURTSELF)) && + if ((player->pflags & PF_TAGIT && !((cv_friendlyfire.value || (gametyperules & GTR_FRIENDLYFIRE) || (damagetype & DMG_CANHURTSELF)) && source && source->player && source->player->pflags & PF_TAGIT))) { if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) @@ -3058,7 +3058,7 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou // Don't allow players on the same team to hurt one another, // unless cv_friendlyfire is on. - if (!(cv_friendlyfire.value || (damagetype & DMG_CANHURTSELF)) && (player->pflags & PF_TAGIT) == (source->player->pflags & PF_TAGIT)) + if (!(cv_friendlyfire.value || (gametyperules & GTR_FRIENDLYFIRE) || (damagetype & DMG_CANHURTSELF)) && (player->pflags & PF_TAGIT) == (source->player->pflags & PF_TAGIT)) { if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) { @@ -3143,7 +3143,7 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj return false; // In COOP/RACE, you can't hurt other players unless cv_friendlyfire is on - if (!cv_friendlyfire.value && (G_PlatformGametype())) + if (!(cv_friendlyfire.value || (gametyperules & GTR_FRIENDLYFIRE)) && (G_PlatformGametype())) { if (gametype == GT_COOP && inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) // co-op only { @@ -3166,7 +3166,7 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj { // Don't allow players on the same team to hurt one another, // unless cv_friendlyfire is on. - if (!cv_friendlyfire.value && target->player->ctfteam == source->player->ctfteam) + if (!(cv_friendlyfire.value || (gametyperules & GTR_FRIENDLYFIRE)) && target->player->ctfteam == source->player->ctfteam) { if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) { @@ -3593,7 +3593,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da { if (source == target) return false; // Don't hit yourself with your own paraloop, baka - if (source && source->player && !cv_friendlyfire.value + if (source && source->player && !(cv_friendlyfire.value || (gametyperules & GTR_FRIENDLYFIRE)) && (gametype == GT_COOP || (G_GametypeHasTeams() && player->ctfteam == source->player->ctfteam))) return false; // Don't run eachother over in special stages and team games and such @@ -3688,7 +3688,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da // by friendly fire. Spilling their rings and other items is enough. else if (!force && G_GametypeHasTeams() && source && source->player && (source->player->ctfteam == player->ctfteam) - && cv_friendlyfire.value) + && (cv_friendlyfire.value || (gametyperules & GTR_FRIENDLYFIRE))) { damage = 0; P_ShieldDamage(player, inflictor, source, damage, damagetype); diff --git a/src/st_stuff.c b/src/st_stuff.c index 4c3f57412..b822678ff 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -2298,7 +2298,7 @@ static void ST_drawTextHUD(void) textHUDdraw(M_GetText("\x82""VIEWPOINT:""\x80 Switch view")) donef12 = true; } - if (gametyperules & GTR_HIDETIMEFROZEN) + if (gametyperules & GTR_HIDEFROZEN) textHUDdraw(M_GetText("You cannot move while hiding.")) } } From f584b61c93a97e1a9852f306acba673ced21e03a Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 18 Dec 2019 15:34:55 -0800 Subject: [PATCH 106/195] Use a random port when connecting --- src/d_clisrv.c | 2 +- src/d_net.h | 2 ++ src/i_tcp.c | 14 ++++++++++---- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 7b6c35eb6..6520a1aa1 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -70,7 +70,7 @@ boolean server = true; // true or false but !server == client #define client (!server) boolean nodownload = false; -static boolean serverrunning = false; +boolean serverrunning = false; INT32 serverplayer = 0; char motd[254], server_context[8]; // Message of the Day, Unique Context (even without Mumble support) diff --git a/src/d_net.h b/src/d_net.h index 8fd6c67b2..c6fe4a27f 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -40,6 +40,8 @@ extern SINT8 nodetoplayer2[MAXNETNODES]; // Say the numplayer for this node if a extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game +extern boolean serverrunning; + INT32 Net_GetFreeAcks(boolean urgent); void Net_AckTicker(void); diff --git a/src/i_tcp.c b/src/i_tcp.c index 2dd9f0591..bd35a292a 100644 --- a/src/i_tcp.c +++ b/src/i_tcp.c @@ -887,6 +887,7 @@ static boolean UDP_Socket(void) #ifdef HAVE_IPV6 const INT32 b_ipv6 = M_CheckParm("-ipv6"); #endif + const char *serv; for (s = 0; s < mysocketses; s++) @@ -902,11 +903,16 @@ static boolean UDP_Socket(void) hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; + if (serverrunning) + serv = port_name; + else + serv = NULL;/* any port */ + if (M_CheckParm("-bindaddr")) { while (M_IsNextParm()) { - gaie = I_getaddrinfo(M_GetNextParm(), port_name, &hints, &ai); + gaie = I_getaddrinfo(M_GetNextParm(), serv, &hints, &ai); if (gaie == 0) { runp = ai; @@ -927,7 +933,7 @@ static boolean UDP_Socket(void) } else { - gaie = I_getaddrinfo("0.0.0.0", port_name, &hints, &ai); + gaie = I_getaddrinfo("0.0.0.0", serv, &hints, &ai); if (gaie == 0) { runp = ai; @@ -960,7 +966,7 @@ static boolean UDP_Socket(void) { while (M_IsNextParm()) { - gaie = I_getaddrinfo(M_GetNextParm(), port_name, &hints, &ai); + gaie = I_getaddrinfo(M_GetNextParm(), serv, &hints, &ai); if (gaie == 0) { runp = ai; @@ -981,7 +987,7 @@ static boolean UDP_Socket(void) } else { - gaie = I_getaddrinfo("::", port_name, &hints, &ai); + gaie = I_getaddrinfo("::", serv, &hints, &ai); if (gaie == 0) { runp = ai; From 4e321012894b2aa87e312597f19be26b30545a8b Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 18 Dec 2019 15:43:29 -0800 Subject: [PATCH 107/195] Use a pointer for port_name Using strcpy is stupid because we don't know how long the argument would be. There's no need for a buffer anyway. --- src/i_tcp.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/i_tcp.c b/src/i_tcp.c index bd35a292a..8ead73c3a 100644 --- a/src/i_tcp.c +++ b/src/i_tcp.c @@ -209,7 +209,7 @@ static size_t numbans = 0; static boolean SOCK_bannednode[MAXNETNODES+1]; /// \note do we really need the +1? static boolean init_tcp_driver = false; -static char port_name[8] = DEFAULTPORT; +static const char *port_name = DEFAULTPORT; #ifndef NONET @@ -1431,10 +1431,11 @@ boolean I_InitTcpNetwork(void) // Combined -udpport and -clientport into -port // As it was really redundant having two seperate parms that does the same thing { - if (M_IsNextParm()) - strcpy(port_name, M_GetNextParm()); - else - strcpy(port_name, "0"); + /* + If it's NULL, that's okay! Because then + we'll get a random port from getaddrinfo. + */ + port_name = M_GetNextParm(); } // parse network game options, From 0421c81e042f89af988d12c83b56cef20eb95986 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 20:43:54 -0300 Subject: [PATCH 108/195] ViewpointSwitch hook for Lua --- src/g_game.c | 10 ++++++++++ src/lua_hook.h | 2 ++ src/lua_hooklib.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/src/g_game.c b/src/g_game.c index 02b32bd48..f84829386 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1956,6 +1956,16 @@ boolean G_Responder(event_t *ev) if (!playeringame[displayplayer]) continue; +#ifdef HAVE_BLUA + { + UINT8 canSwitchView = LUAh_ViewpointSwitch(&players[consoleplayer], &players[displayplayer]); + if (canSwitchView == 1) // Set viewpoint to this player + break; + else if (canSwitchView == 2) // Skip this player + continue; + } +#endif + if (players[displayplayer].spectator) continue; diff --git a/src/lua_hook.h b/src/lua_hook.h index 6617bca93..592a93acc 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -51,6 +51,7 @@ enum hook { hook_PlayerCanDamage, hook_PlayerQuit, hook_IntermissionThinker, + hook_ViewpointSwitch, hook_MAX // last hook }; @@ -93,5 +94,6 @@ boolean LUAh_FollowMobj(player_t *player, mobj_t *mobj); // Hook for P_PlayerAft UINT8 LUAh_PlayerCanDamage(player_t *player, mobj_t *mobj); // Hook for P_PlayerCanDamage void LUAh_PlayerQuit(player_t *plr, int reason); // Hook for player quitting void LUAh_IntermissionThinker(void); // Hook for Y_Ticker +UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer); // Hook for spy mode in G_Responder #endif diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index ef87d0b6f..b1f702f7c 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -62,6 +62,7 @@ const char *const hookNames[hook_MAX+1] = { "PlayerCanDamage", "PlayerQuit", "IntermissionThinker", + "ViewpointSwitch", NULL }; @@ -203,6 +204,7 @@ static int lib_addHook(lua_State *L) case hook_PlayerSpawn: case hook_FollowMobj: case hook_PlayerCanDamage: + case hook_ViewpointSwitch: case hook_ShieldSpawn: case hook_ShieldSpecial: lastp = &playerhooks; @@ -1346,4 +1348,49 @@ void LUAh_IntermissionThinker(void) } } +// Hook for spy mode in G_Responder +UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer) +{ + hook_p hookp; + UINT8 canSwitchView = 0; // 0 = default, 1 = force yes, 2 = force no. + if (!gL || !(hooksAvailable[hook_ViewpointSwitch/8] & (1<<(hook_ViewpointSwitch%8)))) + return 0; + + lua_settop(gL, 0); + + for (hookp = playerhooks; hookp; hookp = hookp->next) + { + if (hookp->type != hook_ViewpointSwitch) + continue; + + if (lua_gettop(gL) == 0) + { + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, newdisplayplayer, META_PLAYER); + } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { // if nil, leave canSwitchView = 0. + if (lua_toboolean(gL, -1)) + canSwitchView = 1; // Force viewpoint switch + else + canSwitchView = 2; // Skip viewpoint switch + } + lua_pop(gL, 1); + } + + lua_settop(gL, 0); + return canSwitchView; +} + #endif From 843d9b9f0a345330d97c579e94f208eb2b65c156 Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 18 Dec 2019 15:47:47 -0800 Subject: [PATCH 109/195] -clientport (it's back!) and -serverport, which is an alias to -port If you ever need to, you can change the client port number. --- src/i_tcp.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/i_tcp.c b/src/i_tcp.c index 8ead73c3a..502eb6732 100644 --- a/src/i_tcp.c +++ b/src/i_tcp.c @@ -209,7 +209,8 @@ static size_t numbans = 0; static boolean SOCK_bannednode[MAXNETNODES+1]; /// \note do we really need the +1? static boolean init_tcp_driver = false; -static const char *port_name = DEFAULTPORT; +static const char *serverport_name = DEFAULTPORT; +static const char *clientport_name;/* any port */ #ifndef NONET @@ -904,9 +905,9 @@ static boolean UDP_Socket(void) hints.ai_protocol = IPPROTO_UDP; if (serverrunning) - serv = port_name; + serv = serverport_name; else - serv = NULL;/* any port */ + serv = clientport_name; if (M_CheckParm("-bindaddr")) { @@ -948,8 +949,8 @@ static boolean UDP_Socket(void) #ifdef HAVE_MINIUPNPC if (UPNP_support) { - I_UPnP_rem(port_name, "UDP"); - I_UPnP_add(NULL, port_name, "UDP"); + I_UPnP_rem(serverport_name, "UDP"); + I_UPnP_add(NULL, serverport_name, "UDP"); } #endif } @@ -1427,16 +1428,19 @@ boolean I_InitTcpNetwork(void) if (!I_InitTcpDriver()) return false; - if (M_CheckParm("-port")) + if (M_CheckParm("-port") || M_CheckParm("-serverport")) // Combined -udpport and -clientport into -port // As it was really redundant having two seperate parms that does the same thing + /* Sorry Steel, I'm adding these back. But -udpport is a stupid name. */ { /* If it's NULL, that's okay! Because then we'll get a random port from getaddrinfo. */ - port_name = M_GetNextParm(); + serverport_name = M_GetNextParm(); } + if (M_CheckParm("-clientport")) + clientport_name = M_GetNextParm(); // parse network game options, if (M_CheckParm("-server") || dedicated) From 5e818e1dab6934be29c55b8f5ae4fb14e353a5cf Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 22:02:37 -0300 Subject: [PATCH 110/195] Custom gametype rankings --- src/dehacked.c | 12 +++++++++++- src/g_game.c | 19 ++++++++++++++++++- src/g_game.h | 1 + src/hu_stuff.c | 24 ++++++++++++------------ 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 676d0e144..254f94ade 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1156,6 +1156,7 @@ static void readgametype(MYFILE *f, char *gtname) INT32 newgttimelimit = 0; UINT8 newgtleftcolor = 0; UINT8 newgtrightcolor = 0; + INT16 newgtrankingstype = -1; int newgtinttype = 0; char gtdescription[441]; @@ -1243,7 +1244,13 @@ static void readgametype(MYFILE *f, char *gtname) newgtleftcolor = (UINT8)get_number(word2); else if (fastcmp(word, "HEADERRIGHTCOLOR") || fastcmp(word, "HEADERRIGHTCOLOUR")) newgtrightcolor = (UINT8)get_number(word2); - // Type of intermission + // Rankings type + else if (fastcmp(word, "RANKINGTYPE")) + { + // Case insensitive + newgtrankingstype = (int)get_number(word2); + } + // Intermission type else if (fastcmp(word, "INTERMISSIONTYPE")) { // Case sensitive @@ -1308,6 +1315,9 @@ static void readgametype(MYFILE *f, char *gtname) G_SetGametypeDescription(newgtidx, gtdescription, newgtleftcolor, newgtrightcolor); // Not covered by G_AddGametype alone. + if (newgtrankingstype == -1) + newgtrankingstype = newgtidx; + gametyperankings[newgtidx] = newgtrankingstype; intermissiontypes[newgtidx] = newgtinttype; pointlimits[newgtidx] = newgtpointlimit; timelimits[newgtidx] = newgttimelimit; diff --git a/src/g_game.c b/src/g_game.c index f84829386..04722acbb 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3084,7 +3084,7 @@ const char *Gametype_ConstantNames[NUMGAMETYPES] = "GT_CTF" // GT_CTF }; -// Game type rules +// Gametype rules UINT32 gametypedefaultrules[NUMGAMETYPES] = { // Co-op @@ -3169,6 +3169,23 @@ void G_SetGametypeDescription(INT16 gtype, char *descriptiontext, UINT8 leftcolo gametypedesc[gtype].col[1] = rightcolor; } +// Gametype rankings +INT16 gametyperankings[NUMGAMETYPES] = +{ + GT_COOP, + GT_COMPETITION, + GT_RACE, + + GT_MATCH, + GT_TEAMMATCH, + + GT_TAG, + GT_HIDEANDSEEK, + + GT_CTF, +}; + +// Gametype to TOL (Type Of Level) UINT32 gametypetol[NUMGAMETYPES] = { TOL_COOP, // Co-op diff --git a/src/g_game.h b/src/g_game.h index 6b29ef836..bd0dc0180 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -203,6 +203,7 @@ boolean G_CheckDemoStatus(void); extern UINT32 gametypedefaultrules[NUMGAMETYPES]; extern UINT32 gametypetol[NUMGAMETYPES]; +extern INT16 gametyperankings[NUMGAMETYPES]; void G_SetGametype(INT16 gametype); INT16 G_AddGametype(UINT32 rules); diff --git a/src/hu_stuff.c b/src/hu_stuff.c index bcad6ebef..e95ab7b1b 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2371,7 +2371,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I for (i = 0; i < scorelines; i++) { - if (players[tab[i].num].spectator && gametype != GT_COOP) + if (players[tab[i].num].spectator && gametyperankings[gametype] != GT_COOP) continue; //ignore them. greycheck = greycheckdef; @@ -2434,7 +2434,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I } } - if (G_GametypeUsesLives() && !(gametype == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != INFLIVES)) //show lives + if (G_GametypeUsesLives() && !(gametyperankings[gametype] == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != INFLIVES)) //show lives V_DrawRightAlignedString(x, y+4, V_ALLOWLOWERCASE|(greycheck ? V_60TRANS : 0), va("%dx", players[tab[i].num].lives)); else if (G_TagGametype() && players[tab[i].num].pflags & PF_TAGIT) { @@ -2447,7 +2447,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I if (players[tab[i].num].exiting || (players[tab[i].num].pflags & PF_FINISHED)) V_DrawSmallScaledPatch(x - SHORT(exiticon->width)/2 - 1, y-3, 0, exiticon); - if (gametype == GT_RACE) + if (gametyperankings[gametype] == GT_RACE) { if (circuitmap) { @@ -2726,7 +2726,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline for (i = 0; i < scorelines; i++) { - if (players[tab[i].num].spectator && gametype != GT_COOP) + if (players[tab[i].num].spectator && gametyperankings[gametype] != GT_COOP) continue; //ignore them. greycheck = greycheckdef; @@ -2743,7 +2743,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline | (greycheck ? V_TRANSLUCENT : 0) | V_ALLOWLOWERCASE, name); - if (G_GametypeUsesLives() && !(gametype == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != INFLIVES)) //show lives + if (G_GametypeUsesLives() && !(gametyperankings[gametype] == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != INFLIVES)) //show lives V_DrawRightAlignedString(x, y+4, V_ALLOWLOWERCASE, va("%dx", players[tab[i].num].lives)); else if (G_TagGametype() && players[tab[i].num].pflags & PF_TAGIT) V_DrawSmallScaledPatch(x-28, y-4, 0, tagico); @@ -2792,7 +2792,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline } // All data drawn with thin string for space. - if (gametype == GT_RACE) + if (gametyperankings[gametype] == GT_RACE) { if (circuitmap) { @@ -2832,7 +2832,7 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor for (i = 0; i < scorelines; i++) { - if (players[tab[i].num].spectator && gametype != GT_COOP) + if (players[tab[i].num].spectator && gametyperankings[gametype] != GT_COOP) continue; //ignore them. greycheck = greycheckdef; @@ -2902,7 +2902,7 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor } // All data drawn with thin string for space. - if (gametype == GT_RACE) + if (gametyperankings[gametype] == GT_RACE) { if (circuitmap) { @@ -3040,7 +3040,7 @@ static void HU_DrawRankings(void) V_DrawCenteredString(256, 16, 0, va("%d", cv_pointlimit.value)); } } - else if (gametype == GT_COOP) + else if (gametyperankings[gametype] == GT_COOP) { INT32 totalscore = 0; for (i = 0; i < MAXPLAYERS; i++) @@ -3074,7 +3074,7 @@ static void HU_DrawRankings(void) tab[i].num = -1; tab[i].name = 0; - if (gametype == GT_RACE && !circuitmap) + if (gametyperankings[gametype] == GT_RACE && !circuitmap) tab[i].count = INT32_MAX; } @@ -3094,7 +3094,7 @@ static void HU_DrawRankings(void) if (!G_PlatformGametype() && players[i].spectator) continue; - if (gametype == GT_RACE) + if (gametyperankings[gametype] == GT_RACE) { if (circuitmap) { @@ -3117,7 +3117,7 @@ static void HU_DrawRankings(void) } } } - else if (gametype == GT_COMPETITION) + else if (gametyperankings[gametype] == GT_COMPETITION) { // todo put something more fitting for the gametype here, such as current // number of categories led From 9228f99260c329370a9c1a9dc6ed5ca29650c5d3 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 22:23:30 -0300 Subject: [PATCH 111/195] Fix timelimit/pointlimit checks in HU_DrawRankings, organise rules in gametypedefaultrules a bit --- src/g_game.c | 4 ++-- src/hu_stuff.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 04722acbb..2675930a4 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3097,7 +3097,7 @@ UINT32 gametypedefaultrules[NUMGAMETYPES] = // Match GTR_RINGSLINGER|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_EMERALDS|GTR_PITYSHIELD|GTR_DEATHPENALTY|GTR_ROUNDENDMESSAGE, // Team Match - GTR_RINGSLINGER|GTR_TEAMS|GTR_POINTLIMIT|GTR_SPECTATORS|GTR_TIMELIMIT|GTR_PITYSHIELD|GTR_ROUNDENDMESSAGE, + GTR_RINGSLINGER|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_PITYSHIELD|GTR_ROUNDENDMESSAGE, // Tag GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED|GTR_ROUNDENDMESSAGE, @@ -3105,7 +3105,7 @@ UINT32 gametypedefaultrules[NUMGAMETYPES] = GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED|GTR_ROUNDENDMESSAGE, // CTF - GTR_RINGSLINGER|GTR_TEAMS|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_EMERALDS|GTR_TEAMFLAGS|GTR_PITYSHIELD|GTR_ROUNDENDMESSAGE, + GTR_RINGSLINGER|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_EMERALDS|GTR_TEAMFLAGS|GTR_PITYSHIELD|GTR_ROUNDENDMESSAGE, }; // diff --git a/src/hu_stuff.c b/src/hu_stuff.c index e95ab7b1b..d9801793b 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -3026,15 +3026,15 @@ static void HU_DrawRankings(void) // draw the current gametype in the lower right HU_drawGametype(); - if (gametyperules & GTR_POINTLIMIT) + if (gametyperules & (GTR_TIMELIMIT|GTR_POINTLIMIT)) { - if (cv_timelimit.value && timelimitintics > 0) + if ((gametyperules & GTR_TIMELIMIT) && cv_timelimit.value && timelimitintics > 0) { V_DrawCenteredString(64, 8, 0, "TIME"); V_DrawCenteredString(64, 16, 0, va("%i:%02i", G_TicsToMinutes(stplyr->realtime, true), G_TicsToSeconds(stplyr->realtime))); } - if (cv_pointlimit.value > 0) + if ((gametyperules & GTR_POINTLIMIT) && cv_pointlimit.value > 0) { V_DrawCenteredString(256, 8, 0, "POINT LIMIT"); V_DrawCenteredString(256, 16, 0, va("%d", cv_pointlimit.value)); From 5daedc70e75057ed1323db4ab9e68f876dbd585d Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 22:46:17 -0300 Subject: [PATCH 112/195] Special Stages/token stuff --- src/dehacked.c | 2 ++ src/doomstat.h | 18 ++++++++++-------- src/g_game.c | 6 +++--- src/p_inter.c | 2 +- src/p_mobj.c | 2 +- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 254f94ade..e60bcae5d 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8919,6 +8919,8 @@ static const char *const GAMETYPERULE_LIST[] = { "PITYSHIELD", "DEATHPENALTY", "NOSPECTATORSPAWN", + "SPECIALSTAGES", + "EMERALDTOKENS", "EMERALDHUNT", "SPAWNENEMIES", "ALLOWEXIT", diff --git a/src/doomstat.h b/src/doomstat.h index 459bfc88f..b79edb93c 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -411,14 +411,16 @@ enum GameTypeRules GTR_PITYSHIELD = 1<<14, // Award pity shield GTR_DEATHPENALTY = 1<<15, // Death score penalty GTR_NOSPECTATORSPAWN = 1<<16, // For use with GTR_SPECTATORS - spawn in the map instead of with the spectators - GTR_EMERALDHUNT = 1<<17, // Emerald Hunt - GTR_SPAWNENEMIES = 1<<18, // Spawn enemies - GTR_ALLOWEXIT = 1<<19, // Allow exit sectors - GTR_ROUNDENDMESSAGE = 1<<20, // Prints "The round has ended." into the console - GTR_NOTITLECARD = 1<<21, // Don't show the title card - GTR_POINTLIMIT = 1<<22, // Ringslinger point limit - GTR_TIMELIMIT = 1<<23, // Ringslinger time limit - GTR_OVERTIME = 1<<24, // Allow overtime + GTR_SPECIALSTAGES = 1<<17, // Allow special stages + GTR_EMERALDTOKENS = 1<<18, // Spawn emerald tokens + GTR_EMERALDHUNT = 1<<19, // Emerald Hunt + GTR_SPAWNENEMIES = 1<<20, // Spawn enemies + GTR_ALLOWEXIT = 1<<21, // Allow exit sectors + GTR_ROUNDENDMESSAGE = 1<<22, // Prints "The round has ended." into the console + GTR_NOTITLECARD = 1<<23, // Don't show the title card + GTR_POINTLIMIT = 1<<24, // Ringslinger point limit + GTR_TIMELIMIT = 1<<25, // Ringslinger time limit + GTR_OVERTIME = 1<<26, // Allow overtime }; // String names for gametypes diff --git a/src/g_game.c b/src/g_game.c index 2675930a4..74fd82be6 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3088,9 +3088,9 @@ const char *Gametype_ConstantNames[NUMGAMETYPES] = UINT32 gametypedefaultrules[NUMGAMETYPES] = { // Co-op - GTR_PLATFORM|GTR_LIVES|GTR_CHASECAM|GTR_EMERALDHUNT|GTR_SPAWNENEMIES|GTR_ALLOWEXIT, + GTR_PLATFORM|GTR_LIVES|GTR_CHASECAM|GTR_EMERALDHUNT|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_EMERALDTOKENS|GTR_SPECIALSTAGES, // Competition - GTR_PLATFORM|GTR_LIVES|GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_ROUNDENDMESSAGE, + GTR_PLATFORM|GTR_LIVES|GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_ROUNDENDMESSAGE|GTR_EMERALDTOKENS, // Race GTR_PLATFORM|GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_ROUNDENDMESSAGE, @@ -3530,7 +3530,7 @@ static void G_DoCompleted(void) if (nextmap >= 1100-1 && nextmap <= 1102-1 && (gametyperules & GTR_RACE)) nextmap = (INT16)(spstage_start-1); - if ((gottoken = (gametype == GT_COOP && token))) + if ((gottoken = ((gametyperules & GTR_SPECIALSTAGES) && token))) { token--; diff --git a/src/p_inter.c b/src/p_inter.c index 900435a99..08e8a62a1 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -625,7 +625,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_AddPlayerScore(player, 1000); - if (gametype != GT_COOP || modeattacking) // score only? + if (!(gametyperules & GTR_SPECIALSTAGES) || modeattacking) // score only? { S_StartSound(toucher, sfx_chchng); break; diff --git a/src/p_mobj.c b/src/p_mobj.c index 8c5497e26..c85d2566c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11811,7 +11811,7 @@ You should think about modifying the deathmatch starts to take full advantage of return; // no doubles } - if (i == MT_TOKEN && ((gametype != GT_COOP && gametype != GT_COMPETITION) || tokenbits == 30 || tokenlist & (1 << tokenbits++))) + if (i == MT_TOKEN && (!(gametyperules & GTR_EMERALDTOKENS) || tokenbits == 30 || tokenlist & (1 << tokenbits++))) return; // you already got this token, or there are too many, or the gametype's not right if (i == MT_EMBLEM && (netgame || multiplayer || (modifiedgame && !savemoddata))) // No cheating!! From ef7e53488db6cf25cf777a530603943597d85116 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 22:50:49 -0300 Subject: [PATCH 113/195] GTR_CAMPAIGN and GTR_NOGAMEEND --- src/doomstat.h | 12 +++++++----- src/g_game.c | 10 +++++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index b79edb93c..6730254a2 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -416,11 +416,13 @@ enum GameTypeRules GTR_EMERALDHUNT = 1<<19, // Emerald Hunt GTR_SPAWNENEMIES = 1<<20, // Spawn enemies GTR_ALLOWEXIT = 1<<21, // Allow exit sectors - GTR_ROUNDENDMESSAGE = 1<<22, // Prints "The round has ended." into the console - GTR_NOTITLECARD = 1<<23, // Don't show the title card - GTR_POINTLIMIT = 1<<24, // Ringslinger point limit - GTR_TIMELIMIT = 1<<25, // Ringslinger time limit - GTR_OVERTIME = 1<<26, // Allow overtime + GTR_CAMPAIGN = 1<<22, // Linear Co-op map progression. Don't allow random maps. + GTR_NOGAMEEND = 1<<23, // Don't end the game. That is, wrap around the maps instead of starting the ending. + GTR_ROUNDENDMESSAGE = 1<<24, // Prints "The round has ended." into the console + GTR_NOTITLECARD = 1<<25, // Don't show the title card + GTR_POINTLIMIT = 1<<26, // Ringslinger point limit + GTR_TIMELIMIT = 1<<27, // Ringslinger time limit + GTR_OVERTIME = 1<<28, // Allow overtime }; // String names for gametypes diff --git a/src/g_game.c b/src/g_game.c index 74fd82be6..d73df8139 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3088,11 +3088,11 @@ const char *Gametype_ConstantNames[NUMGAMETYPES] = UINT32 gametypedefaultrules[NUMGAMETYPES] = { // Co-op - GTR_PLATFORM|GTR_LIVES|GTR_CHASECAM|GTR_EMERALDHUNT|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_EMERALDTOKENS|GTR_SPECIALSTAGES, + GTR_PLATFORM|GTR_CAMPAIGN|GTR_LIVES|GTR_CHASECAM|GTR_EMERALDHUNT|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_EMERALDTOKENS|GTR_SPECIALSTAGES, // Competition - GTR_PLATFORM|GTR_LIVES|GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_ROUNDENDMESSAGE|GTR_EMERALDTOKENS, + GTR_PLATFORM|GTR_NOGAMEEND|GTR_LIVES|GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_ROUNDENDMESSAGE|GTR_EMERALDTOKENS, // Race - GTR_PLATFORM|GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_ROUNDENDMESSAGE, + GTR_PLATFORM|GTR_NOGAMEEND|GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_ROUNDENDMESSAGE, // Match GTR_RINGSLINGER|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_EMERALDS|GTR_PITYSHIELD|GTR_DEATHPENALTY|GTR_ROUNDENDMESSAGE, @@ -3527,7 +3527,7 @@ static void G_DoCompleted(void) I_Error("Followed map %d to invalid map %d\n", prevmap + 1, nextmap + 1); // wrap around in race - if (nextmap >= 1100-1 && nextmap <= 1102-1 && (gametyperules & GTR_RACE)) + if (nextmap >= 1100-1 && nextmap <= 1102-1 && (gametyperules & GTR_NOGAMEEND)) nextmap = (INT16)(spstage_start-1); if ((gottoken = ((gametyperules & GTR_SPECIALSTAGES) && token))) @@ -3550,7 +3550,7 @@ static void G_DoCompleted(void) automapactive = false; - if (gametype != GT_COOP) + if (!(gametyperules & GTR_CAMPAIGN)) { if (cv_advancemap.value == 0) // Stay on same map. nextmap = prevmap; From b496cc0d62e220d17c40a14da3b5a07569067919 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 23:02:07 -0300 Subject: [PATCH 114/195] Whoops --- src/dehacked.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dehacked.c b/src/dehacked.c index e60bcae5d..871fe72a0 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8924,6 +8924,8 @@ static const char *const GAMETYPERULE_LIST[] = { "EMERALDHUNT", "SPAWNENEMIES", "ALLOWEXIT", + "CAMPAIGN", + "NOGAMEEND", "ROUNDENDMESSAGE", "NOTITLECARD", "POINTLIMIT", From 96cf03b716414bfb28c890d6a1c622896465820a Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Wed, 18 Dec 2019 21:28:34 -0500 Subject: [PATCH 115/195] Don't uncurl from spin if Elemental Stomp is used --- src/p_user.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index ea42a2c36..78c5137bc 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -5128,11 +5128,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) boolean elem = ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL); player->pflags |= PF_THOKKED|PF_SHIELDABILITY; if (elem) - { - player->pflags |= PF_NOJUMPDAMAGE; - P_SetPlayerMobjState(player->mo, S_PLAY_FALL); S_StartSound(player->mo, sfx_s3k43); - } else { player->pflags &= ~PF_NOJUMPDAMAGE; From be5fd1a0dbd91e402f9f20fb31d4dc74b3973bbb Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 23:40:58 -0300 Subject: [PATCH 116/195] TeamSwitch hook for Lua --- src/d_netcmd.c | 6 ++++++ src/lua_hook.h | 2 ++ src/lua_hooklib.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++ src/p_user.c | 11 ++++++++++- 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 158b1f802..807daa9ef 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2734,6 +2734,12 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) return; } +#ifdef HAVE_BLUA + // Don't switch team, just go away, please, go awaayyyy, aaauuauugghhhghgh + if (!LUAh_TeamSwitch(&players[playernum], NetPacket.packet.newteam, players[playernum].spectator, NetPacket.packet.autobalance, NetPacket.packet.scrambled)) + return; +#endif + //no status changes after hidetime if ((gametyperules & GTR_HIDEFROZEN) && (leveltime >= (hidetime * TICRATE))) error = true; diff --git a/src/lua_hook.h b/src/lua_hook.h index 592a93acc..524526df2 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -51,6 +51,7 @@ enum hook { hook_PlayerCanDamage, hook_PlayerQuit, hook_IntermissionThinker, + hook_TeamSwitch, hook_ViewpointSwitch, hook_MAX // last hook @@ -94,6 +95,7 @@ boolean LUAh_FollowMobj(player_t *player, mobj_t *mobj); // Hook for P_PlayerAft UINT8 LUAh_PlayerCanDamage(player_t *player, mobj_t *mobj); // Hook for P_PlayerCanDamage void LUAh_PlayerQuit(player_t *plr, int reason); // Hook for player quitting void LUAh_IntermissionThinker(void); // Hook for Y_Ticker +boolean LUAh_TeamSwitch(player_t *player, int newteam, boolean fromspectators, boolean autobalance, boolean scrambled); // Hook for team switching in... uh.... UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer); // Hook for spy mode in G_Responder #endif diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index b1f702f7c..08ffeec03 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -62,6 +62,7 @@ const char *const hookNames[hook_MAX+1] = { "PlayerCanDamage", "PlayerQuit", "IntermissionThinker", + "TeamSwitch", "ViewpointSwitch", NULL }; @@ -204,6 +205,7 @@ static int lib_addHook(lua_State *L) case hook_PlayerSpawn: case hook_FollowMobj: case hook_PlayerCanDamage: + case hook_TeamSwitch: case hook_ViewpointSwitch: case hook_ShieldSpawn: case hook_ShieldSpecial: @@ -1348,6 +1350,53 @@ void LUAh_IntermissionThinker(void) } } +// Hook for team switching +// It's just an edit of LUAh_ViewpointSwitch. +boolean LUAh_TeamSwitch(player_t *player, int newteam, boolean fromspectators, boolean autobalance, boolean scrambled) +{ + hook_p hookp; + boolean canSwitchTeam = true; + if (!gL || !(hooksAvailable[hook_TeamSwitch/8] & (1<<(hook_TeamSwitch%8)))) + return 0; + + lua_settop(gL, 0); + + for (hookp = playerhooks; hookp; hookp = hookp->next) + { + if (hookp->type != hook_TeamSwitch) + continue; + + if (lua_gettop(gL) == 0) + { + LUA_PushUserdata(gL, player, META_PLAYER); + lua_pushinteger(gL, newteam); + lua_pushboolean(gL, fromspectators); + lua_pushboolean(gL, autobalance); + lua_pushboolean(gL, scrambled); + } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + if (lua_pcall(gL, 5, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1) && !lua_toboolean(gL, -1)) + canSwitchTeam = false; // Can't switch team + lua_pop(gL, 1); + } + + lua_settop(gL, 0); + return canSwitchTeam; +} + // Hook for spy mode in G_Responder UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer) { diff --git a/src/p_user.c b/src/p_user.c index b8164c173..b6f352450 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -10364,6 +10364,11 @@ boolean P_SpectatorJoinGame(player_t *player) else changeto = (P_RandomFixed() & 1) + 1; +#ifdef HAVE_BLUA + if (!LUAh_TeamSwitch(player, changeto, true, false, false)) + return false; +#endif + if (player->mo) { P_RemoveMobj(player->mo); @@ -10389,8 +10394,12 @@ boolean P_SpectatorJoinGame(player_t *player) { // Exception for hide and seek. Don't join a game when you simply // respawn in place and sit there for the rest of the round. - if (!(gametype == GT_HIDEANDSEEK && leveltime > (hidetime * TICRATE))) + if (!((gametyperules & GTR_HIDEFROZEN) && leveltime > (hidetime * TICRATE))) { +#ifdef HAVE_BLUA + if (!LUAh_TeamSwitch(player, 3, true, false, false)) + return false; +#endif if (player->mo) { P_RemoveMobj(player->mo); From 6f857df5e52fc62126b5ff9cd1b90a1a8444d012 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 23:47:17 -0300 Subject: [PATCH 117/195] ViewpointSwitch hack so nobody does anything evil Prints the generic "can't do this in a HUD hook" message. Whatever. I'm tired. --- src/lua_hooklib.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 08ffeec03..9604faf4c 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -1406,6 +1406,7 @@ UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer) return 0; lua_settop(gL, 0); + hud_running = true; for (hookp = playerhooks; hookp; hookp = hookp->next) { @@ -1439,6 +1440,8 @@ UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer) } lua_settop(gL, 0); + hud_running = false; + return canSwitchView; } From 5da55e8b7692ef8bd0ee1147b3578c37469c5950 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Wed, 18 Dec 2019 23:53:26 -0300 Subject: [PATCH 118/195] Shadowed variable declarations whoopsie!!! uwu --- src/lua_hook.h | 2 +- src/lua_hooklib.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lua_hook.h b/src/lua_hook.h index 524526df2..8d780490e 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -95,7 +95,7 @@ boolean LUAh_FollowMobj(player_t *player, mobj_t *mobj); // Hook for P_PlayerAft UINT8 LUAh_PlayerCanDamage(player_t *player, mobj_t *mobj); // Hook for P_PlayerCanDamage void LUAh_PlayerQuit(player_t *plr, int reason); // Hook for player quitting void LUAh_IntermissionThinker(void); // Hook for Y_Ticker -boolean LUAh_TeamSwitch(player_t *player, int newteam, boolean fromspectators, boolean autobalance, boolean scrambled); // Hook for team switching in... uh.... +boolean LUAh_TeamSwitch(player_t *player, int newteam, boolean fromspectators, boolean tryingautobalance, boolean tryingscramble); // Hook for team switching in... uh.... UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer); // Hook for spy mode in G_Responder #endif diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 9604faf4c..0393a3577 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -1352,7 +1352,7 @@ void LUAh_IntermissionThinker(void) // Hook for team switching // It's just an edit of LUAh_ViewpointSwitch. -boolean LUAh_TeamSwitch(player_t *player, int newteam, boolean fromspectators, boolean autobalance, boolean scrambled) +boolean LUAh_TeamSwitch(player_t *player, int newteam, boolean fromspectators, boolean tryingautobalance, boolean tryingscramble) { hook_p hookp; boolean canSwitchTeam = true; @@ -1371,8 +1371,8 @@ boolean LUAh_TeamSwitch(player_t *player, int newteam, boolean fromspectators, b LUA_PushUserdata(gL, player, META_PLAYER); lua_pushinteger(gL, newteam); lua_pushboolean(gL, fromspectators); - lua_pushboolean(gL, autobalance); - lua_pushboolean(gL, scrambled); + lua_pushboolean(gL, tryingautobalance); + lua_pushboolean(gL, tryingscramble); } lua_pushfstring(gL, FMT_HOOKID, hookp->id); lua_gettable(gL, LUA_REGISTRYINDEX); From e4b4b60cb6e38760b6a795795acde922b136c55b Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Thu, 19 Dec 2019 00:15:19 -0300 Subject: [PATCH 119/195] Remove this debugging command, as I don't need it anymore. --- src/d_netcmd.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 807daa9ef..2a4bc75a7 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -125,7 +125,6 @@ static void Command_Version_f(void); static void Command_ModDetails_f(void); #endif static void Command_ShowGametype_f(void); -static void Command_SetGametype_f(void); FUNCNORETURN static ATTRNORETURN void Command_Quit_f(void); static void Command_Playintro_f(void); @@ -488,7 +487,6 @@ void D_RegisterServerCommands(void) COM_AddCommand("suicide", Command_Suicide); COM_AddCommand("gametype", Command_ShowGametype_f); - COM_AddCommand("setgametype", Command_SetGametype_f); COM_AddCommand("version", Command_Version_f); #ifdef UPDATE_ALERT COM_AddCommand("mod_details", Command_ModDetails_f); @@ -3643,16 +3641,6 @@ static void Command_ShowGametype_f(void) CONS_Printf(M_GetText("Unknown gametype set (%d)\n"), gametype); } -static void Command_SetGametype_f(void) -{ - if (COM_Argc() > 1) - { - INT16 oldgametype = gametype; - G_SetGametype(atoi(COM_Argv(1))); - D_GameTypeChanged(oldgametype); - } -} - /** Plays the intro. */ static void Command_Playintro_f(void) From 00440224d2d6a25afe5347565d26b7509d2c66fa Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Thu, 19 Dec 2019 00:31:13 -0300 Subject: [PATCH 120/195] De-fuck team change --- src/lua_hooklib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 0393a3577..d213bd307 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -1357,7 +1357,7 @@ boolean LUAh_TeamSwitch(player_t *player, int newteam, boolean fromspectators, b hook_p hookp; boolean canSwitchTeam = true; if (!gL || !(hooksAvailable[hook_TeamSwitch/8] & (1<<(hook_TeamSwitch%8)))) - return 0; + return true; lua_settop(gL, 0); From d401ba558dea325841bbf9b1112505ae0af7715f Mon Sep 17 00:00:00 2001 From: lachwright Date: Thu, 19 Dec 2019 12:03:36 +0800 Subject: [PATCH 121/195] Fix pflags not being properly reset when entering dust devil from top --- src/p_enemy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index 5361f453b..6b60a697f 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -13614,12 +13614,12 @@ static boolean PIT_DustDevilLaunch(mobj_t *thing) } else { //Player on the top of the tornado. + P_ResetPlayer(player); thing->z = dustdevil->z + dustdevil->height; thrust = 20 * FRACUNIT; player->powers[pw_nocontrol] = 0; S_StartSound(thing, sfx_wdjump); P_SetPlayerMobjState(thing, S_PLAY_FALL); - player->pflags &= ~PF_JUMPED; } thing->momz = thrust; From fb6f2fc9b0a232ad4d994757156e82f22459d135 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Thu, 19 Dec 2019 02:13:09 -0300 Subject: [PATCH 122/195] Lua! Lua! Lua! Expecting the buildbot to complain --- src/dehacked.c | 61 ++++++---------------- src/g_game.c | 56 ++++++++++++++++++++ src/g_game.h | 1 + src/lua_baselib.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 202 insertions(+), 46 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 871fe72a0..5301bef68 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1146,7 +1146,6 @@ static void readgametype(MYFILE *f, char *gtname) char *word; char *word2, *word2lwr = NULL; char *tmp; - char *gtconst; INT32 i, j; INT16 newgtidx = 0; @@ -1326,51 +1325,7 @@ static void readgametype(MYFILE *f, char *gtname) Gametype_Names[newgtidx] = Z_StrDup((const char *)gtname); // Write the constant name. - gtconst = Z_Malloc(strlen((const char *)gtname) + 3, PU_STATIC, NULL); - // Copy GT_ and the gametype name. - strcpy(gtconst, "GT_"); - strcat(gtconst, (const char *)gtname); - // Make uppercase. - strupr(gtconst); - // Remove characters. -#define REMOVECHAR(chr) \ - word = strchr(gtconst, chr); \ - while (word) \ - { \ - *word = '_'; \ - word = strchr(word, chr); \ - } - - // Space - REMOVECHAR(' ') - // Used for operations - REMOVECHAR('+') - REMOVECHAR('-') - REMOVECHAR('*') - REMOVECHAR('/') - REMOVECHAR('%') - REMOVECHAR('^') - // Part of Lua's syntax - REMOVECHAR('#') - REMOVECHAR('=') - REMOVECHAR('~') - REMOVECHAR('<') - REMOVECHAR('>') - REMOVECHAR('(') - REMOVECHAR(')') - REMOVECHAR('{') - REMOVECHAR('}') - REMOVECHAR('[') - REMOVECHAR(']') - REMOVECHAR(':') - REMOVECHAR(';') - REMOVECHAR(',') - REMOVECHAR('.') - -#undef REMOVECHAR - - // Finally, set the constant string. - Gametype_ConstantNames[newgtidx] = gtconst; + G_AddGametypeConstant(newgtidx, (const char *)gtname); // Update gametype_cons_t accordingly. G_UpdateGametypeSelections(); @@ -10439,6 +10394,20 @@ static inline int lib_freeslot(lua_State *L) } r++; } + else if (fastcmp(type, "TOL")) + { + if (lastcustomtol > 31) + CONS_Alert(CONS_WARNING, "Ran out of free typeoflevel slots!\n"); + else + { + UINT32 newtol = (1<') + REMOVECHAR('(') + REMOVECHAR(')') + REMOVECHAR('{') + REMOVECHAR('}') + REMOVECHAR('[') + REMOVECHAR(']') + REMOVECHAR(':') + REMOVECHAR(';') + REMOVECHAR(',') + REMOVECHAR('.') + +#undef REMOVECHAR + + // Finally, set the constant string. + Gametype_ConstantNames[gtype] = gtconst; +} + // // G_UpdateGametypeSelections // diff --git a/src/g_game.h b/src/g_game.h index bd0dc0180..de644756f 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -207,6 +207,7 @@ extern INT16 gametyperankings[NUMGAMETYPES]; void G_SetGametype(INT16 gametype); INT16 G_AddGametype(UINT32 rules); +void G_AddGametypeConstant(INT16 gtype, const char *newgtconst); void G_UpdateGametypeSelections(void); void G_AddTOL(UINT32 newtol, const char *tolname); void G_AddGametypeTOL(INT16 gtype, UINT32 newtol); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index b68d16c2a..450da6576 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -12,6 +12,7 @@ #include "doomdef.h" #ifdef HAVE_BLUA +#include "fastcmp.h" #include "p_local.h" #include "p_setup.h" // So we can have P_SetupLevelSky #ifdef ESLOPE @@ -23,6 +24,7 @@ #include "m_random.h" #include "s_sound.h" #include "g_game.h" +#include "y_inter.h" #include "hu_stuff.h" // HU_AddChatText #include "console.h" #include "d_netcmd.h" // IsPlayerAdmin @@ -2632,6 +2634,133 @@ static int lib_sStartMusicCaption(lua_State *L) // G_GAME //////////// +// Copypasted from lib_cvRegisterVar :] +static int lib_gAddGametype(lua_State *L) +{ + const char *k; + lua_Integer i; + + const char *gtname = NULL; + const char *gtdescription = NULL; + INT16 newgtidx = 0; + UINT32 newgtrules = 0; + UINT32 newgttol = 0; + INT32 newgtpointlimit = 0; + INT32 newgttimelimit = 0; + UINT8 newgtleftcolor = 0; + UINT8 newgtrightcolor = 0; + INT16 newgtrankingstype = -1; + int newgtinttype = 0; + + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 1); // Clear out all other possible arguments, leaving only the first one. + + if (!lua_lumploading) + return luaL_error(L, "This function cannot be called from within a hook or coroutine!"); + +#define FIELDERROR(f, e) luaL_error(L, "bad value for " LUA_QL(f) " in table passed to " LUA_QL("G_AddGametype") " (%s)", e); +#define TYPEERROR(f, t) FIELDERROR(f, va("%s expected, got %s", lua_typename(L, t), luaL_typename(L, -1))) + + lua_pushnil(L); + while (lua_next(L, 1)) { + // stack: gametype table, key/index, value + // 1 2 3 + i = 0; + k = NULL; + if (lua_isnumber(L, 2)) + i = lua_tointeger(L, 2); + else if (lua_isstring(L, 2)) + k = lua_tostring(L, 2); + + // Sorry, no gametype rules as key names. + if (i == 1 || (k && fasticmp(k, "name"))) { + if (!lua_isstring(L, 3)) + TYPEERROR("name", LUA_TSTRING) + gtname = Z_StrDup(lua_tostring(L, 3)); + } else if (i == 2 || (k && fasticmp(k, "rules"))) { + if (!lua_isnumber(L, 3)) + TYPEERROR("rules", LUA_TNUMBER) + newgtrules = (UINT32)lua_tointeger(L, 3); + } else if (i == 3 || (k && fasticmp(k, "typeoflevel"))) { + if (!lua_isnumber(L, 3)) + TYPEERROR("typeoflevel", LUA_TNUMBER) + newgttol = (UINT32)lua_tointeger(L, 3); + } else if (i == 4 || (k && fasticmp(k, "rankingtype"))) { + if (!lua_isnumber(L, 3)) + TYPEERROR("rankingtype", LUA_TNUMBER) + newgtrankingstype = (INT16)lua_tointeger(L, 3); + } else if (i == 5 || (k && fasticmp(k, "intermissiontype"))) { + if (!lua_isnumber(L, 3)) + TYPEERROR("intermissiontype", LUA_TNUMBER) + newgtinttype = (int)lua_tointeger(L, 3); + } else if (i == 6 || (k && fasticmp(k, "defaultpointlimit"))) { + if (!lua_isnumber(L, 3)) + TYPEERROR("defaultpointlimit", LUA_TNUMBER) + newgtpointlimit = (INT32)lua_tointeger(L, 3); + } else if (i == 7 || (k && fasticmp(k, "defaulttimelimit"))) { + if (!lua_isnumber(L, 3)) + TYPEERROR("defaulttimelimit", LUA_TNUMBER) + newgttimelimit = (INT32)lua_tointeger(L, 3); + } else if (i == 8 || (k && fasticmp(k, "description"))) { + if (!lua_isstring(L, 3)) + TYPEERROR("description", LUA_TSTRING) + gtdescription = Z_StrDup(lua_tostring(L, 3)); + } else if (i == 9 || (k && fasticmp(k, "headerleftcolor"))) { + if (!lua_isnumber(L, 3)) + TYPEERROR("headerleftcolor", LUA_TNUMBER) + newgtleftcolor = (UINT8)lua_tointeger(L, 3); + } else if (i == 10 || (k && fasticmp(k, "headerrightcolor"))) { + if (!lua_isnumber(L, 3)) + TYPEERROR("headerrightcolor", LUA_TNUMBER) + newgtrightcolor = (UINT8)lua_tointeger(L, 3); + // Key name specified + } else if ((!i) && (k && fasticmp(k, "headercolor"))) { + if (!lua_isnumber(L, 3)) + TYPEERROR("headercolor", LUA_TNUMBER) + newgtleftcolor = newgtrightcolor = (UINT8)lua_tointeger(L, 3); + } + lua_pop(L, 1); + } + +#undef FIELDERROR +#undef TYPEERROR + + // pop gametype table + lua_pop(L, 1); + + // Set defaults + if (gtname == NULL) + gtname = Z_StrDup("Unnamed gametype"); + if (gtdescription == NULL) + gtdescription = Z_StrDup("???"); + + // Add the new gametype + newgtidx = G_AddGametype(newgtrules); + G_AddGametypeTOL(newgtidx, newgttol); + G_SetGametypeDescription(newgtidx, (char *)gtdescription, newgtleftcolor, newgtrightcolor); + + // Not covered by G_AddGametype alone. + if (newgtrankingstype == -1) + newgtrankingstype = newgtidx; + gametyperankings[newgtidx] = newgtrankingstype; + intermissiontypes[newgtidx] = newgtinttype; + pointlimits[newgtidx] = newgtpointlimit; + timelimits[newgtidx] = newgttimelimit; + + // Write the new gametype name. + Gametype_Names[newgtidx] = gtname; + + // Write the constant name. + G_AddGametypeConstant(newgtidx, gtname); + + // Update gametype_cons_t accordingly. + G_UpdateGametypeSelections(); + + // done + CONS_Printf("Added gametype %s\n", Gametype_Names[newgtidx]); + return 0; +} + static int lib_gBuildMapName(lua_State *L) { INT32 map = luaL_optinteger(L, 1, gamemap); @@ -2997,6 +3126,7 @@ static luaL_Reg lib[] = { {"S_StartMusicCaption", lib_sStartMusicCaption}, // g_game + {"G_AddGametype", lib_gAddGametype}, {"G_BuildMapName",lib_gBuildMapName}, {"G_DoReborn",lib_gDoReborn}, {"G_SetCustomExitVars",lib_gSetCustomExitVars}, From 019e52a4f431ad93075a719bab64a4d0d80fa22d Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Thu, 19 Dec 2019 02:17:03 -0300 Subject: [PATCH 123/195] allow CTF spawns in GTR_TEAMS gametype rule --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 7c00f0131..96a7ed423 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2574,7 +2574,7 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost) // -- CTF -- // Order: CTF->DM->Coop - if ((gametyperules & GTR_TEAMFLAGS) && players[playernum].ctfteam) + if ((gametyperules & (GTR_TEAMFLAGS|GTR_TEAMS)) && players[playernum].ctfteam) { if (!(spawnpoint = G_FindCTFStart(playernum)) // find a CTF start && !(spawnpoint = G_FindMatchStart(playernum))) // find a DM start From ebdd9c62572076bcd4dd151ebba1f5bf47d40a1a Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Thu, 19 Dec 2019 02:20:49 -0300 Subject: [PATCH 124/195] fix warnings --- src/g_game.c | 3 ++- src/lua_baselib.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 96a7ed423..0c085c84e 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3220,7 +3220,8 @@ void G_UpdateGametypeSelections(void) // void G_SetGametypeDescription(INT16 gtype, char *descriptiontext, UINT8 leftcolor, UINT8 rightcolor) { - strncpy(gametypedesc[gtype].notes, descriptiontext, 441); + if (descriptiontext != NULL) + strncpy(gametypedesc[gtype].notes, descriptiontext, 441); gametypedesc[gtype].col[0] = leftcolor; gametypedesc[gtype].col[1] = rightcolor; } diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 7ff967b40..5f9d3dbf6 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -24,6 +24,7 @@ #include "m_random.h" #include "s_sound.h" #include "g_game.h" +#include "m_menu.h" #include "y_inter.h" #include "hu_stuff.h" // HU_AddChatText #include "console.h" @@ -2737,7 +2738,8 @@ static int lib_gAddGametype(lua_State *L) // Add the new gametype newgtidx = G_AddGametype(newgtrules); G_AddGametypeTOL(newgtidx, newgttol); - G_SetGametypeDescription(newgtidx, (char *)gtdescription, newgtleftcolor, newgtrightcolor); + G_SetGametypeDescription(newgtidx, NULL, newgtleftcolor, newgtrightcolor); + strncpy(gametypedesc[newgtidx].notes, gtdescription, 441); // Not covered by G_AddGametype alone. if (newgtrankingstype == -1) From ce0e4201b810c1cdd2d3a19f99bfe485f6d2ac3b Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Thu, 19 Dec 2019 02:26:17 -0300 Subject: [PATCH 125/195] GTR_DEATHMATCHSTARTS --- src/dehacked.c | 1 + src/doomstat.h | 25 +++++++++++++------------ src/g_game.c | 2 +- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 9b4656627..dedeeb87f 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8874,6 +8874,7 @@ static const char *const GAMETYPERULE_LIST[] = { "PITYSHIELD", "DEATHPENALTY", "NOSPECTATORSPAWN", + "DEATHMATCHSTARTS", "SPECIALSTAGES", "EMERALDTOKENS", "EMERALDHUNT", diff --git a/src/doomstat.h b/src/doomstat.h index 6730254a2..d24de58f1 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -411,18 +411,19 @@ enum GameTypeRules GTR_PITYSHIELD = 1<<14, // Award pity shield GTR_DEATHPENALTY = 1<<15, // Death score penalty GTR_NOSPECTATORSPAWN = 1<<16, // For use with GTR_SPECTATORS - spawn in the map instead of with the spectators - GTR_SPECIALSTAGES = 1<<17, // Allow special stages - GTR_EMERALDTOKENS = 1<<18, // Spawn emerald tokens - GTR_EMERALDHUNT = 1<<19, // Emerald Hunt - GTR_SPAWNENEMIES = 1<<20, // Spawn enemies - GTR_ALLOWEXIT = 1<<21, // Allow exit sectors - GTR_CAMPAIGN = 1<<22, // Linear Co-op map progression. Don't allow random maps. - GTR_NOGAMEEND = 1<<23, // Don't end the game. That is, wrap around the maps instead of starting the ending. - GTR_ROUNDENDMESSAGE = 1<<24, // Prints "The round has ended." into the console - GTR_NOTITLECARD = 1<<25, // Don't show the title card - GTR_POINTLIMIT = 1<<26, // Ringslinger point limit - GTR_TIMELIMIT = 1<<27, // Ringslinger time limit - GTR_OVERTIME = 1<<28, // Allow overtime + GTR_DEATHMATCHSTARTS = 1<<17, // Use deathmatch starts + GTR_SPECIALSTAGES = 1<<18, // Allow special stages + GTR_EMERALDTOKENS = 1<<19, // Spawn emerald tokens + GTR_EMERALDHUNT = 1<<20, // Emerald Hunt + GTR_SPAWNENEMIES = 1<<21, // Spawn enemies + GTR_ALLOWEXIT = 1<<22, // Allow exit sectors + GTR_CAMPAIGN = 1<<23, // Linear Co-op map progression. Don't allow random maps. + GTR_NOGAMEEND = 1<<24, // Don't end the game. That is, wrap around the maps instead of starting the ending. + GTR_ROUNDENDMESSAGE = 1<<25, // Prints "The round has ended." into the console + GTR_NOTITLECARD = 1<<26, // Don't show the title card + GTR_POINTLIMIT = 1<<27, // Ringslinger point limit + GTR_TIMELIMIT = 1<<28, // Ringslinger time limit + GTR_OVERTIME = 1<<29, // Allow overtime }; // String names for gametypes diff --git a/src/g_game.c b/src/g_game.c index 0c085c84e..9c51e4741 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2583,7 +2583,7 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost) // -- DM/Tag/CTF-spectator/etc -- // Order: DM->CTF->Coop - else if (gametype == GT_MATCH || gametype == GT_TEAMMATCH || gametype == GT_CTF + else if ((gametyperules & GTR_DEATHMATCHSTARTS) || gametype == GT_MATCH || gametype == GT_TEAMMATCH || gametype == GT_CTF || ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && !(players[playernum].pflags & PF_TAGIT))) { if (!(spawnpoint = G_FindMatchStart(playernum)) // find a DM start From 768080977fea335d7d4da77fc434ba495464ca04 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Thu, 19 Dec 2019 15:47:37 -0300 Subject: [PATCH 126/195] Remove GTR_ROUNDENDMESSAGE --- src/dehacked.c | 1 - src/doomstat.h | 9 ++++----- src/g_game.c | 16 ++++++++-------- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index dedeeb87f..84abc9139 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8882,7 +8882,6 @@ static const char *const GAMETYPERULE_LIST[] = { "ALLOWEXIT", "CAMPAIGN", "NOGAMEEND", - "ROUNDENDMESSAGE", "NOTITLECARD", "POINTLIMIT", "TIMELIMIT", diff --git a/src/doomstat.h b/src/doomstat.h index d24de58f1..58d9d4896 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -419,11 +419,10 @@ enum GameTypeRules GTR_ALLOWEXIT = 1<<22, // Allow exit sectors GTR_CAMPAIGN = 1<<23, // Linear Co-op map progression. Don't allow random maps. GTR_NOGAMEEND = 1<<24, // Don't end the game. That is, wrap around the maps instead of starting the ending. - GTR_ROUNDENDMESSAGE = 1<<25, // Prints "The round has ended." into the console - GTR_NOTITLECARD = 1<<26, // Don't show the title card - GTR_POINTLIMIT = 1<<27, // Ringslinger point limit - GTR_TIMELIMIT = 1<<28, // Ringslinger time limit - GTR_OVERTIME = 1<<29, // Allow overtime + GTR_NOTITLECARD = 1<<25, // Don't show the title card + GTR_POINTLIMIT = 1<<26, // Ringslinger point limit + GTR_TIMELIMIT = 1<<27, // Ringslinger time limit + GTR_OVERTIME = 1<<28, // Allow overtime }; // String names for gametypes diff --git a/src/g_game.c b/src/g_game.c index 9c51e4741..80fa42dea 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3036,7 +3036,7 @@ void G_ExitLevel(void) CV_SetValue(&cv_teamscramble, cv_scrambleonchange.value); } - if (gametyperules & GTR_ROUNDENDMESSAGE) + if (!(gametyperules & GTR_CAMPAIGN)) CONS_Printf(M_GetText("The round has ended.\n")); // Remove CEcho text on round end. @@ -3090,22 +3090,22 @@ UINT32 gametypedefaultrules[NUMGAMETYPES] = // Co-op GTR_PLATFORM|GTR_CAMPAIGN|GTR_LIVES|GTR_CHASECAM|GTR_EMERALDHUNT|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_EMERALDTOKENS|GTR_SPECIALSTAGES, // Competition - GTR_PLATFORM|GTR_NOGAMEEND|GTR_LIVES|GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_ROUNDENDMESSAGE|GTR_EMERALDTOKENS, + GTR_PLATFORM|GTR_NOGAMEEND|GTR_LIVES|GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_EMERALDTOKENS, // Race - GTR_PLATFORM|GTR_NOGAMEEND|GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_ROUNDENDMESSAGE, + GTR_PLATFORM|GTR_NOGAMEEND|GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT, // Match - GTR_RINGSLINGER|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_EMERALDS|GTR_PITYSHIELD|GTR_DEATHPENALTY|GTR_ROUNDENDMESSAGE, + GTR_RINGSLINGER|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_EMERALDS|GTR_PITYSHIELD|GTR_DEATHPENALTY, // Team Match - GTR_RINGSLINGER|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_PITYSHIELD|GTR_ROUNDENDMESSAGE, + GTR_RINGSLINGER|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_PITYSHIELD, // Tag - GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED|GTR_ROUNDENDMESSAGE, + GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED, // Hide and Seek - GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED|GTR_ROUNDENDMESSAGE, + GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED, // CTF - GTR_RINGSLINGER|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_EMERALDS|GTR_TEAMFLAGS|GTR_PITYSHIELD|GTR_ROUNDENDMESSAGE, + GTR_RINGSLINGER|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_EMERALDS|GTR_TEAMFLAGS|GTR_PITYSHIELD, }; // From 6d7262e9855409b128dbeed1495ba0a2cca39be6 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Thu, 19 Dec 2019 16:05:03 -0300 Subject: [PATCH 127/195] Remove GTR_PLATFORM --- src/dehacked.c | 2 +- src/doomstat.h | 2 +- src/g_game.c | 9 ++++----- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 84abc9139..e078d2f69 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8857,7 +8857,7 @@ static const char *const PLAYERFLAG_LIST[] = { }; static const char *const GAMETYPERULE_LIST[] = { - "PLATFORM", + "\x01", "TAG", "RINGSLINGER", "SPECTATORS", diff --git a/src/doomstat.h b/src/doomstat.h index 58d9d4896..0abc6a467 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -389,7 +389,7 @@ enum GameType // Game type rules enum GameTypeRules { - GTR_PLATFORM = 1, // Co-op, Competition, and Race + GTR_SORRYNOTHING = 1, GTR_TAG = 1<<1, // Tag and Hide and Seek GTR_RINGSLINGER = 1<<2, // Not Co-op, not Competition, and not Race (overriden by cv_ringslinger) GTR_SPECTATORS = 1<<3, // Not Co-op, not Competition, and not Race diff --git a/src/g_game.c b/src/g_game.c index 80fa42dea..2e25b5c2f 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3088,11 +3088,11 @@ const char *Gametype_ConstantNames[NUMGAMETYPES] = UINT32 gametypedefaultrules[NUMGAMETYPES] = { // Co-op - GTR_PLATFORM|GTR_CAMPAIGN|GTR_LIVES|GTR_CHASECAM|GTR_EMERALDHUNT|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_EMERALDTOKENS|GTR_SPECIALSTAGES, + GTR_CAMPAIGN|GTR_LIVES|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_EMERALDHUNT|GTR_EMERALDTOKENS|GTR_SPECIALSTAGES, // Competition - GTR_PLATFORM|GTR_NOGAMEEND|GTR_LIVES|GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_EMERALDTOKENS, + GTR_RACE|GTR_LIVES|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_EMERALDTOKENS|GTR_ALLOWEXIT|GTR_NOGAMEEND, // Race - GTR_PLATFORM|GTR_NOGAMEEND|GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT, + GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_NOGAMEEND, // Match GTR_RINGSLINGER|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_EMERALDS|GTR_PITYSHIELD|GTR_DEATHPENALTY, @@ -3378,8 +3378,7 @@ boolean G_RingSlingerGametype(void) // boolean G_PlatformGametype(void) { - return (gametyperules & GTR_PLATFORM); - //return (gametype == GT_COOP || gametype == GT_RACE || gametype == GT_COMPETITION); + return (!G_RingSlingerGametype()); } // From f4bb618f9387f1045a7ae03433b2858adead2a84 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Thu, 19 Dec 2019 16:12:10 -0300 Subject: [PATCH 128/195] Organise rules --- src/dehacked.c | 19 ++++++++-------- src/doomstat.h | 60 +++++++++++++++++++++++--------------------------- src/g_game.c | 4 ++-- src/p_mobj.c | 2 +- 4 files changed, 39 insertions(+), 46 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index e078d2f69..a4467c699 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8857,19 +8857,21 @@ static const char *const PLAYERFLAG_LIST[] = { }; static const char *const GAMETYPERULE_LIST[] = { - "\x01", - "TAG", + "CAMPAIGN", "RINGSLINGER", "SPECTATORS", - "TEAMS", - "LIVES", - "RACE", - "CHASECAM", "FRIENDLYFIRE", + "LIVES", + "TEAMS", + "RACE", + "TAG", + "POINTLIMIT", + "TIMELIMIT", "HIDETIME", "HIDEFROZEN", "BLINDFOLDED", - "EMERALDS", + "CHASECAM", + "MATCHEMERALDS", "TEAMFLAGS", "PITYSHIELD", "DEATHPENALTY", @@ -8880,11 +8882,8 @@ static const char *const GAMETYPERULE_LIST[] = { "EMERALDHUNT", "SPAWNENEMIES", "ALLOWEXIT", - "CAMPAIGN", "NOGAMEEND", "NOTITLECARD", - "POINTLIMIT", - "TIMELIMIT", "OVERTIME", NULL }; diff --git a/src/doomstat.h b/src/doomstat.h index 0abc6a467..c8d3b492a 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -389,40 +389,34 @@ enum GameType // Game type rules enum GameTypeRules { - GTR_SORRYNOTHING = 1, - GTR_TAG = 1<<1, // Tag and Hide and Seek - GTR_RINGSLINGER = 1<<2, // Not Co-op, not Competition, and not Race (overriden by cv_ringslinger) - GTR_SPECTATORS = 1<<3, // Not Co-op, not Competition, and not Race - GTR_TEAMS = 1<<4, // Team Match, CTF - GTR_LIVES = 1<<5, // A lot of special cases in G_GametypeUsesLives actually, but just Co-op and Competition + GTR_CAMPAIGN = 1, // Linear Co-op map progression. Don't allow random maps. + GTR_RINGSLINGER = 1<<1, // Outside of Co-op, Competition, and Race (overriden by cv_ringslinger) + GTR_SPECTATORS = 1<<2, // Outside of Co-op, Competition, and Race + GTR_FRIENDLYFIRE = 1<<3, // Always allow friendly fire + GTR_LIVES = 1<<4, // Co-op and Competition + GTR_TEAMS = 1<<5, // Team Match, CTF GTR_RACE = 1<<6, // Race and Competition - - // Lactozilla - // Awesome! Those are new game type rules provided by yours truly to allow for more - // flexibility! Those will replace some straight-up gametype checks scattered around the source code! - - GTR_CHASECAM = 1<<7, // Prefer chasecam at map load (All platform gametypes) - GTR_FRIENDLYFIRE = 1<<8, // Always allow friendly fire - GTR_HIDETIME = 1<<9, // Hide time (Tag and Hide and Seek) - GTR_HIDEFROZEN = 1<<10, // Frozen after hide time (Hide and Seek, but not Tag) - GTR_BLINDFOLDED = 1<<11, // Blindfolded view (Tag and Hide and Seek) - GTR_EMERALDS = 1<<12, // Ringslinger emeralds (Match and CTF) - GTR_TEAMFLAGS = 1<<13, // Gametype has team flags (CTF) - GTR_PITYSHIELD = 1<<14, // Award pity shield - GTR_DEATHPENALTY = 1<<15, // Death score penalty - GTR_NOSPECTATORSPAWN = 1<<16, // For use with GTR_SPECTATORS - spawn in the map instead of with the spectators - GTR_DEATHMATCHSTARTS = 1<<17, // Use deathmatch starts - GTR_SPECIALSTAGES = 1<<18, // Allow special stages - GTR_EMERALDTOKENS = 1<<19, // Spawn emerald tokens - GTR_EMERALDHUNT = 1<<20, // Emerald Hunt - GTR_SPAWNENEMIES = 1<<21, // Spawn enemies - GTR_ALLOWEXIT = 1<<22, // Allow exit sectors - GTR_CAMPAIGN = 1<<23, // Linear Co-op map progression. Don't allow random maps. - GTR_NOGAMEEND = 1<<24, // Don't end the game. That is, wrap around the maps instead of starting the ending. - GTR_NOTITLECARD = 1<<25, // Don't show the title card - GTR_POINTLIMIT = 1<<26, // Ringslinger point limit - GTR_TIMELIMIT = 1<<27, // Ringslinger time limit - GTR_OVERTIME = 1<<28, // Allow overtime + GTR_TAG = 1<<7, // Tag and Hide and Seek + GTR_POINTLIMIT = 1<<8, // Ringslinger point limit + GTR_TIMELIMIT = 1<<9, // Ringslinger time limit + GTR_HIDETIME = 1<<10, // Hide time (Tag and Hide and Seek) + GTR_HIDEFROZEN = 1<<11, // Frozen after hide time (Hide and Seek, but not Tag) + GTR_BLINDFOLDED = 1<<12, // Blindfolded view (Tag and Hide and Seek) + GTR_CHASECAM = 1<<13, // Prefer chasecam at map load (All platform gametypes) + GTR_MATCHEMERALDS = 1<<14, // Ringslinger emeralds (Match and CTF) + GTR_TEAMFLAGS = 1<<15, // Gametype has team flags (CTF) + GTR_PITYSHIELD = 1<<16, // Award pity shield + GTR_DEATHPENALTY = 1<<17, // Death score penalty + GTR_NOSPECTATORSPAWN = 1<<18, // For use with GTR_SPECTATORS - spawn in the map instead of with the spectators + GTR_DEATHMATCHSTARTS = 1<<19, // Use deathmatch starts + GTR_SPECIALSTAGES = 1<<20, // Allow special stages + GTR_EMERALDTOKENS = 1<<21, // Spawn emerald tokens + GTR_EMERALDHUNT = 1<<22, // Emerald Hunt + GTR_SPAWNENEMIES = 1<<23, // Spawn enemies + GTR_ALLOWEXIT = 1<<24, // Allow exit sectors + GTR_NOGAMEEND = 1<<25, // Don't end the game. That is, wrap around the maps instead of starting the ending. + GTR_NOTITLECARD = 1<<26, // Don't show the title card + GTR_OVERTIME = 1<<27, // Allow overtime }; // String names for gametypes diff --git a/src/g_game.c b/src/g_game.c index 2e25b5c2f..47e1dc9f0 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3095,7 +3095,7 @@ UINT32 gametypedefaultrules[NUMGAMETYPES] = GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_NOGAMEEND, // Match - GTR_RINGSLINGER|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_EMERALDS|GTR_PITYSHIELD|GTR_DEATHPENALTY, + GTR_RINGSLINGER|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_MATCHEMERALDS|GTR_PITYSHIELD|GTR_DEATHPENALTY, // Team Match GTR_RINGSLINGER|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_PITYSHIELD, @@ -3105,7 +3105,7 @@ UINT32 gametypedefaultrules[NUMGAMETYPES] = GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED, // CTF - GTR_RINGSLINGER|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_EMERALDS|GTR_TEAMFLAGS|GTR_PITYSHIELD, + GTR_RINGSLINGER|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_MATCHEMERALDS|GTR_TEAMFLAGS|GTR_PITYSHIELD, }; // diff --git a/src/p_mobj.c b/src/p_mobj.c index 69d352c5b..dcf3a9127 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11774,7 +11774,7 @@ You should think about modifying the deathmatch starts to take full advantage of if (!cv_powerstones.value) return; - if (!(gametyperules & GTR_EMERALDS)) + if (!(gametyperules & GTR_MATCHEMERALDS)) return; runemeraldmanager = true; From 7efd9662d1c2289451cb54dedefe605a840c9eef Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Thu, 19 Dec 2019 16:13:27 -0300 Subject: [PATCH 129/195] Remove GTR_NOGAMEEND --- src/dehacked.c | 1 - src/doomstat.h | 5 ++--- src/g_game.c | 6 +++--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index a4467c699..6bad6a6dd 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8882,7 +8882,6 @@ static const char *const GAMETYPERULE_LIST[] = { "EMERALDHUNT", "SPAWNENEMIES", "ALLOWEXIT", - "NOGAMEEND", "NOTITLECARD", "OVERTIME", NULL diff --git a/src/doomstat.h b/src/doomstat.h index c8d3b492a..0ab8c1bff 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -414,9 +414,8 @@ enum GameTypeRules GTR_EMERALDHUNT = 1<<22, // Emerald Hunt GTR_SPAWNENEMIES = 1<<23, // Spawn enemies GTR_ALLOWEXIT = 1<<24, // Allow exit sectors - GTR_NOGAMEEND = 1<<25, // Don't end the game. That is, wrap around the maps instead of starting the ending. - GTR_NOTITLECARD = 1<<26, // Don't show the title card - GTR_OVERTIME = 1<<27, // Allow overtime + GTR_NOTITLECARD = 1<<25, // Don't show the title card + GTR_OVERTIME = 1<<26, // Allow overtime }; // String names for gametypes diff --git a/src/g_game.c b/src/g_game.c index 47e1dc9f0..2367f23f4 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3090,9 +3090,9 @@ UINT32 gametypedefaultrules[NUMGAMETYPES] = // Co-op GTR_CAMPAIGN|GTR_LIVES|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_EMERALDHUNT|GTR_EMERALDTOKENS|GTR_SPECIALSTAGES, // Competition - GTR_RACE|GTR_LIVES|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_EMERALDTOKENS|GTR_ALLOWEXIT|GTR_NOGAMEEND, + GTR_RACE|GTR_LIVES|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_EMERALDTOKENS|GTR_ALLOWEXIT, // Race - GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_NOGAMEEND, + GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT, // Match GTR_RINGSLINGER|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_MATCHEMERALDS|GTR_PITYSHIELD|GTR_DEATHPENALTY, @@ -3583,7 +3583,7 @@ static void G_DoCompleted(void) I_Error("Followed map %d to invalid map %d\n", prevmap + 1, nextmap + 1); // wrap around in race - if (nextmap >= 1100-1 && nextmap <= 1102-1 && (gametyperules & GTR_NOGAMEEND)) + if (nextmap >= 1100-1 && nextmap <= 1102-1 && !(gametyperules & GTR_CAMPAIGN)) nextmap = (INT16)(spstage_start-1); if ((gottoken = ((gametyperules & GTR_SPECIALSTAGES) && token))) From a39b6a12861242ce7aaca6a6217eae5dc7e734bb Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Thu, 19 Dec 2019 01:14:34 -0500 Subject: [PATCH 130/195] Allow access to bluescore and redscore --- src/dehacked.c | 8 ++++++++ src/lua_script.c | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/dehacked.c b/src/dehacked.c index 6bad6a6dd..8633a31c3 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -10822,6 +10822,12 @@ static inline int lib_getenum(lua_State *L) } else if (fastcmp(word,"paused")) { lua_pushboolean(L, paused); return 1; + } else if (fastcmp(word,"bluescore")) { + lua_pushinteger(L, bluescore); + return 1; + } else if (fastcmp(word,"redscore")) { + lua_pushinteger(L, redscore); + return 1; // begin map vars } else if (fastcmp(word,"spstage_start")) { lua_pushinteger(L, spstage_start); @@ -11035,6 +11041,8 @@ static int lib_getActionName(lua_State *L) return luaL_typerror(L, 1, "action userdata or Lua function"); } + + int LUA_SOCLib(lua_State *L) { lua_register(L,"freeslot",lib_freeslot); diff --git a/src/lua_script.c b/src/lua_script.c index fe3c2f10d..13592815b 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -106,6 +106,17 @@ static int noglobals(lua_State *L) return 0; } + if (fastcmp(csname,"redscore")) + { + redscore = (UINT32)luaL_checkinteger(L, 2); + return 0; + } + else if (fastcmp(csname,"bluescore")) + { + bluescore = (UINT32)luaL_checkinteger(L, 2); + return 0; + } + Z_Free(name); return luaL_error(L, "Implicit global " LUA_QS " prevented. Create a local variable instead.", csname); } From 9b2b526eb49f12e62ed10ea3c9cea7e47f0d04a4 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Thu, 19 Dec 2019 16:22:55 -0300 Subject: [PATCH 131/195] Removing commented out code --- src/dehacked.c | 2 +- src/g_game.c | 23 +++-------------------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 8633a31c3..12014b8b6 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1284,7 +1284,7 @@ static void readgametype(MYFILE *f, char *gtname) UINT32 wordgt = 0; for (j = 0; GAMETYPERULE_LIST[j]; j++) if (fastcmp(word, GAMETYPERULE_LIST[j])) { - if (!j) // GTR_PLATFORM + if (!j) // GTR_CAMPAIGN wordgt |= 1; else wordgt |= (1< Date: Thu, 19 Dec 2019 16:31:38 -0300 Subject: [PATCH 132/195] Make G_PlatformGametype only check the gametype rules, to avoid unintended side effects --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 582d61989..3cc11c4d1 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3374,7 +3374,7 @@ boolean G_RingSlingerGametype(void) // boolean G_PlatformGametype(void) { - return (!G_RingSlingerGametype()); + return (!(gametyperules & GTR_RINGSLINGER)); } // From 4ad1727b66770cf9a8467b9c13a4373d31f3ee40 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Thu, 19 Dec 2019 17:06:07 -0300 Subject: [PATCH 133/195] Don't spawn End Level Signs without the GTR_ALLOWEXIT rule --- src/p_mobj.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index dcf3a9127..6ee615cdd 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11838,8 +11838,10 @@ You should think about modifying the deathmatch starts to take full advantage of } } - if (!G_PlatformGametype() && (i == MT_SIGN || i == MT_STARPOST)) - return; // Don't spawn exit signs or starposts in wrong game modes + if (!(gametyperules & GTR_ALLOWEXIT) && i == MT_SIGN) + return; // Don't spawn exit signs without the necessary gametype rule + if (!G_PlatformGametype() && i == MT_STARPOST) + return; // Don't spawn starposts in wrong game modes if (modeattacking) // Record Attack special stuff { From 6d7bdf8fdbf827d753011bc12ab92b4ff1c86ba8 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Thu, 19 Dec 2019 18:27:11 -0300 Subject: [PATCH 134/195] Lua gametyperules --- src/dehacked.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/dehacked.c b/src/dehacked.c index 12014b8b6..e3fac0a4b 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -10909,6 +10909,9 @@ static inline int lib_getenum(lua_State *L) } else if (fastcmp(word,"gametype")) { lua_pushinteger(L, gametype); return 1; + } else if (fastcmp(word,"gametyperules")) { + lua_pushinteger(L, gametyperules); + return 1; } else if (fastcmp(word,"leveltime")) { lua_pushinteger(L, leveltime); return 1; From ace202daf08fdce5a1e7d2475403d2f1cf0c32e4 Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Fri, 20 Dec 2019 23:22:45 -0500 Subject: [PATCH 135/195] Fix Amy and Fang being able to attack other players in MP Special Stages --- src/p_inter.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/p_inter.c b/src/p_inter.c index 70fb01fd0..4da942f72 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -3426,6 +3426,17 @@ void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source) if (player->powers[pw_invulnerability] || player->powers[pw_flashing] || player->powers[pw_super]) return; + // Don't allow players to hurt one another, + // unless cv_friendlyfire is on. + if (!cv_friendlyfire.value) + { + if (inflictor->type == MT_LHRT) + return; + + if (source->player->ctfteam == player->ctfteam) + return; + } + if (player->powers[pw_shield] || player->bot) //If One-Hit Shield { P_RemoveShield(player); From de1d25cf08f649cd7c3726aa47b31c252f323ed9 Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Fri, 20 Dec 2019 23:45:32 -0500 Subject: [PATCH 136/195] Fix super theme ending early if invincibility expired --- src/p_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_user.c b/src/p_user.c index 7a86d9419..2b82ae697 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1600,7 +1600,7 @@ void P_RestoreMusic(player_t *player) P_PlayJingle(player, JT_SUPER); // Invulnerability - else if (player->powers[pw_invulnerability] > 1) + else if (player->powers[pw_invulnerability] > 1 && !player->powers[pw_super]) { strlcpy(S_sfx[sfx_None].caption, "Invincibility", 14); S_StartCaption(sfx_None, -1, player->powers[pw_invulnerability]); From dacd5614f9589fae25ebfffe463eef7e4fa7fafb Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Sun, 22 Dec 2019 17:37:54 +0100 Subject: [PATCH 137/195] Make both NiGHTS hoop types use the same spawning code. As a result, the old generic hoops now use 24 sprites instead of 32. --- src/p_mobj.c | 368 ++++++++++++++++----------------------------------- 1 file changed, 114 insertions(+), 254 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index dea4a7a4d..98b640da5 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -13082,6 +13082,115 @@ ML_EFFECT5 : Don't stop thinking when too far away mthing->mobj = mobj; } +static void P_SpawnHoop(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z, sector_t* sec, INT32 hoopsize, fixed_t sizefactor) +{ + mobj_t *mobj = NULL; + mobj_t *nextmobj = NULL; + mobj_t *hoopcenter; + TMatrix *pitchmatrix, *yawmatrix; + fixed_t radius = hoopsize*sizefactor; + INT32 i; + angle_t fa; + TVector v, *res; + + z += +#ifdef ESLOPE + sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : +#endif + sec->floorheight; + + hoopcenter = P_SpawnMobj(x, y, z, MT_HOOPCENTER); + hoopcenter->spawnpoint = mthing; + hoopcenter->z -= hoopcenter->height/2; + + P_UnsetThingPosition(hoopcenter); + hoopcenter->x = x; + hoopcenter->y = y; + P_SetThingPosition(hoopcenter); + + // Scale 0-255 to 0-359 =( + hoopcenter->movedir = ((mthing->angle & 255)*360)/256; // Pitch + pitchmatrix = RotateXMatrix(FixedAngle(hoopcenter->movedir << FRACBITS)); + hoopcenter->movecount = (((UINT16)mthing->angle >> 8)*360)/256; // Yaw + yawmatrix = RotateZMatrix(FixedAngle(hoopcenter->movecount << FRACBITS)); + + // For the hoop when it flies away + hoopcenter->extravalue1 = hoopsize; + hoopcenter->extravalue2 = radius/12; + + // Create the hoop! + for (i = 0; i < hoopsize; i++) + { + fa = i*(FINEANGLES/hoopsize); + v[0] = FixedMul(FINECOSINE(fa), radius); + v[1] = 0; + v[2] = FixedMul(FINESINE(fa), radius); + v[3] = FRACUNIT; + + res = VectorMatrixMultiply(v, *pitchmatrix); + M_Memcpy(&v, res, sizeof(v)); + res = VectorMatrixMultiply(v, *yawmatrix); + M_Memcpy(&v, res, sizeof(v)); + + mobj = P_SpawnMobj(x + v[0], y + v[1], z + v[2], MT_HOOP); + mobj->z -= mobj->height/2; + + if (maptol & TOL_XMAS) + P_SetMobjState(mobj, mobj->info->seestate + (i & 1)); + + P_SetTarget(&mobj->target, hoopcenter); // Link the sprite to the center. + mobj->fuse = 0; + + // Link all the sprites in the hoop together + if (nextmobj) + { + P_SetTarget(&mobj->hprev, nextmobj); + P_SetTarget(&mobj->hprev->hnext, mobj); + } + else + P_SetTarget(&mobj->hprev, P_SetTarget(&mobj->hnext, NULL)); + + nextmobj = mobj; + } + + // Create the collision detectors! + // Create them until the size is less than 8 + // But always create at least ONE set of collision detectors + do + { + if (hoopsize >= 32) + hoopsize -= 16; + else + hoopsize /= 2; + + radius = hoopsize*sizefactor; + + for (i = 0; i < hoopsize; i++) + { + fa = i*(FINEANGLES/hoopsize); + v[0] = FixedMul(FINECOSINE(fa), radius); + v[1] = 0; + v[2] = FixedMul(FINESINE(fa), radius); + v[3] = FRACUNIT; + + res = VectorMatrixMultiply(v, *pitchmatrix); + M_Memcpy(&v, res, sizeof(v)); + res = VectorMatrixMultiply(v, *yawmatrix); + M_Memcpy(&v, res, sizeof(v)); + + mobj = P_SpawnMobj(x + v[0], y + v[1], z + v[2], MT_HOOPCOLLIDE); + mobj->z -= mobj->height/2; + + // Link all the collision sprites together. + P_SetTarget(&mobj->hnext, NULL); + P_SetTarget(&mobj->hprev, nextmobj); + P_SetTarget(&mobj->hprev->hnext, mobj); + + nextmobj = mobj; + } + } while (hoopsize >= 8); +} + void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) { mobjtype_t ringthing = MT_RING; @@ -13101,267 +13210,18 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) // NiGHTS hoop! if (mthing->type == 1705) { - mobj_t *nextmobj = NULL; - mobj_t *hoopcenter; - INT16 spewangle; - z = mthing->options << FRACBITS; - - hoopcenter = P_SpawnMobj(x, y, z, MT_HOOPCENTER); - - hoopcenter->spawnpoint = mthing; - - // Screw these damn hoops, I need this thinker. - //hoopcenter->flags |= MF_NOTHINK; - - z += -#ifdef ESLOPE - sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : -#endif - sec->floorheight; - - hoopcenter->z = z - hoopcenter->height/2; - - P_UnsetThingPosition(hoopcenter); - hoopcenter->x = x; - hoopcenter->y = y; - P_SetThingPosition(hoopcenter); - - // Scale 0-255 to 0-359 =( - closestangle = FixedAngle(FixedMul((mthing->angle>>8)*FRACUNIT, - 360*(FRACUNIT/256))); - - hoopcenter->movedir = FixedInt(FixedMul((mthing->angle&255)*FRACUNIT, - 360*(FRACUNIT/256))); - hoopcenter->movecount = FixedInt(AngleFixed(closestangle)); - - // For the hoop when it flies away - hoopcenter->extravalue1 = 32; - hoopcenter->extravalue2 = 8 * FRACUNIT; - - spewangle = (INT16)hoopcenter->movedir; - - // Create the hoop! - for (i = 0; i < 32; i++) - { - fa = i*(FINEANGLES/32); - v[0] = FixedMul(FINECOSINE(fa),96*FRACUNIT); - v[1] = 0; - v[2] = FixedMul(FINESINE(fa),96*FRACUNIT); - v[3] = FRACUNIT; - - res = VectorMatrixMultiply(v, *RotateXMatrix(FixedAngle(spewangle*FRACUNIT))); - M_Memcpy(&v, res, sizeof (v)); - res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle)); - M_Memcpy(&v, res, sizeof (v)); - - finalx = x + v[0]; - finaly = y + v[1]; - finalz = z + v[2]; - - mobj = P_SpawnMobj(finalx, finaly, finalz, MT_HOOP); - - if (maptol & TOL_XMAS) - P_SetMobjState(mobj, mobj->info->seestate + (i & 1)); - - mobj->z -= mobj->height/2; - P_SetTarget(&mobj->target, hoopcenter); // Link the sprite to the center. - mobj->fuse = 0; - - // Link all the sprites in the hoop together - if (nextmobj) - { - P_SetTarget(&mobj->hprev, nextmobj); - P_SetTarget(&mobj->hprev->hnext, mobj); - } - else - P_SetTarget(&mobj->hprev, P_SetTarget(&mobj->hnext, NULL)); - - nextmobj = mobj; - } - - // Create the collision detectors! - for (i = 0; i < 16; i++) - { - fa = i*FINEANGLES/16; - v[0] = FixedMul(FINECOSINE(fa),32*FRACUNIT); - v[1] = 0; - v[2] = FixedMul(FINESINE(fa),32*FRACUNIT); - v[3] = FRACUNIT; - res = VectorMatrixMultiply(v, *RotateXMatrix(FixedAngle(spewangle*FRACUNIT))); - M_Memcpy(&v, res, sizeof (v)); - res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle)); - M_Memcpy(&v, res, sizeof (v)); - - finalx = x + v[0]; - finaly = y + v[1]; - finalz = z + v[2]; - - mobj = P_SpawnMobj(finalx, finaly, finalz, MT_HOOPCOLLIDE); - mobj->z -= mobj->height/2; - - // Link all the collision sprites together. - P_SetTarget(&mobj->hnext, NULL); - P_SetTarget(&mobj->hprev, nextmobj); - P_SetTarget(&mobj->hprev->hnext, mobj); - - nextmobj = mobj; - } - // Create the collision detectors! - for (i = 0; i < 16; i++) - { - fa = i*FINEANGLES/16; - v[0] = FixedMul(FINECOSINE(fa),64*FRACUNIT); - v[1] = 0; - v[2] = FixedMul(FINESINE(fa),64*FRACUNIT); - v[3] = FRACUNIT; - res = VectorMatrixMultiply(v, *RotateXMatrix(FixedAngle(spewangle*FRACUNIT))); - M_Memcpy(&v, res, sizeof (v)); - res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle)); - M_Memcpy(&v, res, sizeof (v)); - - finalx = x + v[0]; - finaly = y + v[1]; - finalz = z + v[2]; - - mobj = P_SpawnMobj(finalx, finaly, finalz, MT_HOOPCOLLIDE); - mobj->z -= mobj->height/2; - - // Link all the collision sprites together. - P_SetTarget(&mobj->hnext, NULL); - P_SetTarget(&mobj->hprev, nextmobj); - P_SetTarget(&mobj->hprev->hnext, mobj); - - nextmobj = mobj; - } + P_SpawnHoop(mthing, x, y, z, sec, 24, 4*FRACUNIT); return; } // CUSTOMIZABLE NiGHTS hoop! else if (mthing->type == 1713) { - mobj_t *nextmobj = NULL; - mobj_t *hoopcenter; - INT16 spewangle; - INT32 hoopsize; - INT32 hoopplacement; - - // Save our flags! - z = (mthing->options>>ZSHIFT) << FRACBITS; - - hoopcenter = P_SpawnMobj(x, y, z, MT_HOOPCENTER); - hoopcenter->spawnpoint = mthing; - - z += -#ifdef ESLOPE - sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : -#endif - sec->floorheight; - hoopcenter->z = z - hoopcenter->height/2; - - P_UnsetThingPosition(hoopcenter); - hoopcenter->x = x; - hoopcenter->y = y; - P_SetThingPosition(hoopcenter); - - // Scale 0-255 to 0-359 =( - closestangle = FixedAngle(FixedMul((mthing->angle>>8)*FRACUNIT, - 360*(FRACUNIT/256))); - - hoopcenter->movedir = FixedInt(FixedMul((mthing->angle&255)*FRACUNIT, - 360*(FRACUNIT/256))); - hoopcenter->movecount = FixedInt(AngleFixed(closestangle)); - - spewangle = (INT16)hoopcenter->movedir; - // Super happy fun time - // For each flag add 4 fracunits to the size - // Default (0 flags) is 8 fracunits - hoopsize = 8 + (4 * (mthing->options & 0xF)); - hoopplacement = hoopsize * (4*FRACUNIT); - - // For the hoop when it flies away - hoopcenter->extravalue1 = hoopsize; - hoopcenter->extravalue2 = FixedDiv(hoopplacement, 12*FRACUNIT); - - // Create the hoop! - for (i = 0; i < hoopsize; i++) - { - fa = i*(FINEANGLES/hoopsize); - v[0] = FixedMul(FINECOSINE(fa), hoopplacement); - v[1] = 0; - v[2] = FixedMul(FINESINE(fa), hoopplacement); - v[3] = FRACUNIT; - - res = VectorMatrixMultiply(v, *RotateXMatrix(FixedAngle(spewangle*FRACUNIT))); - M_Memcpy(&v, res, sizeof (v)); - res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle)); - M_Memcpy(&v, res, sizeof (v)); - - finalx = x + v[0]; - finaly = y + v[1]; - finalz = z + v[2]; - - mobj = P_SpawnMobj(finalx, finaly, finalz, MT_HOOP); - - if (maptol & TOL_XMAS) - P_SetMobjState(mobj, mobj->info->seestate + (i & 1)); - - mobj->z -= mobj->height/2; - P_SetTarget(&mobj->target, hoopcenter); // Link the sprite to the center. - mobj->fuse = 0; - - // Link all the sprites in the hoop together - if (nextmobj) - { - P_SetTarget(&mobj->hprev, nextmobj); - P_SetTarget(&mobj->hprev->hnext, mobj); - } - else - P_SetTarget(&mobj->hprev, P_SetTarget(&mobj->hnext, NULL)); - - nextmobj = mobj; - } - - // Create the collision detectors! - // Create them until the size is less than 8 - // But always create at least ONE set of collision detectors - do - { - if (hoopsize >= 32) - hoopsize -= 16; - else - hoopsize /= 2; - - hoopplacement = hoopsize * (4*FRACUNIT); - - for (i = 0; i < hoopsize; i++) - { - fa = i*FINEANGLES/hoopsize; - v[0] = FixedMul(FINECOSINE(fa), hoopplacement); - v[1] = 0; - v[2] = FixedMul(FINESINE(fa), hoopplacement); - v[3] = FRACUNIT; - res = VectorMatrixMultiply(v, *RotateXMatrix(FixedAngle(spewangle*FRACUNIT))); - M_Memcpy(&v, res, sizeof (v)); - res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle)); - M_Memcpy(&v, res, sizeof (v)); - - finalx = x + v[0]; - finaly = y + v[1]; - finalz = z + v[2]; - - mobj = P_SpawnMobj(finalx, finaly, finalz, MT_HOOPCOLLIDE); - mobj->z -= mobj->height/2; - - // Link all the collision sprites together. - P_SetTarget(&mobj->hnext, NULL); - P_SetTarget(&mobj->hprev, nextmobj); - P_SetTarget(&mobj->hprev->hnext, mobj); - - nextmobj = mobj; - } - } while (hoopsize >= 8); - + // For each flag add 16 fracunits to the size + // Default (0 flags) is 32 fracunits + z = (mthing->options >> ZSHIFT) << FRACBITS; + P_SpawnHoop(mthing, x, y, z, sec, 8 + (4*(mthing->options & 0xF)), 4*FRACUNIT); return; } // *** From 579362fd3bd0d5dcbda606680459302e408f9b08 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Sun, 22 Dec 2019 23:22:15 +0100 Subject: [PATCH 138/195] P_LoadMapData(): Throw an error if resources are not found. --- src/p_setup.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/p_setup.c b/src/p_setup.c index 14d2cc9e6..bc736588e 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1960,6 +1960,17 @@ static void P_LoadMapData(const virtres_t* virt) virtsidedefs = vres_Find(virt, "SIDEDEFS"); virtlinedefs = vres_Find(virt, "LINEDEFS"); + if (!virtthings) + I_Error("THINGS lump not found"); + if (!virtvertexes) + I_Error("VERTEXES lump not found"); + if (!virtsectors) + I_Error("SECTORS lump not found"); + if (!virtsidedefs) + I_Error("SIDEDEFS lump not found"); + if (!virtlinedefs) + I_Error("LINEDEFS lump not found"); + // Traditional doom map format just assumes the number of elements from the lump sizes. numvertexes = virtvertexes->size / sizeof (mapvertex_t); numsectors = virtsectors->size / sizeof (mapsector_t); From 356b25def45606a61e805f68e486264277c52167 Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Mon, 23 Dec 2019 00:28:06 -0500 Subject: [PATCH 139/195] Spawn Amy's shields for other players --- src/p_inter.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/p_inter.c b/src/p_inter.c index 4da942f72..5ec1161ea 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -3430,6 +3430,15 @@ void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source) // unless cv_friendlyfire is on. if (!cv_friendlyfire.value) { + if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) + { + if (player->revitem != MT_LHRT && player->spinitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers. + { + P_SwitchShield(player, SH_PINK); + S_StartSound(player->mo, mobjinfo[MT_PITY_ICON].seesound); + } + } + if (inflictor->type == MT_LHRT) return; From efb47b3786ad163faf5116cc5eb39fa4ec149b21 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Mon, 23 Dec 2019 12:07:03 +0100 Subject: [PATCH 140/195] Move spawning of ring-like items into its own function, use P_GetMobjSpawnHeight() --- src/p_mobj.c | 129 +++++++++++++++++++++++---------------------------- 1 file changed, 57 insertions(+), 72 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 87ec1fe9f..b74c70dd3 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11595,13 +11595,21 @@ static fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* case MT_EMERALDSPAWN: case MT_TOKEN: case MT_EMBLEM: + case MT_RING: + case MT_REDTEAMRING: + case MT_BLUETEAMRING: + case MT_COIN: + case MT_BLUESPHERE: + case MT_BOMBSPHERE: + case MT_NIGHTSCHIP: + case MT_NIGHTSSTAR: offset += mthing->options & MTF_AMBUSH ? 24*FRACUNIT : 0; break; // Remaining objects. default: if (P_WeaponOrPanel(mobjtype)) - offset += mthing->options & MTF_AMBUSH ? 24 * FRACUNIT : 0; + offset += mthing->options & MTF_AMBUSH ? 24*FRACUNIT : 0; } if (!offset) // Snap to the surfaces when there's no offset set. @@ -13165,6 +13173,53 @@ static void P_SpawnHoop(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z, sec } while (hoopsize >= 8); } +static void P_SpawnRingItem(mapthing_t *mthing, fixed_t x, fixed_t y, boolean bonustime, boolean nightsreplace) +{ + mobjtype_t ringthing = MT_RING; + mobj_t *mobj = NULL; + fixed_t z; + + // Which ringthing to use + if (mthing->type == mobjinfo[MT_BLUESPHERE].doomednum) + ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE; + else if (mthing->type == mobjinfo[MT_BOMBSPHERE].doomednum) + ringthing = MT_BOMBSPHERE; + else + { + if (ultimatemode) + return; // No rings in Ultimate! + + if (nightsreplace) + ringthing = MT_NIGHTSSTAR; + else if (mthing->type == mobjinfo[MT_COIN].doomednum) + ringthing = MT_COIN; + else if (mthing->type == mobjinfo[MT_REDTEAMRING].doomednum) // No team rings in non-CTF + ringthing = (gametype == GT_CTF) ? MT_REDTEAMRING : MT_RING; + else if (mthing->type == mobjinfo[MT_BLUETEAMRING].doomednum) // Ditto + ringthing = (gametype == GT_CTF) ? MT_BLUETEAMRING : MT_RING; + } + + z = P_GetMobjSpawnHeight(ringthing, mthing, x, y); + mobj = P_SpawnMobj(x, y, z, ringthing); + mobj->spawnpoint = mthing; + + if (mthing->options & MTF_OBJECTFLIP) + { + mobj->eflags |= MFE_VERTICALFLIP; + mobj->flags2 |= MF2_OBJECTFLIP; + } + + mobj->angle = FixedAngle(mthing->angle << FRACBITS); + mthing->mobj = mobj; + if (mthing->options & MTF_AMBUSH) + mobj->flags2 |= MF2_AMBUSH; + + if (bonustime && (ringthing == MT_BLUESPHERE || ringthing == MT_NIGHTSCHIP)) + P_SetMobjState(mobj, mobj->info->raisestate); + else if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR)) + P_SetMobjState(mobj, mobj->info->seestate); +} + void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) { mobjtype_t ringthing = MT_RING; @@ -13414,77 +13469,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) } // All manners of rings and coins else - { - - // Which ringthing to use - if (mthing->type == mobjinfo[MT_BLUESPHERE].doomednum) - ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE; - else if (mthing->type == mobjinfo[MT_BOMBSPHERE].doomednum) - ringthing = MT_BOMBSPHERE; - else - { - if (ultimatemode) - return; // No rings in Ultimate! - - if (nightsreplace) - ringthing = MT_NIGHTSSTAR; - else if (mthing->type == mobjinfo[MT_COIN].doomednum) - ringthing = MT_COIN; - else if (mthing->type == mobjinfo[MT_REDTEAMRING].doomednum) // No team rings in non-CTF - ringthing = (gametype == GT_CTF) ? MT_REDTEAMRING : MT_RING; - else if (mthing->type == mobjinfo[MT_BLUETEAMRING].doomednum) // Ditto - ringthing = (gametype == GT_CTF) ? MT_BLUETEAMRING : MT_RING; - } - - // Set proper height - if (mthing->options & MTF_OBJECTFLIP) - { - z = ( -#ifdef ESLOPE - sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : -#endif - sec->ceilingheight) - mobjinfo[ringthing].height; - if (mthing->z) - z -= (mthing->z << FRACBITS); - } - else - { - z = -#ifdef ESLOPE - sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : -#endif - sec->floorheight; - if (mthing->z) - z += (mthing->z << FRACBITS); - } - - if (mthing->options & MTF_AMBUSH) // Special flag for rings - { - if (mthing->options & MTF_OBJECTFLIP) - z -= 24*FRACUNIT; - else - z += 24*FRACUNIT; - } - - mobj = P_SpawnMobj(x, y, z, ringthing); - mobj->spawnpoint = mthing; - - if (mthing->options & MTF_OBJECTFLIP) - { - mobj->eflags |= MFE_VERTICALFLIP; - mobj->flags2 |= MF2_OBJECTFLIP; - } - - mobj->angle = FixedAngle(mthing->angle*FRACUNIT); - mthing->mobj = mobj; - if (mthing->options & MTF_AMBUSH) - mobj->flags2 |= MF2_AMBUSH; - - if (bonustime && (ringthing == MT_BLUESPHERE || ringthing == MT_NIGHTSCHIP)) - P_SetMobjState(mobj, mobj->info->raisestate); - else if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR)) - P_SetMobjState(mobj, mobj->info->seestate); - } + P_SpawnRingItem(mthing, x, y, bonustime, nightsreplace); } // From eadf9539571a60b98bea01fda60bb4e65db62e98 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Mon, 23 Dec 2019 12:30:01 +0100 Subject: [PATCH 141/195] Store a copy of sectors, lines and sides in memory so that P_NetArchiveWorld() can soon use them instead of relying on re-opening the original lumps. Fix print type issue. --- src/p_setup.c | 12 ++++++++++++ src/r_state.h | 3 +++ 2 files changed, 15 insertions(+) diff --git a/src/p_setup.c b/src/p_setup.c index bc736588e..529cab798 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -103,6 +103,9 @@ node_t *nodes; line_t *lines; side_t *sides; mapthing_t *mapthings; +sector_t *spawnsectors; +line_t *spawnlines; +side_t *spawnsides; INT32 numstarposts; UINT16 bossdisabled; boolean stoppedclock; @@ -2775,6 +2778,15 @@ boolean P_SetupLevel(boolean skipprecip) P_LoadLineDefs2(); P_GroupLines(); + // Copy relevant map data for NetArchive purposes. + spawnsectors = Z_Calloc(numsectors * sizeof (*sectors), PU_LEVEL, NULL); + spawnlines = Z_Calloc(numlines * sizeof (*lines), PU_LEVEL, NULL); + spawnsides = Z_Calloc(numsides * sizeof (*sides), PU_LEVEL, NULL); + + memcpy(spawnsectors, sectors, numsectors * sizeof (*sectors)); + memcpy(spawnlines, lines, numlines * sizeof (*lines)); + memcpy(spawnsides, sides, numsides * sizeof (*sides)); + P_PrepareRawThings(vres_Find(virt, "THINGS")->data); P_MakeMapMD5(virt, &mapmd5); diff --git a/src/r_state.h b/src/r_state.h index 75566923b..4e1eb388e 100644 --- a/src/r_state.h +++ b/src/r_state.h @@ -63,6 +63,7 @@ extern seg_t *segs; extern size_t numsectors; extern sector_t *sectors; +extern sector_t *spawnsectors; extern size_t numsubsectors; extern subsector_t *subsectors; @@ -72,9 +73,11 @@ extern node_t *nodes; extern size_t numlines; extern line_t *lines; +extern line_t *spawnlines; extern size_t numsides; extern side_t *sides; +extern side_t *spawnsides; // // POV data. From 21dcbc856cc6ce9f77faf54a149e76195d4815cb Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Mon, 23 Dec 2019 12:42:09 +0100 Subject: [PATCH 142/195] Split up P_SpawnHoopsAndRings() into subfunctions --- src/p_mobj.c | 480 ++++++++++++++++++++++++++------------------------- 1 file changed, 248 insertions(+), 232 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index b74c70dd3..459a7c003 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -13220,256 +13220,272 @@ static void P_SpawnRingItem(mapthing_t *mthing, fixed_t x, fixed_t y, boolean bo P_SetMobjState(mobj, mobj->info->seestate); } -void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) +static void P_SpawnVerticalSpringRings(mapthing_t *mthing, fixed_t x, fixed_t y, sector_t* sec, boolean nightsreplace) { mobjtype_t ringthing = MT_RING; - mobj_t *mobj = NULL; - INT32 r, i; - fixed_t x, y, z, finalx, finaly, finalz; - sector_t *sec; - TVector v, *res; - angle_t closestangle, fa; - boolean nightsreplace = ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)); + mobj_t* mobj = NULL; + fixed_t z; + INT32 r; - x = mthing->x << FRACBITS; - y = mthing->y << FRACBITS; + INT32 dist = 64*FRACUNIT; + if (mthing->type == 601) + dist = 128*FRACUNIT; - sec = R_PointInSubsector(x, y)->sector; + if (ultimatemode) + return; // No rings in Ultimate! - // NiGHTS hoop! - if (mthing->type == 1705) + if (nightsreplace) + ringthing = MT_NIGHTSSTAR; + + if (mthing->options & MTF_OBJECTFLIP) { - z = mthing->z << FRACBITS; - P_SpawnHoop(mthing, x, y, z, sec, 24, 4*FRACUNIT); - return; - } - // CUSTOMIZABLE NiGHTS hoop! - else if (mthing->type == 1713) - { - // Super happy fun time - // For each flag add 16 fracunits to the size - // Default (0 flags) is 32 fracunits - z = mthing->z << FRACBITS; - P_SpawnHoop(mthing, x, y, z, sec, 8 + (4*(mthing->options & 0xF)), 4*FRACUNIT); - return; - } - // *** - // Special placement patterns - // *** - - // Vertical Rings - Stack of 5 (handles both red and yellow) - else if (mthing->type == 600 || mthing->type == 601) - { - INT32 dist = 64*FRACUNIT; - if (mthing->type == 601) - dist = 128*FRACUNIT; - - if (ultimatemode) - return; // No rings in Ultimate! - - if (nightsreplace) - ringthing = MT_NIGHTSSTAR; - - if (mthing->options & MTF_OBJECTFLIP) - { - z = ( + z = ( #ifdef ESLOPE - sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : + sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : #endif - sec->ceilingheight) - mobjinfo[ringthing].height; - if (mthing->z) - z -= (mthing->z << FRACBITS); - } - else - { - z = ( -#ifdef ESLOPE - sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : -#endif - sec->floorheight); - if (mthing->z) - z += (mthing->z << FRACBITS); - } - - for (r = 1; r <= 5; r++) - { - if (mthing->options & MTF_OBJECTFLIP) - z -= dist; - else - z += dist; - - mobj = P_SpawnMobj(x, y, z, ringthing); - - if (mthing->options & MTF_OBJECTFLIP) - { - mobj->eflags |= MFE_VERTICALFLIP; - mobj->flags2 |= MF2_OBJECTFLIP; - } - - mobj->angle = FixedAngle(mthing->angle*FRACUNIT); - if (mthing->options & MTF_AMBUSH) - mobj->flags2 |= MF2_AMBUSH; - - if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR)) - P_SetMobjState(mobj, mobj->info->seestate); - } + sec->ceilingheight) - mobjinfo[ringthing].height; + if (mthing->z) + z -= (mthing->z << FRACBITS); } - // Diagonal rings (handles both types) - else if (mthing->type == 602 || mthing->type == 603) // Diagonal rings (5) + else { - INT32 iterations = 5; - if (mthing->type == 603) - iterations = 10; - - if (ultimatemode) - return; // No rings in Ultimate! - - if (nightsreplace) - ringthing = MT_NIGHTSSTAR; - - closestangle = FixedAngle(mthing->angle*FRACUNIT); - fa = (closestangle >> ANGLETOFINESHIFT); - - if (mthing->options & MTF_OBJECTFLIP) - { - z = ( -#ifdef ESLOPE - sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : -#endif - sec->ceilingheight) - mobjinfo[ringthing].height; - if (mthing->z) - z -= (mthing->z << FRACBITS); - } - else - { - z = ( -#ifdef ESLOPE - sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : -#endif - sec->floorheight); - if (mthing->z) - z += (mthing->z << FRACBITS); - } - - for (r = 1; r <= iterations; r++) - { - x += FixedMul(64*FRACUNIT, FINECOSINE(fa)); - y += FixedMul(64*FRACUNIT, FINESINE(fa)); - - if (mthing->options & MTF_OBJECTFLIP) - z -= 64*FRACUNIT; - else - z += 64*FRACUNIT; - - mobj = P_SpawnMobj(x, y, z, ringthing); - - if (mthing->options & MTF_OBJECTFLIP) - { - mobj->eflags |= MFE_VERTICALFLIP; - mobj->flags2 |= MF2_OBJECTFLIP; - } - - mobj->angle = closestangle; - if (mthing->options & MTF_AMBUSH) - mobj->flags2 |= MF2_AMBUSH; - - if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR)) - P_SetMobjState(mobj, mobj->info->seestate); - } - } - // Rings of items (all six of them) - else if (mthing->type >= 604 && mthing->type <= 609) - { - INT32 numitems = 8; - INT32 size = 96*FRACUNIT; - - if (mthing->type & 1) - { - numitems = 16; - size = 192*FRACUNIT; - } - - z = + z = ( #ifdef ESLOPE sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : #endif - sec->floorheight; + sec->floorheight); if (mthing->z) z += (mthing->z << FRACBITS); - - closestangle = FixedAngle(mthing->angle*FRACUNIT); - - switch (mthing->type) - { - case 604: - case 605: - if (ultimatemode) - return; // No rings in Ultimate! - if (nightsreplace) - ringthing = MT_NIGHTSSTAR; - break; - case 608: - case 609: - /*ringthing = (i & 1) ? MT_RING : MT_BLUESPHERE; -- i == 0 is bluesphere - break;*/ - case 606: - case 607: - ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE; - break; - default: - break; - } - - // Create the hoop! - for (i = 0; i < numitems; i++) - { - if (mthing->type == 608 || mthing->type == 609) - { - if (i & 1) - { - if (ultimatemode) - continue; // No rings in Ultimate! - ringthing = (nightsreplace) ? MT_NIGHTSSTAR : MT_RING; - } - else - ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE; - } - - fa = i*FINEANGLES/numitems; - v[0] = FixedMul(FINECOSINE(fa),size); - v[1] = 0; - v[2] = FixedMul(FINESINE(fa),size); - v[3] = FRACUNIT; - - res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle)); - M_Memcpy(&v, res, sizeof (v)); - - finalx = x + v[0]; - finaly = y + v[1]; - finalz = z + v[2]; - - mobj = P_SpawnMobj(finalx, finaly, finalz, ringthing); - mobj->z -= mobj->height/2; - - if (mthing->options & MTF_OBJECTFLIP) - { - mobj->eflags |= MFE_VERTICALFLIP; - mobj->flags2 |= MF2_OBJECTFLIP; - } - - mobj->angle = closestangle; - if (mthing->options & MTF_AMBUSH) - mobj->flags2 |= MF2_AMBUSH; - - if (bonustime && (ringthing == MT_BLUESPHERE || ringthing == MT_NIGHTSCHIP)) - P_SetMobjState(mobj, mobj->info->raisestate); - else if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR)) - P_SetMobjState(mobj, mobj->info->seestate); - } } - // All manners of rings and coins + + for (r = 1; r <= 5; r++) + { + if (mthing->options & MTF_OBJECTFLIP) + z -= dist; + else + z += dist; + + mobj = P_SpawnMobj(x, y, z, ringthing); + + if (mthing->options & MTF_OBJECTFLIP) + { + mobj->eflags |= MFE_VERTICALFLIP; + mobj->flags2 |= MF2_OBJECTFLIP; + } + + mobj->angle = FixedAngle(mthing->angle << FRACBITS); + if (mthing->options & MTF_AMBUSH) + mobj->flags2 |= MF2_AMBUSH; + + if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR)) + P_SetMobjState(mobj, mobj->info->seestate); + } +} + +static void P_SpawnDiagonalSpringRings(mapthing_t* mthing, fixed_t x, fixed_t y, sector_t* sec, boolean nightsreplace) +{ + mobjtype_t ringthing = MT_RING; + mobj_t *mobj = NULL; + fixed_t z; + INT32 r; + angle_t closestangle, fa; + + INT32 iterations = 5; + if (mthing->type == 603) + iterations = 10; + + if (ultimatemode) + return; // No rings in Ultimate! + + if (nightsreplace) + ringthing = MT_NIGHTSSTAR; + + closestangle = FixedAngle(mthing->angle << FRACBITS); + fa = (closestangle >> ANGLETOFINESHIFT); + + if (mthing->options & MTF_OBJECTFLIP) + { + z = ( +#ifdef ESLOPE + sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : +#endif + sec->ceilingheight) - mobjinfo[ringthing].height; + if (mthing->z) + z -= (mthing->z << FRACBITS); + } else + { + z = ( +#ifdef ESLOPE + sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : +#endif + sec->floorheight); + if (mthing->z) + z += (mthing->z << FRACBITS); + } + + for (r = 1; r <= iterations; r++) + { + x += FixedMul(64*FRACUNIT, FINECOSINE(fa)); + y += FixedMul(64*FRACUNIT, FINESINE(fa)); + + if (mthing->options & MTF_OBJECTFLIP) + z -= 64*FRACUNIT; + else + z += 64*FRACUNIT; + + mobj = P_SpawnMobj(x, y, z, ringthing); + + if (mthing->options & MTF_OBJECTFLIP) + { + mobj->eflags |= MFE_VERTICALFLIP; + mobj->flags2 |= MF2_OBJECTFLIP; + } + + mobj->angle = closestangle; + if (mthing->options & MTF_AMBUSH) + mobj->flags2 |= MF2_AMBUSH; + + if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR)) + P_SetMobjState(mobj, mobj->info->seestate); + } +} + +static void P_SpawnItemCircle(mapthing_t* mthing, fixed_t x, fixed_t y, sector_t* sec, boolean bonustime, boolean nightsreplace) +{ + mobjtype_t ringthing = MT_RING; + mobj_t *mobj = NULL; + fixed_t z, finalx, finaly, finalz; + angle_t closestangle, fa; + INT32 i; + TVector v, *res; + INT32 numitems = 8; + INT32 size = 96*FRACUNIT; + + if (mthing->type & 1) + { + numitems = 16; + size = 192*FRACUNIT; + } + + z = +#ifdef ESLOPE + sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : +#endif + sec->floorheight; + if (mthing->z) + z += (mthing->z << FRACBITS); + + closestangle = FixedAngle(mthing->angle << FRACBITS); + + switch (mthing->type) + { + case 604: + case 605: + if (ultimatemode) + return; // No rings in Ultimate! + if (nightsreplace) + ringthing = MT_NIGHTSSTAR; + break; + case 608: + case 609: + /*ringthing = (i & 1) ? MT_RING : MT_BLUESPHERE; -- i == 0 is bluesphere + break;*/ + case 606: + case 607: + ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE; + break; + default: + break; + } + + // Create the hoop! + for (i = 0; i < numitems; i++) + { + if (mthing->type == 608 || mthing->type == 609) + { + if (i & 1) + { + if (ultimatemode) + continue; // No rings in Ultimate! + ringthing = (nightsreplace) ? MT_NIGHTSSTAR : MT_RING; + } + else + ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE; + } + + fa = i * FINEANGLES/numitems; + v[0] = FixedMul(FINECOSINE(fa), size); + v[1] = 0; + v[2] = FixedMul(FINESINE(fa), size); + v[3] = FRACUNIT; + + res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle)); + M_Memcpy(&v, res, sizeof(v)); + + finalx = x + v[0]; + finaly = y + v[1]; + finalz = z + v[2]; + + mobj = P_SpawnMobj(finalx, finaly, finalz, ringthing); + mobj->z -= mobj->height/2; + + if (mthing->options & MTF_OBJECTFLIP) + { + mobj->eflags |= MFE_VERTICALFLIP; + mobj->flags2 |= MF2_OBJECTFLIP; + } + + mobj->angle = closestangle; + if (mthing->options & MTF_AMBUSH) + mobj->flags2 |= MF2_AMBUSH; + + if (bonustime && (ringthing == MT_BLUESPHERE || ringthing == MT_NIGHTSCHIP)) + P_SetMobjState(mobj, mobj->info->raisestate); + else if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR)) + P_SetMobjState(mobj, mobj->info->seestate); + } +} + +void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) +{ + fixed_t x = mthing->x << FRACBITS; + fixed_t y = mthing->y << FRACBITS; + fixed_t z = mthing->z << FRACBITS; + sector_t *sec = R_PointInSubsector(x, y)->sector; + boolean nightsreplace = ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)); + + switch (mthing->type) + { + // Special placement patterns + case 600: // 5 vertical rings (yellow spring) + case 601: // 5 vertical rings (red spring) + P_SpawnVerticalSpringRings(mthing, x, y, sec, nightsreplace); + return; + case 602: // 5 diagonal rings (yellow spring) + case 603: // 10 diagonal rings (red spring) + P_SpawnDiagonalSpringRings(mthing, x, y, sec, nightsreplace); + return; + case 604: // Circle of rings (8 items) + case 605: // Circle of rings (16 bits) + case 606: // Circle of blue spheres (8 items) + case 607: // Circle of blue spheres (16 items) + case 608: // Circle of rings and blue spheres (8 items) + case 609: // Circle of rings and blue spheres (16 items) + P_SpawnItemCircle(mthing, x, y, sec, bonustime, nightsreplace); + return; + // Hoops + case 1705: // Generic NiGHTS hoop + P_SpawnHoop(mthing, x, y, z, sec, 24, 4*FRACUNIT); + return; + case 1713: // Customizable NiGHTS hoop + // For each flag add 16 fracunits to the size + // Default (0 flags) is 32 fracunits + P_SpawnHoop(mthing, x, y, z, sec, 8 + (4*(mthing->options & 0xF)), 4*FRACUNIT); + return; + default: // All manners of rings and coins P_SpawnRingItem(mthing, x, y, bonustime, nightsreplace); + } } // From bb54597552df972c4a4e27144df4876da7757e5c Mon Sep 17 00:00:00 2001 From: Nev3r Date: Mon, 23 Dec 2019 12:42:38 +0100 Subject: [PATCH 143/195] Remove redundant netarchive-related sector vars as they're not used anymore. Replace lump-based difference checks for sectors in P_NetArchiveWorld(), now it uses the mapload-created copy instead. --- src/p_saveg.c | 34 +++++++++++++++++----------------- src/p_setup.c | 4 ---- src/p_spec.c | 12 ++---------- src/r_defs.h | 11 ----------- 4 files changed, 19 insertions(+), 42 deletions(-) diff --git a/src/p_saveg.c b/src/p_saveg.c index c876713e4..356d696a5 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -782,10 +782,10 @@ static void P_NetArchiveWorld(void) // reload the map just to see difference virtres_t* virt = vres_GetMap(lastloadedmaplumpnum); - mapsector_t *ms = (mapsector_t*) vres_Find(virt, "SECTORS")->data; mapsidedef_t *msd = (mapsidedef_t*) vres_Find(virt, "SIDEDEFS")->data; maplinedef_t *mld = (maplinedef_t*) vres_Find(virt, "LINEDEFS")->data; const sector_t *ss = sectors; + const sector_t *spawnss = spawnsectors; UINT8 diff, diff2, diff3; // initialize colormap vars because paranoia @@ -794,45 +794,45 @@ static void P_NetArchiveWorld(void) WRITEUINT32(save_p, ARCHIVEBLOCK_WORLD); put = save_p; - for (i = 0; i < numsectors; i++, ss++, ms++) + for (i = 0; i < numsectors; i++, ss++, spawnss++) { diff = diff2 = diff3 = 0; - if (ss->floorheight != SHORT(ms->floorheight)<floorheight != spawnss->floorheight) diff |= SD_FLOORHT; - if (ss->ceilingheight != SHORT(ms->ceilingheight)<ceilingheight != spawnss->ceilingheight) diff |= SD_CEILHT; // // flats // - if (ss->floorpic != P_CheckLevelFlat(ms->floorpic)) + if (ss->floorpic != spawnss->floorpic) diff |= SD_FLOORPIC; - if (ss->ceilingpic != P_CheckLevelFlat(ms->ceilingpic)) + if (ss->ceilingpic != spawnss->ceilingpic) diff |= SD_CEILPIC; - if (ss->lightlevel != SHORT(ms->lightlevel)) + if (ss->lightlevel != spawnss->lightlevel) diff |= SD_LIGHT; - if (ss->special != SHORT(ms->special)) + if (ss->special != spawnss->special) diff |= SD_SPECIAL; - if (ss->floor_xoffs != ss->spawn_flr_xoffs) + if (ss->floor_xoffs != spawnss->floor_xoffs) diff2 |= SD_FXOFFS; - if (ss->floor_yoffs != ss->spawn_flr_yoffs) + if (ss->floor_yoffs != spawnss->floor_yoffs) diff2 |= SD_FYOFFS; - if (ss->ceiling_xoffs != ss->spawn_ceil_xoffs) + if (ss->ceiling_xoffs != spawnss->ceiling_xoffs) diff2 |= SD_CXOFFS; - if (ss->ceiling_yoffs != ss->spawn_ceil_yoffs) + if (ss->ceiling_yoffs != spawnss->ceiling_yoffs) diff2 |= SD_CYOFFS; - if (ss->floorpic_angle != ss->spawn_flrpic_angle) + if (ss->floorpic_angle != spawnss->floorpic_angle) diff2 |= SD_FLOORANG; - if (ss->ceilingpic_angle != ss->spawn_flrpic_angle) + if (ss->ceilingpic_angle != spawnss->ceilingpic_angle) diff2 |= SD_CEILANG; - if (ss->tag != SHORT(ms->tag)) + if (ss->tag != spawnss->tag) diff2 |= SD_TAG; - if (ss->nexttag != ss->spawn_nexttag || ss->firsttag != ss->spawn_firsttag) + if (ss->nexttag != spawnss->nexttag || ss->firsttag != spawnss->firsttag) diff3 |= SD_TAGLIST; - if (ss->extra_colormap != ss->spawn_extra_colormap) + if (ss->extra_colormap != spawnss->extra_colormap) diff3 |= SD_COLORMAP; // Check if any of the sector's FOFs differ from how they spawned diff --git a/src/p_setup.c b/src/p_setup.c index 529cab798..6e6c1a72b 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -669,11 +669,9 @@ static void P_LoadRawSectors(UINT8 *data) ss->ceilingpic = P_AddLevelFlat(ms->ceilingpic, foundflats); ss->lightlevel = SHORT(ms->lightlevel); - ss->spawn_lightlevel = SHORT(ms->lightlevel); ss->special = SHORT(ms->special); ss->tag = SHORT(ms->tag); ss->nexttag = ss->firsttag = -1; - ss->spawn_nexttag = ss->spawn_firsttag = -1; memset(&ss->soundorg, 0, sizeof(ss->soundorg)); ss->validcount = 0; @@ -708,9 +706,7 @@ static void P_LoadRawSectors(UINT8 *data) ss->spawn_extra_colormap = NULL; ss->floor_xoffs = ss->ceiling_xoffs = ss->floor_yoffs = ss->ceiling_yoffs = 0; - ss->spawn_flr_xoffs = ss->spawn_ceil_xoffs = ss->spawn_flr_yoffs = ss->spawn_ceil_yoffs = 0; ss->floorpic_angle = ss->ceilingpic_angle = 0; - ss->spawn_flrpic_angle = ss->spawn_ceilpic_angle = 0; ss->gravity = NULL; ss->cullheight = NULL; ss->verticalflip = false; diff --git a/src/p_spec.c b/src/p_spec.c index bf7f6210a..297c9a427 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1603,8 +1603,6 @@ static inline void P_InitTagLists(void) size_t j = (unsigned)sectors[i].tag % numsectors; sectors[i].nexttag = sectors[j].firsttag; sectors[j].firsttag = (INT32)i; - sectors[i].spawn_nexttag = sectors[i].nexttag; - sectors[j].spawn_firsttag = sectors[j].firsttag; } for (i = numlines - 1; i != (size_t)-1; i--) @@ -6405,22 +6403,16 @@ static void P_ApplyFlatAlignment(line_t *master, sector_t *sector, angle_t flata { if (!(master->flags & ML_NETONLY)) // Modify floor flat alignment unless ML_NETONLY flag is set { - sector->spawn_flrpic_angle = sector->floorpic_angle = flatangle; + sector->floorpic_angle = flatangle; sector->floor_xoffs += xoffs; sector->floor_yoffs += yoffs; - // saved for netgames - sector->spawn_flr_xoffs = sector->floor_xoffs; - sector->spawn_flr_yoffs = sector->floor_yoffs; } if (!(master->flags & ML_NONET)) // Modify ceiling flat alignment unless ML_NONET flag is set { - sector->spawn_ceilpic_angle = sector->ceilingpic_angle = flatangle; + sector->ceilingpic_angle = flatangle; sector->ceiling_xoffs += xoffs; sector->ceiling_yoffs += yoffs; - // saved for netgames - sector->spawn_ceil_xoffs = sector->ceiling_xoffs; - sector->spawn_ceil_yoffs = sector->ceiling_yoffs; } } diff --git a/src/r_defs.h b/src/r_defs.h index 3cc780545..353dc572b 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -384,17 +384,6 @@ typedef struct sector_s // for fade thinker INT16 spawn_lightlevel; - // these are saved for netgames, so do not let Lua touch these! - INT32 spawn_nexttag, spawn_firsttag; // the actual nexttag/firsttag values may differ if the sector's tag was changed - - // offsets sector spawned with (via linedef type 7) - fixed_t spawn_flr_xoffs, spawn_flr_yoffs; - fixed_t spawn_ceil_xoffs, spawn_ceil_yoffs; - - // flag angles sector spawned with (via linedef type 7) - angle_t spawn_flrpic_angle; - angle_t spawn_ceilpic_angle; - // colormap structure extracolormap_t *spawn_extra_colormap; } sector_t; From 1221c108c67db0b16ce21de288eae411fda9e14f Mon Sep 17 00:00:00 2001 From: Nev3r Date: Mon, 23 Dec 2019 12:47:40 +0100 Subject: [PATCH 144/195] Make lines and sides use the mapload copies in P_NetArchiveWorld() too; do no longer use vres stuff there. --- src/p_saveg.c | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/src/p_saveg.c b/src/p_saveg.c index 356d696a5..5af72cd46 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -777,13 +777,11 @@ static void P_NetArchiveWorld(void) size_t i; INT32 statsec = 0, statline = 0; const line_t *li = lines; + const line_t *spawnli = spawnlines; const side_t *si; + const side_t *spawnsi; UINT8 *put; - // reload the map just to see difference - virtres_t* virt = vres_GetMap(lastloadedmaplumpnum); - mapsidedef_t *msd = (mapsidedef_t*) vres_Find(virt, "SIDEDEFS")->data; - maplinedef_t *mld = (maplinedef_t*) vres_Find(virt, "LINEDEFS")->data; const sector_t *ss = sectors; const sector_t *spawnss = spawnsectors; UINT8 diff, diff2, diff3; @@ -936,45 +934,41 @@ static void P_NetArchiveWorld(void) WRITEUINT16(put, 0xffff); // do lines - for (i = 0; i < numlines; i++, mld++, li++) + for (i = 0; i < numlines; i++, spawnli++, li++) { diff = diff2 = diff3 = 0; - if (li->special != SHORT(mld->special)) + if (li->special != spawnli->special) diff |= LD_SPECIAL; - if (SHORT(mld->special) == 321 || SHORT(mld->special) == 322) // only reason li->callcount would be non-zero is if either of these are involved + if (spawnli->special == 321 || spawnli->special == 322) // only reason li->callcount would be non-zero is if either of these are involved diff |= LD_CLLCOUNT; if (li->sidenum[0] != 0xffff) { si = &sides[li->sidenum[0]]; - if (si->textureoffset != SHORT(msd[li->sidenum[0]].textureoffset)<sidenum[0]]; + if (si->textureoffset != spawnsi->textureoffset) diff |= LD_S1TEXOFF; //SoM: 4/1/2000: Some textures are colormaps. Don't worry about invalid textures. - if (R_CheckTextureNumForName(msd[li->sidenum[0]].toptexture) != -1 - && si->toptexture != R_TextureNumForName(msd[li->sidenum[0]].toptexture)) + if (si->toptexture != spawnsi->toptexture) diff |= LD_S1TOPTEX; - if (R_CheckTextureNumForName(msd[li->sidenum[0]].bottomtexture) != -1 - && si->bottomtexture != R_TextureNumForName(msd[li->sidenum[0]].bottomtexture)) + if (si->bottomtexture != spawnsi->bottomtexture) diff |= LD_S1BOTTEX; - if (R_CheckTextureNumForName(msd[li->sidenum[0]].midtexture) != -1 - && si->midtexture != R_TextureNumForName(msd[li->sidenum[0]].midtexture)) + if (si->midtexture != spawnsi->midtexture) diff |= LD_S1MIDTEX; } if (li->sidenum[1] != 0xffff) { si = &sides[li->sidenum[1]]; - if (si->textureoffset != SHORT(msd[li->sidenum[1]].textureoffset)<sidenum[1]]; + if (si->textureoffset != spawnsi->textureoffset) diff2 |= LD_S2TEXOFF; - if (R_CheckTextureNumForName(msd[li->sidenum[1]].toptexture) != -1 - && si->toptexture != R_TextureNumForName(msd[li->sidenum[1]].toptexture)) + if (si->toptexture != spawnsi->toptexture) diff2 |= LD_S2TOPTEX; - if (R_CheckTextureNumForName(msd[li->sidenum[1]].bottomtexture) != -1 - && si->bottomtexture != R_TextureNumForName(msd[li->sidenum[1]].bottomtexture)) + if (si->bottomtexture != spawnsi->bottomtexture) diff2 |= LD_S2BOTTEX; - if (R_CheckTextureNumForName(msd[li->sidenum[1]].midtexture) != -1 - && si->midtexture != R_TextureNumForName(msd[li->sidenum[1]].midtexture)) + if (si->midtexture != spawnsi->midtexture) diff2 |= LD_S2MIDTEX; if (diff2) diff |= LD_DIFF2; @@ -1018,7 +1012,6 @@ static void P_NetArchiveWorld(void) WRITEUINT16(put, 0xffff); R_ClearTextureNumCache(false); - vres_Free(virt); save_p = put; } From 112b15cca2f459559a00b6608af8bed23e624482 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Mon, 23 Dec 2019 14:45:43 +0100 Subject: [PATCH 145/195] Add P_GetMobjtype for finding the mobjtype for a given mapthingnum --- src/p_mobj.c | 50 ++++++++++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 459a7c003..112ef67f3 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11159,17 +11159,12 @@ void P_RespawnSpecials(void) if (mthing) { - mobjtype_t i; + mobjtype_t i = P_GetMobjtype(mthing->type); x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; ss = R_PointInSubsector(x, y); - // find which type to spawn - for (i = 0; i < NUMMOBJTYPES; i++) - if (mthing->type == mobjinfo[i].doomednum) - break; - - if (i == NUMMOBJTYPES) // prevent creation of objects with this type -- Monster Iestyn 17/12/17 + if (i == MT_UNKNOWN) // prevent creation of objects with this type -- Monster Iestyn 17/12/17 { // 3D Mode start Thing is unlikely to be added to the que, // so don't bother checking for that specific type @@ -11635,6 +11630,19 @@ static fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* ss->sector->floorheight) + offset; } +/** Returns corresponding mobj type from mapthing number. + * \param mthingtype Mapthing number in question. + * \return Mobj type; MT_UNKNOWN if nothing found. + */ +static mobjtype_t P_GetMobjtype(UINT16 mthingtype) +{ + mobjtype_t i; + for (i = 0; i < NUMMOBJTYPES; i++) + if (mthingtype == mobjinfo[i].doomednum) + return i; + return MT_UNKNOWN; +} + // // P_SpawnMapThing // The fields of the mapthing should @@ -11650,22 +11658,17 @@ void P_SpawnMapThing(mapthing_t *mthing) if (!mthing->type) return; // Ignore type-0 things as NOPs + if (mthing->type == 3328) // 3D Mode start Thing + return; + // Always spawn in objectplace. // Skip all returning code. if (objectplacing) { // find which type to spawn - for (i = 0; i < NUMMOBJTYPES; i++) - if (mthing->type == mobjinfo[i].doomednum) - break; - - if (i == NUMMOBJTYPES) - { - if (mthing->type == 3328) // 3D Mode start Thing - return; + i = P_GetMobjtype(mthing->type); + if (i == MT_UNKNOWN) CONS_Alert(CONS_WARNING, M_GetText("Unknown thing type %d placed at (%d, %d)\n"), mthing->type, mthing->x, mthing->y); - i = MT_UNKNOWN; - } goto noreturns; } @@ -11734,18 +11737,9 @@ You should think about modifying the deathmatch starts to take full advantage of return; } - // find which type to spawn - for (i = 0; i < NUMMOBJTYPES; i++) - if (mthing->type == mobjinfo[i].doomednum) - break; - - if (i == NUMMOBJTYPES) - { - if (mthing->type == 3328) // 3D Mode start Thing - return; + i = P_GetMobjtype(mthing->type); + if (i == MT_UNKNOWN) CONS_Alert(CONS_WARNING, M_GetText("Unknown thing type %d placed at (%d, %d)\n"), mthing->type, mthing->x, mthing->y); - i = MT_UNKNOWN; - } if (metalrecording) // Metal Sonic can't use these things. if (mobjinfo[i].flags & (MF_ENEMY|MF_BOSS) || i == MT_TOKEN || i == MT_STARPOST) From d6a86c37b2c0ecd9e3256ae7c57fa0043302d44d Mon Sep 17 00:00:00 2001 From: Nev3r Date: Mon, 23 Dec 2019 16:36:26 +0100 Subject: [PATCH 146/195] P_PrepareRawThings() is now where it was supposed to be at; moved save and flat & texture caching related functions to the end of P_LoadMapData(). --- src/p_setup.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index 6e6c1a72b..7ac713044 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -485,6 +485,7 @@ static inline void P_LoadRawSubsectors(void *data) size_t numlevelflats; levelflat_t *levelflats; +levelflat_t *foundflats; //SoM: Other files want this info. size_t P_PrecacheLevelFlats(void) @@ -648,7 +649,6 @@ static void P_LoadRawSectors(UINT8 *data) { mapsector_t *ms = (mapsector_t *)data; sector_t *ss = sectors; - levelflat_t *foundflats; size_t i; // Allocate a big chunk of memory as big as our MAXLEVELFLATS limit. @@ -725,16 +725,6 @@ static void P_LoadRawSectors(UINT8 *data) ss->lineoutLength = -1.0l; #endif // ----- end special tricks ----- } - - // set the sky flat num - skyflatnum = P_AddLevelFlat(SKYFLATNAME, foundflats); - - // copy table for global usage - levelflats = M_Memcpy(Z_Calloc(numlevelflats * sizeof (*levelflats), PU_LEVEL, NULL), foundflats, numlevelflats * sizeof (levelflat_t)); - free(foundflats); - - // search for animated flats and set up - P_SetupLevelFlatAnims(); } // @@ -1455,7 +1445,6 @@ static void P_LoadRawSideDefs2(void *data) break; } } - R_ClearTextureNumCache(true); } static boolean LineInBlock(fixed_t cx1, fixed_t cy1, fixed_t cx2, fixed_t cy2, fixed_t bx1, fixed_t by1) @@ -2007,7 +1996,29 @@ static void P_LoadMapData(const virtres_t* virt) P_LoadRawLineDefs(virtlinedefs->data); P_SetupLines(); P_LoadRawSideDefs2(virtsidedefs->data); + P_PrepareRawThings(virtthings->data); } + + R_ClearTextureNumCache(true); + + // set the sky flat num + skyflatnum = P_AddLevelFlat(SKYFLATNAME, foundflats); + + // copy table for global usage + levelflats = M_Memcpy(Z_Calloc(numlevelflats * sizeof (*levelflats), PU_LEVEL, NULL), foundflats, numlevelflats * sizeof (levelflat_t)); + free(foundflats); + + // search for animated flats and set up + P_SetupLevelFlatAnims(); + + // Copy relevant map data for NetArchive purposes. + spawnsectors = Z_Calloc(numsectors * sizeof (*sectors), PU_LEVEL, NULL); + spawnlines = Z_Calloc(numlines * sizeof (*lines), PU_LEVEL, NULL); + spawnsides = Z_Calloc(numsides * sizeof (*sides), PU_LEVEL, NULL); + + memcpy(spawnsectors, sectors, numsectors * sizeof (*sectors)); + memcpy(spawnlines, lines, numlines * sizeof (*lines)); + memcpy(spawnsides, sides, numsides * sizeof (*sides)); } #if 0 @@ -2774,17 +2785,6 @@ boolean P_SetupLevel(boolean skipprecip) P_LoadLineDefs2(); P_GroupLines(); - // Copy relevant map data for NetArchive purposes. - spawnsectors = Z_Calloc(numsectors * sizeof (*sectors), PU_LEVEL, NULL); - spawnlines = Z_Calloc(numlines * sizeof (*lines), PU_LEVEL, NULL); - spawnsides = Z_Calloc(numsides * sizeof (*sides), PU_LEVEL, NULL); - - memcpy(spawnsectors, sectors, numsectors * sizeof (*sectors)); - memcpy(spawnlines, lines, numlines * sizeof (*lines)); - memcpy(spawnsides, sides, numsides * sizeof (*sides)); - - P_PrepareRawThings(vres_Find(virt, "THINGS")->data); - P_MakeMapMD5(virt, &mapmd5); vres_Free(virt); From 9a9f72f59899143f1b0483c7d828b5b260de8151 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Mon, 23 Dec 2019 16:37:44 +0100 Subject: [PATCH 147/195] Don't reload mapthings in P_LoadThingsOnly() as they should no longer be modified past the mapload procedure. --- src/p_setup.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index 7ac713044..f5d4c26e2 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2196,8 +2196,6 @@ void P_LoadThingsOnly(void) // Search through all the thinkers. thinker_t *think; INT32 i, viewid = -1, centerid = -1; // for skyboxes - virtres_t* virt = vres_GetMap(lastloadedmaplumpnum); - virtlump_t* vth = vres_Find(virt, "THINGS"); // check if these are any of the normal viewpoint/centerpoint mobjs in the level or not if (skyboxmo[0] || skyboxmo[1]) @@ -2218,11 +2216,8 @@ void P_LoadThingsOnly(void) P_LevelInitStuff(); - P_PrepareRawThings(vth->data); P_LoadThings(true); - vres_Free(virt); - // restore skybox viewpoint/centerpoint if necessary, set them to defaults if we can't do that skyboxmo[0] = skyboxviewpnts[(viewid >= 0) ? viewid : 0]; skyboxmo[1] = skyboxcenterpnts[(centerid >= 0) ? centerid : 0]; From 6a69aa4ffa7619c4094d922891035831ba5291a3 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Mon, 23 Dec 2019 16:53:45 +0100 Subject: [PATCH 148/195] Separate handling of non-mobj mapthings in P_SpawnMapThing into its own function --- src/p_mobj.c | 120 +++++++++++++++++++++++++-------------------------- 1 file changed, 59 insertions(+), 61 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 112ef67f3..714eef737 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11643,6 +11643,61 @@ static mobjtype_t P_GetMobjtype(UINT16 mthingtype) return MT_UNKNOWN; } +static boolean P_SpawnNonMobjMapThing(mapthing_t *mthing) +{ +#if MAXPLAYERS > 32 + You should think about modifying the deathmatch starts to take full advantage of this! +#endif + if (mthing->type <= MAXPLAYERS) // Player starts + { + // save spots for respawning in network games + if (!metalrecording) + playerstarts[mthing->type - 1] = mthing; + return true; + } + else if (mthing->type == 33) // Match starts + { + if (numdmstarts < MAX_DM_STARTS) + { + deathmatchstarts[numdmstarts] = mthing; + mthing->type = 0; + numdmstarts++; + } + return true; + } + else if (mthing->type == 34) // Red CTF starts + { + if (numredctfstarts < MAXPLAYERS) + { + redctfstarts[numredctfstarts] = mthing; + mthing->type = 0; + numredctfstarts++; + } + return true; + } + else if (mthing->type == 35) // Blue CTF starts + { + if (numbluectfstarts < MAXPLAYERS) + { + bluectfstarts[numbluectfstarts] = mthing; + mthing->type = 0; + numbluectfstarts++; + } + return true; + } + else if (metalrecording && mthing->type == mobjinfo[MT_METALSONIC_RACE].doomednum) + { // If recording, you ARE Metal Sonic. Do not spawn it, do not save normal spawnpoints. + playerstarts[0] = mthing; + return true; + } + else if (mthing->type == 750 // Slope vertex point (formerly chaos spawn) + || (mthing->type >= 600 && mthing->type <= 609) // Special placement patterns + || mthing->type == 1705 || mthing->type == 1713) // Hoops + return true; // These are handled elsewhere. + + return false; +} + // // P_SpawnMapThing // The fields of the mapthing should @@ -11672,70 +11727,13 @@ void P_SpawnMapThing(mapthing_t *mthing) goto noreturns; } - // count deathmatch start positions - if (mthing->type == 33) - { - if (numdmstarts < MAX_DM_STARTS) - { - deathmatchstarts[numdmstarts] = mthing; - mthing->type = 0; - numdmstarts++; - } - return; - } - - else if (mthing->type == 34) // Red CTF Starts - { - if (numredctfstarts < MAXPLAYERS) - { - redctfstarts[numredctfstarts] = mthing; - mthing->type = 0; - numredctfstarts++; - } - return; - } - - else if (mthing->type == 35) // Blue CTF Starts - { - if (numbluectfstarts < MAXPLAYERS) - { - bluectfstarts[numbluectfstarts] = mthing; - mthing->type = 0; - numbluectfstarts++; - } - return; - } - - else if (mthing->type == 750) // Slope vertex point (formerly chaos spawn) + if (P_SpawnNonMobjMapThing(mthing)) return; - else if (mthing->type == mobjinfo[MT_RING].doomednum || mthing->type == mobjinfo[MT_COIN].doomednum + if (mthing->type == mobjinfo[MT_RING].doomednum || mthing->type == mobjinfo[MT_COIN].doomednum || mthing->type == mobjinfo[MT_REDTEAMRING].doomednum || mthing->type == mobjinfo[MT_BLUETEAMRING].doomednum - || mthing->type == mobjinfo[MT_BLUESPHERE].doomednum || mthing->type == mobjinfo[MT_BOMBSPHERE].doomednum - || (mthing->type >= 600 && mthing->type <= 609) // circles and diagonals - || mthing->type == 1705 || mthing->type == 1713) // hoops - { - // Don't spawn hoops, wings, or rings yet! - return; - } - - // check for players specially -#if MAXPLAYERS > 32 -You should think about modifying the deathmatch starts to take full advantage of this! -#endif - if (mthing->type > 0 && mthing->type <= MAXPLAYERS) - { - // save spots for respawning in network games - if (!metalrecording) - playerstarts[mthing->type-1] = mthing; - return; - } - - if (metalrecording && mthing->type == mobjinfo[MT_METALSONIC_RACE].doomednum) - { // If recording, you ARE Metal Sonic. Do not spawn it, do not save normal spawnpoints. - playerstarts[0] = mthing; - return; - } + || mthing->type == mobjinfo[MT_BLUESPHERE].doomednum || mthing->type == mobjinfo[MT_BOMBSPHERE].doomednum) // hoops + return; // These are handled in P_SpawnHoopsAndRings(). i = P_GetMobjtype(mthing->type); if (i == MT_UNKNOWN) From e90eb9a5e73c69c7996c2b258a34f42108f63a51 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Mon, 23 Dec 2019 16:54:26 +0100 Subject: [PATCH 149/195] Move P_GetMobjtype above first use --- src/p_mobj.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 714eef737..f607fdf8a 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11121,6 +11121,19 @@ void P_PrecipitationEffects(void) } } +/** Returns corresponding mobj type from mapthing number. + * \param mthingtype Mapthing number in question. + * \return Mobj type; MT_UNKNOWN if nothing found. + */ +static mobjtype_t P_GetMobjtype(UINT16 mthingtype) +{ + mobjtype_t i; + for (i = 0; i < NUMMOBJTYPES; i++) + if (mthingtype == mobjinfo[i].doomednum) + return i; + return MT_UNKNOWN; +} + // // P_RespawnSpecials // @@ -11630,19 +11643,6 @@ static fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* ss->sector->floorheight) + offset; } -/** Returns corresponding mobj type from mapthing number. - * \param mthingtype Mapthing number in question. - * \return Mobj type; MT_UNKNOWN if nothing found. - */ -static mobjtype_t P_GetMobjtype(UINT16 mthingtype) -{ - mobjtype_t i; - for (i = 0; i < NUMMOBJTYPES; i++) - if (mthingtype == mobjinfo[i].doomednum) - return i; - return MT_UNKNOWN; -} - static boolean P_SpawnNonMobjMapThing(mapthing_t *mthing) { #if MAXPLAYERS > 32 From 8ddd078b20a82e9abe35c177bc997470507d6120 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Mon, 23 Dec 2019 17:28:21 +0100 Subject: [PATCH 150/195] P_MapThingSpawn(): Move early returning/substitution code into their own functions --- src/p_mobj.c | 358 ++++++++++++++++++++++++++++----------------------- 1 file changed, 199 insertions(+), 159 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index f607fdf8a..c2b40a96b 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11698,6 +11698,198 @@ static boolean P_SpawnNonMobjMapThing(mapthing_t *mthing) return false; } +static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i) +{ + switch (i) + { + case MT_RING: + case MT_COIN: + case MT_REDTEAMRING: + case MT_BLUETEAMRING: + case MT_BLUESPHERE: + case MT_BOMBSPHERE: + case MT_NIGHTSSTAR: + case MT_NIGHTSCHIP: + return false; // These are handled in P_SpawnHoopsAndRings(). + case MT_EMERALD1: + case MT_EMERALD2: + case MT_EMERALD3: + case MT_EMERALD4: + case MT_EMERALD5: + case MT_EMERALD6: + case MT_EMERALD7: + if (gametype != GT_COOP) // Don't place emeralds in non-coop modes + return false; + + if (metalrecording) + return false; // Metal Sonic isn't for collecting emeralds. + + if (emeralds & mobjinfo[i].speed) // You already have this emerald! + return false; + + break; + case MT_EMERHUNT: + // Emerald Hunt is Coop only. + if (gametype != GT_COOP) + return false; + + if (numhuntemeralds < MAXHUNTEMERALDS) + huntemeralds[numhuntemeralds++] = mthing; + return false; + case MT_EMERALDSPAWN: + if (!cv_powerstones.value) + return false; + + if (!(gametype == GT_MATCH || gametype == GT_CTF)) + return false; + + runemeraldmanager = true; + break; + case MT_ROSY: + if (!(gametype == GT_COOP || (mthing->options & MTF_EXTRA))) + return false; // she doesn't hang out here + + if (!mariomode && !(netgame || multiplayer) && players[consoleplayer].skin == 3) + return false; // no doubles + + break; + case MT_TOKEN: + if (gametype != GT_COOP && gametype != GT_COMPETITION) + return false; // Gametype's not right + + if (tokenbits == 30) + return false; // Too many tokens + + if (tokenlist & (1 << tokenbits++)) + return false; // You already got this token + + break; + case MT_EMBLEM: + if (netgame || multiplayer) + return false; // Single player + + if (modifiedgame && !savemoddata) + return false; // No cheating!! + + break; + default: + break; + } + + if (metalrecording) // Metal Sonic can't use these things. + if (mobjinfo[i].flags & (MF_ENEMY|MF_BOSS) || i == MT_TOKEN || i == MT_STARPOST) + return false; + + if (!G_PlatformGametype()) + { + if ((mobjinfo[i].flags & MF_ENEMY) || (mobjinfo[i].flags & MF_BOSS)) + return false; // No enemies in ringslinger modes + + if (i == MT_SIGN || i == MT_STARPOST) + return false; // Don't spawn exit signs or starposts in wrong game modes + } + + if (!G_RingSlingerGametype() || !cv_specialrings.value) + if (P_WeaponOrPanel(i)) + return false; // Don't place weapons/panels in non-ringslinger modes + + if (gametype != GT_CTF) // CTF specific things + { + if (i == MT_BLUEFLAG || i == MT_REDFLAG) + return false; // No flags in non-CTF modes! + } + else + { + if ((i == MT_BLUEFLAG && blueflag) || (i == MT_REDFLAG && redflag)) + { + CONS_Alert(CONS_ERROR, M_GetText("Only one flag per team allowed in CTF!\n")); + return false; + } + } + + if (modeattacking) // Record Attack special stuff + { + // Don't spawn starposts that wouldn't be usable + if (i == MT_STARPOST) + return false; + } + + if (ultimatemode) + { + if (i == MT_PITY_BOX || i == MT_ELEMENTAL_BOX || i == MT_ATTRACT_BOX + || i == MT_FORCE_BOX || i == MT_ARMAGEDDON_BOX || i == MT_WHIRLWIND_BOX + || i == MT_FLAMEAURA_BOX || i == MT_BUBBLEWRAP_BOX || i == MT_THUNDERCOIN_BOX + || i == MT_RING_BOX || i == MT_STARPOST) + return false; // No rings or shields in Ultimate mode + + // Don't include the gold repeating boxes here please. + // They're likely facets of the level's design and therefore required to progress. + } + + return true; +} + +static mobjtype_t P_GetMobjtypeSubstitute(mapthing_t *mthing, mobjtype_t i) +{ + // Altering monitor spawns via cvars + // If MF_GRENADEBOUNCE is set in the monitor's info, + // skip this step. (Used for gold monitors) + // Yeah, this is a dirty hack. + if ((mobjinfo[i].flags & (MF_MONITOR|MF_GRENADEBOUNCE)) == MF_MONITOR) + { + if (gametype == GT_COMPETITION || gametype == GT_RACE) + { + // Set powerup boxes to user settings for competition. + switch (cv_competitionboxes.value) + { + case 1: // Mystery + return MT_MYSTERY_BOX; + case 2: // Teleport + return MT_MIXUP_BOX; + case 3: // None + return MT_NULL; // Don't spawn! + default: + return i; + } + } + // Set powerup boxes to user settings for other netplay modes + else if (gametype != GT_COOP) + { + switch (cv_matchboxes.value) + { + case 1: // Mystery + return MT_MYSTERY_BOX; + case 2: // Unchanging + if (i == MT_MYSTERY_BOX) + return MT_NULL; // don't spawn + mthing->options &= ~(MTF_AMBUSH|MTF_OBJECTSPECIAL); // no random respawning! + return i; + case 3: // Don't spawn + return MT_NULL; + default: + return i; + } + } + } + + if (gametype != GT_CTF && (i == MT_RING_BLUEBOX || i == MT_RING_REDBOX)) + return MT_RING_BOX; + + if (modeattacking && i == MT_1UP_BOX) // 1UPs -->> Score TVs + { + // Either or, doesn't matter which. + if (mthing->options & (MTF_AMBUSH | MTF_OBJECTSPECIAL)) + return MT_SCORE10K_BOX; // 10,000 + else + return MT_SCORE1K_BOX; // 1,000 + } + + if (mariomode && i == MT_ROSY) + return MT_TOAD; // don't remove on penalty of death + + return i; +} + // // P_SpawnMapThing // The fields of the mapthing should @@ -11716,176 +11908,24 @@ void P_SpawnMapThing(mapthing_t *mthing) if (mthing->type == 3328) // 3D Mode start Thing return; - // Always spawn in objectplace. - // Skip all returning code. - if (objectplacing) - { - // find which type to spawn - i = P_GetMobjtype(mthing->type); - if (i == MT_UNKNOWN) - CONS_Alert(CONS_WARNING, M_GetText("Unknown thing type %d placed at (%d, %d)\n"), mthing->type, mthing->x, mthing->y); - goto noreturns; - } - - if (P_SpawnNonMobjMapThing(mthing)) + if (!objectplacing && P_SpawnNonMobjMapThing(mthing)) return; - if (mthing->type == mobjinfo[MT_RING].doomednum || mthing->type == mobjinfo[MT_COIN].doomednum - || mthing->type == mobjinfo[MT_REDTEAMRING].doomednum || mthing->type == mobjinfo[MT_BLUETEAMRING].doomednum - || mthing->type == mobjinfo[MT_BLUESPHERE].doomednum || mthing->type == mobjinfo[MT_BOMBSPHERE].doomednum) // hoops - return; // These are handled in P_SpawnHoopsAndRings(). - i = P_GetMobjtype(mthing->type); if (i == MT_UNKNOWN) CONS_Alert(CONS_WARNING, M_GetText("Unknown thing type %d placed at (%d, %d)\n"), mthing->type, mthing->x, mthing->y); - if (metalrecording) // Metal Sonic can't use these things. - if (mobjinfo[i].flags & (MF_ENEMY|MF_BOSS) || i == MT_TOKEN || i == MT_STARPOST) + // Skip all returning/substitution code in objectplace. + if (!objectplacing) + { + if (!P_AllowMobjSpawn(mthing, i)) return; - if (i >= MT_EMERALD1 && i <= MT_EMERALD7) // Pickupable Emeralds - { - if (gametype != GT_COOP) // Don't place emeralds in non-coop modes - return; - - if (metalrecording) - return; // Metal Sonic isn't for collecting emeralds. - - if (emeralds & mobjinfo[i].speed) // You already have this emerald! + i = P_GetMobjtypeSubstitute(mthing, i); + if (i == MT_NULL) // Don't spawn mobj return; } - if (i == MT_EMERHUNT) - { - // Emerald Hunt is Coop only. - if (gametype != GT_COOP) - return; - - if (numhuntemeralds < MAXHUNTEMERALDS) - huntemeralds[numhuntemeralds++] = mthing; - return; - } - - if (i == MT_EMERALDSPAWN) - { - if (!cv_powerstones.value) - return; - - if (!(gametype == GT_MATCH || gametype == GT_CTF)) - return; - - runemeraldmanager = true; - } - - if (!G_PlatformGametype()) // No enemies in match or CTF modes - if ((mobjinfo[i].flags & MF_ENEMY) || (mobjinfo[i].flags & MF_BOSS)) - return; - - if (!G_RingSlingerGametype() || !cv_specialrings.value) - if (P_WeaponOrPanel(i)) - return; // Don't place weapons/panels in non-ringslinger modes - - // Altering monitor spawns via cvars - // If MF_GRENADEBOUNCE is set in the monitor's info, - // skip this step. (Used for gold monitors) - // Yeah, this is a dirty hack. - if ((mobjinfo[i].flags & (MF_MONITOR|MF_GRENADEBOUNCE)) == MF_MONITOR) - { - if (gametype == GT_COMPETITION || gametype == GT_RACE) - { - // Set powerup boxes to user settings for competition. - if (cv_competitionboxes.value == 1) // Mystery - i = MT_MYSTERY_BOX; - else if (cv_competitionboxes.value == 2) // Teleport - i = MT_MIXUP_BOX; - else if (cv_competitionboxes.value == 3) // None - return; // Don't spawn! - // default case: normal - } - // Set powerup boxes to user settings for other netplay modes - else if (gametype != GT_COOP) - { - if (cv_matchboxes.value == 1) // Mystery - i = MT_MYSTERY_BOX; - else if (cv_matchboxes.value == 2) // Unchanging - { - if (i == MT_MYSTERY_BOX) - return; // don't spawn - mthing->options &= ~(MTF_AMBUSH|MTF_OBJECTSPECIAL); // no random respawning! - } - else if (cv_matchboxes.value == 3) // Don't spawn - return; - // default case: normal - } - } - - if (gametype != GT_CTF) // CTF specific things - { - if (i == MT_RING_BLUEBOX || i == MT_RING_REDBOX) - i = MT_RING_BOX; - else if (i == MT_BLUEFLAG || i == MT_REDFLAG) - return; // No flags in non-CTF modes! - } - else - { - if ((i == MT_BLUEFLAG && blueflag) || (i == MT_REDFLAG && redflag)) - { - CONS_Alert(CONS_ERROR, M_GetText("Only one flag per team allowed in CTF!\n")); - return; - } - } - - if (!G_PlatformGametype() && (i == MT_SIGN || i == MT_STARPOST)) - return; // Don't spawn exit signs or starposts in wrong game modes - - if (modeattacking) // Record Attack special stuff - { - // Don't spawn starposts that wouldn't be usable - if (i == MT_STARPOST) - return; - - // 1UPs -->> Score TVs - else if (i == MT_1UP_BOX) // 1UP - { - // Either or, doesn't matter which. - if (mthing->options & (MTF_AMBUSH|MTF_OBJECTSPECIAL)) - i = MT_SCORE10K_BOX; // 10,000 - else - i = MT_SCORE1K_BOX; // 1,000 - } - } - - if (ultimatemode) - { - if (i == MT_PITY_BOX || i == MT_ELEMENTAL_BOX || i == MT_ATTRACT_BOX - || i == MT_FORCE_BOX || i == MT_ARMAGEDDON_BOX || i == MT_WHIRLWIND_BOX - || i == MT_FLAMEAURA_BOX || i == MT_BUBBLEWRAP_BOX || i == MT_THUNDERCOIN_BOX - || i == MT_RING_BOX || i == MT_STARPOST) - return; // No rings or shields in Ultimate mode - - // Don't include the gold repeating boxes here please. - // They're likely facets of the level's design and therefore required to progress. - } - - if (i == MT_ROSY) - { - if (!(gametype == GT_COOP || (mthing->options & MTF_EXTRA))) - return; // she doesn't hang out here - else if (mariomode) - i = MT_TOAD; // don't remove on penalty of death - else if (!(netgame || multiplayer) && players[consoleplayer].skin == 3) - return; // no doubles - } - - if (i == MT_TOKEN && ((gametype != GT_COOP && gametype != GT_COMPETITION) || tokenbits == 30 || tokenlist & (1 << tokenbits++))) - return; // you already got this token, or there are too many, or the gametype's not right - - if (i == MT_EMBLEM && (netgame || multiplayer || (modifiedgame && !savemoddata))) // No cheating!! - return; - - // Objectplace landing point - noreturns: - // spawn it x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; From e382c2e09464dcb4c6bb8d51e9c1b5d362a53f68 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Mon, 23 Dec 2019 18:59:11 +0100 Subject: [PATCH 151/195] P_SpawnMapThing(): Separated the giant post-Lua hook switch-case statement into its own function, and separated some of the larger cases into their own function as well --- src/p_mobj.c | 1539 +++++++++++++++++++++++++------------------------- 1 file changed, 759 insertions(+), 780 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index c2b40a96b..0397451d0 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11890,116 +11890,626 @@ static mobjtype_t P_GetMobjtypeSubstitute(mapthing_t *mthing, mobjtype_t i) return i; } -// -// P_SpawnMapThing -// The fields of the mapthing should -// already be in host byte order. -// -void P_SpawnMapThing(mapthing_t *mthing) +static boolean P_SetupEmblem(mapthing_t *mthing, mobj_t *mobj) { - mobjtype_t i; - mobj_t *mobj; - fixed_t x, y, z; - boolean doangle = true; + INT32 j; + emblem_t* emblem = M_GetLevelEmblems(gamemap); + skincolors_t emcolor; - if (!mthing->type) - return; // Ignore type-0 things as NOPs - - if (mthing->type == 3328) // 3D Mode start Thing - return; - - if (!objectplacing && P_SpawnNonMobjMapThing(mthing)) - return; - - i = P_GetMobjtype(mthing->type); - if (i == MT_UNKNOWN) - CONS_Alert(CONS_WARNING, M_GetText("Unknown thing type %d placed at (%d, %d)\n"), mthing->type, mthing->x, mthing->y); - - // Skip all returning/substitution code in objectplace. - if (!objectplacing) + while (emblem) { - if (!P_AllowMobjSpawn(mthing, i)) - return; - - i = P_GetMobjtypeSubstitute(mthing, i); - if (i == MT_NULL) // Don't spawn mobj - return; - } - - // spawn it - x = mthing->x << FRACBITS; - y = mthing->y << FRACBITS; - z = P_GetMobjSpawnHeight(i, mthing, x, y); - - mobj = P_SpawnMobj(x, y, z, i); - mobj->spawnpoint = mthing; - -#ifdef HAVE_BLUA - if (LUAh_MapThingSpawn(mobj, mthing)) - { - if (P_MobjWasRemoved(mobj)) - return; - } - else if (P_MobjWasRemoved(mobj)) - return; - else -#endif - switch(mobj->type) - { - case MT_EMBLEM: - { - INT32 j; - emblem_t *emblem = M_GetLevelEmblems(gamemap); - skincolors_t emcolor; - - while (emblem) - { - if ((emblem->type == ET_GLOBAL || emblem->type == ET_SKIN) && emblem->tag == mthing->angle) - break; - - emblem = M_GetLevelEmblems(-1); - } - - if (!emblem) - { - CONS_Debug(DBG_GAMELOGIC, "No map emblem for map %d with tag %d found!\n", gamemap, mthing->angle); + if ((emblem->type == ET_GLOBAL || emblem->type == ET_SKIN) && emblem->tag == mthing->angle) break; - } - j = emblem - emblemlocations; + emblem = M_GetLevelEmblems(-1); + } - I_Assert(emblemlocations[j].sprite >= 'A' && emblemlocations[j].sprite <= 'Z'); - P_SetMobjState(mobj, mobj->info->spawnstate + (emblemlocations[j].sprite - 'A')); + if (!emblem) + { + CONS_Debug(DBG_GAMELOGIC, "No map emblem for map %d with tag %d found!\n", gamemap, mthing->angle); + return false; + } - mobj->health = j + 1; - emcolor = M_GetEmblemColor(&emblemlocations[j]); // workaround for compiler complaint about bad function casting - mobj->color = (UINT8)emcolor; + j = emblem - emblemlocations; - if (emblemlocations[j].collected - || (emblemlocations[j].type == ET_SKIN && emblemlocations[j].var != players[0].skin)) + I_Assert(emblemlocations[j].sprite >= 'A' && emblemlocations[j].sprite <= 'Z'); + P_SetMobjState(mobj, mobj->info->spawnstate + (emblemlocations[j].sprite - 'A')); + + mobj->health = j + 1; + emcolor = M_GetEmblemColor(&emblemlocations[j]); // workaround for compiler complaint about bad function casting + mobj->color = (UINT8)emcolor; + + if (emblemlocations[j].collected + || (emblemlocations[j].type == ET_SKIN && emblemlocations[j].var != players[0].skin)) + { + P_UnsetThingPosition(mobj); + mobj->flags |= MF_NOCLIP; + mobj->flags &= ~MF_SPECIAL; + mobj->flags |= MF_NOBLOCKMAP; + mobj->frame |= (tr_trans50 << FF_TRANSSHIFT); + P_SetThingPosition(mobj); + } + else + { + mobj->frame &= ~FF_TRANSMASK; + + if (emblemlocations[j].type == ET_GLOBAL) { - P_UnsetThingPosition(mobj); - mobj->flags |= MF_NOCLIP; - mobj->flags &= ~MF_SPECIAL; - mobj->flags |= MF_NOBLOCKMAP; - mobj->frame |= (tr_trans50 << FF_TRANSSHIFT); - P_SetThingPosition(mobj); + mobj->reactiontime = emblemlocations[j].var; + if (emblemlocations[j].var & GE_NIGHTSITEM) + { + mobj->flags |= MF_NIGHTSITEM; + mobj->flags &= ~MF_SPECIAL; + mobj->flags2 |= MF2_DONTDRAW; + } + } + } + return true; +} + +static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) +{ + fixed_t mlength, mmaxlength, mlengthset, mspeed, mphase, myaw, mpitch, mminlength, mnumspokes, mpinch, mroll, mnumnospokes, mwidth, mwidthset, mmin, msound, radiusfactor, widthfactor; + angle_t mspokeangle; + mobjtype_t chainlink, macetype, firsttype, linktype; + boolean mdosound, mdocenter, mchainlike = false; + mobj_t *spawnee = NULL, *hprev = mobj; + mobjflag_t mflagsapply; + mobjflag2_t mflags2apply; + mobjeflag_t meflagsapply; + INT32 line; + const size_t mthingi = (size_t)(mthing - mapthings); + + // Find the corresponding linedef special, using angle as tag + // P_FindSpecialLineFromTag works here now =D + line = P_FindSpecialLineFromTag(9, mthing->angle, -1); + + if (line == -1) + { + CONS_Debug(DBG_GAMELOGIC, "Mace chain (mapthing #%s) needs to be tagged to a #9 parameter line (trying to find tag %d).\n", sizeu1(mthingi), mthing->angle); + return false; + } + /* + mapthing - + MTF_AMBUSH : + MT_SPRINGBALLPOINT - upgrade from yellow to red spring + anything else - bigger mace/chain theory + MTF_OBJECTSPECIAL - force silent + MTF_GRAVFLIP - flips objects, doesn't affect chain arrangements + Parameter value : number of "spokes" + + linedef - + ML_NOCLIMB : + MT_CHAINPOINT/MT_CHAINMACEPOINT with ML_EFFECT1 applied - Direction not controllable + anything else - no functionality + ML_EFFECT1 : Swings instead of spins + ML_EFFECT2 : Linktype is replaced with macetype for all spokes not ending in chains (inverted for MT_FIREBARPOINT) + ML_EFFECT3 : Spawn a bonus linktype at the hinge point + ML_EFFECT4 : Don't clip inside the ground + ML_EFFECT5 : Don't stop thinking when too far away + */ + mlength = abs(lines[line].dx >> FRACBITS); + mspeed = abs(lines[line].dy >> (FRACBITS - 4)); + mphase = (sides[lines[line].sidenum[0]].textureoffset >> FRACBITS) % 360; + if ((mminlength = -sides[lines[line].sidenum[0]].rowoffset >> FRACBITS) < 0) + mminlength = 0; + else if (mminlength > mlength - 1) + mminlength = mlength - 1; + mpitch = (lines[line].frontsector->floorheight >> FRACBITS) % 360; + myaw = (lines[line].frontsector->ceilingheight >> FRACBITS) % 360; + + mnumspokes = mthing->extrainfo + 1; + mspokeangle = FixedAngle((360*FRACUNIT)/mnumspokes) >> ANGLETOFINESHIFT; + + if (lines[line].backsector) + { + mpinch = (lines[line].backsector->floorheight >> FRACBITS) % 360; + mroll = (lines[line].backsector->ceilingheight >> FRACBITS) % 360; + mnumnospokes = (sides[lines[line].sidenum[1]].textureoffset >> FRACBITS); + if ((mwidth = sides[lines[line].sidenum[1]].rowoffset >> FRACBITS) < 0) + mwidth = 0; + } + else + mpinch = mroll = mnumnospokes = mwidth = 0; + + CONS_Debug(DBG_GAMELOGIC, "Mace/Chain (mapthing #%s):\n" + "Length is %d (minus %d)\n" + "Speed is %d\n" + "Phase is %d\n" + "Yaw is %d\n" + "Pitch is %d\n" + "No. of spokes is %d (%d antispokes)\n" + "Pinch is %d\n" + "Roll is %d\n" + "Width is %d\n", + sizeu1(mthingi), mlength, mminlength, mspeed, mphase, myaw, mpitch, mnumspokes, mnumnospokes, mpinch, mroll, mwidth); + + if (mnumnospokes > 0 && (mnumnospokes < mnumspokes)) + mnumnospokes = mnumspokes/mnumnospokes; + else + mnumnospokes = ((mobj->type == MT_CHAINMACEPOINT) ? (mnumspokes) : 0); + + mobj->lastlook = mspeed; + mobj->movecount = mobj->lastlook; + mobj->angle = FixedAngle(myaw << FRACBITS); + *doangle = false; + mobj->threshold = (FixedAngle(mpitch << FRACBITS) >> ANGLETOFINESHIFT); + mobj->movefactor = mpinch; + mobj->movedir = 0; + + // Mobjtype selection + switch (mobj->type) + { + case MT_SPRINGBALLPOINT: + macetype = ((mthing->options & MTF_AMBUSH) + ? MT_REDSPRINGBALL + : MT_YELLOWSPRINGBALL); + chainlink = MT_SMALLMACECHAIN; + break; + case MT_FIREBARPOINT: + macetype = ((mthing->options & MTF_AMBUSH) + ? MT_BIGFIREBAR + : MT_SMALLFIREBAR); + chainlink = MT_NULL; + break; + case MT_CUSTOMMACEPOINT: + macetype = (mobjtype_t)sides[lines[line].sidenum[0]].toptexture; + if (lines[line].backsector) + chainlink = (mobjtype_t)sides[lines[line].sidenum[1]].toptexture; + else + chainlink = MT_NULL; + break; + case MT_CHAINPOINT: + if (mthing->options & MTF_AMBUSH) + { + macetype = MT_BIGGRABCHAIN; + chainlink = MT_BIGMACECHAIN; } else { - mobj->frame &= ~FF_TRANSMASK; + macetype = MT_SMALLGRABCHAIN; + chainlink = MT_SMALLMACECHAIN; + } + mchainlike = true; + break; + default: + if (mthing->options & MTF_AMBUSH) + { + macetype = MT_BIGMACE; + chainlink = MT_BIGMACECHAIN; + } + else + { + macetype = MT_SMALLMACE; + chainlink = MT_SMALLMACECHAIN; + } + break; + } - if (emblemlocations[j].type == ET_GLOBAL) + if (!macetype && !chainlink) + return true; + + if (mobj->type == MT_CHAINPOINT) + { + if (!mlength) + return true; + } + else + mlength++; + + firsttype = macetype; + + // Adjustable direction + if (lines[line].flags & ML_NOCLIMB) + mobj->flags |= MF_SLIDEME; + + // Swinging + if (lines[line].flags & ML_EFFECT1) + { + mobj->flags2 |= MF2_STRONGBOX; + mmin = ((mnumnospokes > 1) ? 1 : 0); + } + else + mmin = mnumspokes; + + // If over distance away, don't move UNLESS this flag is applied + if (lines[line].flags & ML_EFFECT5) + mobj->flags2 |= MF2_BOSSNOTRAP; + + // Make the links the same type as the end - repeated below + if ((mobj->type != MT_CHAINPOINT) && (((lines[line].flags & ML_EFFECT2) == ML_EFFECT2) != (mobj->type == MT_FIREBARPOINT))) // exclusive or + { + linktype = macetype; + radiusfactor = 2; // Double the radius. + } + else + radiusfactor = (((linktype = chainlink) == MT_NULL) ? 2 : 1); + + if (!mchainlike) + mchainlike = (firsttype == chainlink); + widthfactor = (mchainlike ? 1 : 2); + + mflagsapply = ((lines[line].flags & ML_EFFECT4) ? 0 : (MF_NOCLIP | MF_NOCLIPHEIGHT)); + mflags2apply = ((mthing->options & MTF_OBJECTFLIP) ? MF2_OBJECTFLIP : 0); + meflagsapply = ((mthing->options & MTF_OBJECTFLIP) ? MFE_VERTICALFLIP : 0); + + msound = (mchainlike ? 0 : (mwidth & 1)); + + // Quick and easy preparatory variable setting + mphase = (FixedAngle(mphase << FRACBITS) >> ANGLETOFINESHIFT); + mroll = (FixedAngle(mroll << FRACBITS) >> ANGLETOFINESHIFT); + +#define makemace(mobjtype, dist, moreflags2) {\ + spawnee = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobjtype);\ + P_SetTarget(&spawnee->tracer, mobj);\ + spawnee->threshold = mphase;\ + spawnee->friction = mroll;\ + spawnee->movefactor = mwidthset;\ + spawnee->movecount = dist;\ + spawnee->angle = myaw;\ + spawnee->flags |= (MF_NOGRAVITY|mflagsapply);\ + spawnee->flags2 |= (mflags2apply|moreflags2);\ + spawnee->eflags |= meflagsapply;\ + P_SetTarget(&hprev->hnext, spawnee);\ + P_SetTarget(&spawnee->hprev, hprev);\ + hprev = spawnee;\ +} + + mdosound = (mspeed && !(mthing->options & MTF_OBJECTSPECIAL)); + mdocenter = (macetype && (lines[line].flags & ML_EFFECT3)); + + // The actual spawning of spokes + while (mnumspokes-- > 0) + { + // Offsets + if (lines[line].flags & ML_EFFECT1) // Swinging + mroll = (mroll - mspokeangle) & FINEMASK; + else // Spinning + mphase = (mphase - mspokeangle) & FINEMASK; + + if (mnumnospokes && !(mnumspokes % mnumnospokes)) // Skipping a "missing" spoke + { + if (mobj->type != MT_CHAINMACEPOINT) + continue; + + linktype = chainlink; + firsttype = ((mthing->options & MTF_AMBUSH) ? MT_BIGGRABCHAIN : MT_SMALLGRABCHAIN); + mmaxlength = 1 + (mlength - 1) * radiusfactor; + radiusfactor = widthfactor = 1; + } + else + { + if (mobj->type == MT_CHAINMACEPOINT) { - mobj->reactiontime = emblemlocations[j].var; - if (emblemlocations[j].var & GE_NIGHTSITEM) + // Make the links the same type as the end - repeated above + if (lines[line].flags & ML_EFFECT2) { - mobj->flags |= MF_NIGHTSITEM; - mobj->flags &= ~MF_SPECIAL; - mobj->flags2 |= MF2_DONTDRAW; + linktype = macetype; + radiusfactor = 2; + } + else + radiusfactor = (((linktype = chainlink) == MT_NULL) ? 2 : 1); + + firsttype = macetype; + widthfactor = 2; + } + + mmaxlength = mlength; + } + + mwidthset = mwidth; + mlengthset = mminlength; + + if (mdocenter) // Innermost link + makemace(linktype, 0, 0); + + // Out from the center... + if (linktype) + { + while ((++mlengthset) < mmaxlength) + makemace(linktype, radiusfactor*mlengthset, 0); + } + else + mlengthset = mmaxlength; + + // Outermost mace/link + if (firsttype) + makemace(firsttype, radiusfactor*mlengthset, MF2_AMBUSH); + + if (!mwidth) + { + if (mdosound && mnumspokes <= mmin) // Can it make a sound? + spawnee->flags2 |= MF2_BOSSNOTRAP; + } + else + { + // Across the bar! + if (!firsttype) + mwidthset = -mwidth; + else if (mwidth > 0) + { + while ((mwidthset -= widthfactor) > -mwidth) + { + makemace(firsttype, radiusfactor*mlengthset, MF2_AMBUSH); + if (mdosound && (mwidthset == msound) && mnumspokes <= mmin) // Can it make a sound? + spawnee->flags2 |= MF2_BOSSNOTRAP; } } + else + { + while ((mwidthset += widthfactor) < -mwidth) + { + makemace(firsttype, radiusfactor*mlengthset, MF2_AMBUSH); + if (mdosound && (mwidthset == msound) && mnumspokes <= mmin) // Can it make a sound? + spawnee->flags2 |= MF2_BOSSNOTRAP; + } + } + mwidth = -mwidth; + + // Outermost mace/link again! + if (firsttype) + makemace(firsttype, radiusfactor*(mlengthset--), MF2_AMBUSH); + + // ...and then back into the center! + if (linktype) + while (mlengthset > mminlength) + makemace(linktype, radiusfactor*(mlengthset--), 0); + + if (mdocenter) // Innermost link + makemace(linktype, 0, 0); } + } +#undef makemace + return true; +} + +static boolean P_SetupParticleGen(mapthing_t *mthing, mobj_t *mobj) +{ + fixed_t radius, speed; + INT32 type, numdivisions, anglespeed, ticcount; + angle_t angledivision; + INT32 line; + const size_t mthingi = (size_t)(mthing - mapthings); + + // Find the corresponding linedef special, using angle as tag + line = P_FindSpecialLineFromTag(15, mthing->angle, -1); + + if (line == -1) + { + CONS_Debug(DBG_GAMELOGIC, "Particle generator (mapthing #%s) needs to be tagged to a #15 parameter line (trying to find tag %d).\n", sizeu1(mthingi), mthing->angle); + return false; + } + + if (sides[lines[line].sidenum[0]].toptexture) + type = sides[lines[line].sidenum[0]].toptexture; // Set as object type in p_setup.c... + else + type = (INT32)MT_PARTICLE; + + if (!lines[line].backsector + || (ticcount = (sides[lines[line].sidenum[1]].textureoffset >> FRACBITS)) < 1) + ticcount = 3; + + numdivisions = (mthing->options >> ZSHIFT); + + if (numdivisions) + { + radius = R_PointToDist2(lines[line].v1->x, lines[line].v1->y, lines[line].v2->x, lines[line].v2->y); + anglespeed = (sides[lines[line].sidenum[0]].rowoffset >> FRACBITS) % 360; + angledivision = 360/numdivisions; + } + else + { + numdivisions = 1; // Simple trick to make A_ParticleSpawn simpler. + radius = 0; + anglespeed = 0; + angledivision = 0; + } + + speed = abs(sides[lines[line].sidenum[0]].textureoffset); + if (mthing->options & MTF_OBJECTFLIP) + speed *= -1; + + CONS_Debug(DBG_GAMELOGIC, "Particle Generator (mapthing #%s):\n" + "Radius is %d\n" + "Speed is %d\n" + "Anglespeed is %d\n" + "Numdivisions is %d\n" + "Angledivision is %d\n" + "Type is %d\n" + "Tic seperation is %d\n", + sizeu1(mthingi), radius, speed, anglespeed, numdivisions, angledivision, type, ticcount); + + mobj->angle = 0; + mobj->movefactor = speed; + mobj->lastlook = numdivisions; + mobj->movedir = angledivision*ANG1; + mobj->movecount = anglespeed*ANG1; + mobj->friction = radius; + mobj->threshold = type; + mobj->reactiontime = ticcount; + mobj->cvmem = line; + mobj->watertop = mobj->waterbottom = 0; + return true; +} + +static boolean P_SetupNiGHTSDrone(mapthing_t* mthing, mobj_t* mobj) +{ + boolean flip = mthing->options & MTF_OBJECTFLIP; + boolean topaligned = (mthing->options & MTF_OBJECTSPECIAL) && !(mthing->options & MTF_EXTRA); + boolean middlealigned = (mthing->options & MTF_EXTRA) && !(mthing->options & MTF_OBJECTSPECIAL); + boolean bottomoffsetted = !(mthing->options & MTF_OBJECTSPECIAL) && !(mthing->options & MTF_EXTRA); + + INT16 timelimit = mthing->angle & 0xFFF; + fixed_t hitboxradius = ((mthing->angle & 0xF000) >> 12)*32*FRACUNIT; + fixed_t hitboxheight = mthing->extrainfo*32*FRACUNIT; + fixed_t oldheight = mobj->height; + fixed_t dronemanoffset, goaloffset, sparkleoffset, droneboxmandiff, dronemangoaldiff; + + if (timelimit > 0) + mobj->health = timelimit; + + if (hitboxradius > 0) + mobj->radius = hitboxradius; + + if (hitboxheight > 0) + mobj->height = hitboxheight; + else + mobj->height = mobjinfo[MT_NIGHTSDRONE].height; + + droneboxmandiff = max(mobj->height - mobjinfo[MT_NIGHTSDRONE_MAN].height, 0); + dronemangoaldiff = max(mobjinfo[MT_NIGHTSDRONE_MAN].height - mobjinfo[MT_NIGHTSDRONE_GOAL].height, 0); + + if (flip && mobj->height != oldheight) + P_TeleportMove(mobj, mobj->x, mobj->y, mobj->z - (mobj->height - oldheight)); + + if (!flip) + { + if (topaligned) // Align droneman to top of hitbox + { + dronemanoffset = droneboxmandiff; + goaloffset = dronemangoaldiff/2 + dronemanoffset; + } + else if (middlealigned) // Align droneman to center of hitbox + { + dronemanoffset = droneboxmandiff/2; + goaloffset = dronemangoaldiff/2 + dronemanoffset; + } + else if (bottomoffsetted) + { + dronemanoffset = 24*FRACUNIT; + goaloffset = dronemangoaldiff + dronemanoffset; + } + else + { + dronemanoffset = 0; + goaloffset = dronemangoaldiff/2 + dronemanoffset; + } + + sparkleoffset = goaloffset - FixedMul(15*FRACUNIT, mobj->scale); + } + else + { + mobj->eflags |= MFE_VERTICALFLIP; + mobj->flags2 |= MF2_OBJECTFLIP; + + if (topaligned) // Align droneman to top of hitbox + { + dronemanoffset = 0; + goaloffset = dronemangoaldiff/2 + dronemanoffset; + } + else if (middlealigned) // Align droneman to center of hitbox + { + dronemanoffset = droneboxmandiff/2; + goaloffset = dronemangoaldiff/2 + dronemanoffset; + } + else if (bottomoffsetted) + { + dronemanoffset = droneboxmandiff - FixedMul(24*FRACUNIT, mobj->scale); + goaloffset = dronemangoaldiff + dronemanoffset; + } + else + { + dronemanoffset = droneboxmandiff; + goaloffset = dronemangoaldiff/2 + dronemanoffset; + } + + sparkleoffset = goaloffset + FixedMul(15*FRACUNIT, mobj->scale); + } + + // spawn visual elements + { + mobj_t* goalpost = P_SpawnMobjFromMobj(mobj, 0, 0, goaloffset, MT_NIGHTSDRONE_GOAL); + mobj_t* sparkle = P_SpawnMobjFromMobj(mobj, 0, 0, sparkleoffset, MT_NIGHTSDRONE_SPARKLING); + mobj_t* droneman = P_SpawnMobjFromMobj(mobj, 0, 0, dronemanoffset, MT_NIGHTSDRONE_MAN); + + P_SetTarget(&mobj->target, goalpost); + P_SetTarget(&goalpost->target, sparkle); + P_SetTarget(&goalpost->tracer, droneman); + + // correct Z position + if (flip) + { + P_TeleportMove(goalpost, goalpost->x, goalpost->y, mobj->z + goaloffset); + P_TeleportMove(sparkle, sparkle->x, sparkle->y, mobj->z + sparkleoffset); + P_TeleportMove(droneman, droneman->x, droneman->y, mobj->z + dronemanoffset); + } + + // Remember position preference for later + mobj->flags &= ~(MF_SLIDEME|MF_GRENADEBOUNCE); + if (topaligned) + mobj->flags |= MF_SLIDEME; + else if (middlealigned) + mobj->flags |= MF_GRENADEBOUNCE; + else if (!bottomoffsetted) + mobj->flags |= MF_SLIDEME|MF_GRENADEBOUNCE; + + // Remember old Z position and flags for correction detection + goalpost->movefactor = mobj->z; + goalpost->friction = mobj->height; + goalpost->threshold = mobj->flags & (MF_SLIDEME|MF_GRENADEBOUNCE); + } + return true; +} + +static boolean P_SetupBooster(mapthing_t* mthing, mobj_t* mobj, boolean strong) +{ + angle_t angle = FixedAngle(mthing->angle << FRACBITS); + fixed_t x1 = FINECOSINE((angle >> ANGLETOFINESHIFT) & FINEMASK); + fixed_t y1 = FINESINE((angle >> ANGLETOFINESHIFT) & FINEMASK); + fixed_t x2 = FINECOSINE(((angle + ANGLE_90) >> ANGLETOFINESHIFT) & FINEMASK); + fixed_t y2 = FINESINE(((angle + ANGLE_90) >> ANGLETOFINESHIFT) & FINEMASK); + statenum_t facestate = strong ? S_REDBOOSTERSEG_FACE : S_YELLOWBOOSTERSEG_FACE; + statenum_t leftstate = strong ? S_REDBOOSTERSEG_LEFT : S_YELLOWBOOSTERSEG_LEFT; + statenum_t rightstate = strong ? S_REDBOOSTERSEG_RIGHT : S_YELLOWBOOSTERSEG_RIGHT; + statenum_t rollerstate = strong ? S_REDBOOSTERROLLER : S_YELLOWBOOSTERROLLER; + + mobj_t *seg = P_SpawnMobjFromMobj(mobj, 26*x1, 26*y1, 0, MT_BOOSTERSEG); + seg->angle = angle - ANGLE_90; + P_SetMobjState(seg, facestate); + seg = P_SpawnMobjFromMobj(mobj, -26*x1, -26*y1, 0, MT_BOOSTERSEG); + seg->angle = angle + ANGLE_90; + P_SetMobjState(seg, facestate); + seg = P_SpawnMobjFromMobj(mobj, 21*x2, 21*y2, 0, MT_BOOSTERSEG); + seg->angle = angle; + P_SetMobjState(seg, leftstate); + seg = P_SpawnMobjFromMobj(mobj, -21*x2, -21*y2, 0, MT_BOOSTERSEG); + seg->angle = angle; + P_SetMobjState(seg, rightstate); + + seg = P_SpawnMobjFromMobj(mobj, 13*(x1 + x2), 13*(y1 + y2), 0, MT_BOOSTERROLLER); + seg->angle = angle; + P_SetMobjState(seg, rollerstate); + seg = P_SpawnMobjFromMobj(mobj, 13*(x1 - x2), 13*(y1 - y2), 0, MT_BOOSTERROLLER); + seg->angle = angle; + P_SetMobjState(seg, rollerstate); + seg = P_SpawnMobjFromMobj(mobj, -13*(x1 + x2), -13*(y1 + y2), 0, MT_BOOSTERROLLER); + seg->angle = angle; + P_SetMobjState(seg, rollerstate); + seg = P_SpawnMobjFromMobj(mobj, -13*(x1 - x2), -13*(y1 - y2), 0, MT_BOOSTERROLLER); + seg->angle = angle; + P_SetMobjState(seg, rollerstate); + + return true; +} + +static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) +{ +#ifdef HAVE_BLUA + boolean override = LUAh_MapThingSpawn(mobj, mthing); + + if (P_MobjWasRemoved(mobj)) + return false; + + if (override) + return true; +#endif + + switch (mobj->type) + { + case MT_EMBLEM: + { + if (!P_SetupEmblem(mthing, mobj)) + return false; break; } case MT_SKYBOX: @@ -12033,7 +12543,7 @@ void P_SpawnMapThing(mapthing_t *mthing) if (mthing->angle) mobj->health = mthing->angle; else - mobj->health = FixedMul(mobj->subsector->sector->ceilingheight - mobj->subsector->sector->floorheight, 3*(FRACUNIT/4))>>FRACBITS; + mobj->health = FixedMul(mobj->subsector->sector->ceilingheight - mobj->subsector->sector->floorheight, 3*(FRACUNIT/4)) >> FRACBITS; break; case MT_METALSONIC_RACE: case MT_METALSONIC_BATTLE: @@ -12048,7 +12558,7 @@ void P_SpawnMapThing(mapthing_t *mthing) break; case MT_BALLOON: if (mthing->angle > 0) - mobj->color = ((mthing->angle-1) % (MAXSKINCOLORS-1))+1; + mobj->color = ((mthing->angle - 1) % (MAXSKINCOLORS - 1)) + 1; break; #define makesoftwarecorona(mo, h) \ corona = P_SpawnMobjFromMobj(mo, 0, 0, h<angle) - mobj->tics = 3*TICRATE + mthing->angle; - else - mobj->tics = 3*TICRATE; + mobj->tics = 3*TICRATE + mthing->angle; break; case MT_FLAMEJET: case MT_VERTICALFLAMEJET: @@ -12120,391 +12627,13 @@ void P_SpawnMapThing(mapthing_t *mthing) case MT_CHAINPOINT: case MT_FIREBARPOINT: case MT_CUSTOMMACEPOINT: - { - fixed_t mlength, mmaxlength, mlengthset, mspeed, mphase, myaw, mpitch, mminlength, mnumspokes, mpinch, mroll, mnumnospokes, mwidth, mwidthset, mmin, msound, radiusfactor, widthfactor; - angle_t mspokeangle; - mobjtype_t chainlink, macetype, firsttype, linktype; - boolean mdosound, mdocenter, mchainlike = false; - mobj_t *spawnee = NULL, *hprev = mobj; - mobjflag_t mflagsapply; - mobjflag2_t mflags2apply; - mobjeflag_t meflagsapply; - INT32 line; - const size_t mthingi = (size_t)(mthing - mapthings); - - // Find the corresponding linedef special, using angle as tag - // P_FindSpecialLineFromTag works here now =D - line = P_FindSpecialLineFromTag(9, mthing->angle, -1); - - if (line == -1) - { - CONS_Debug(DBG_GAMELOGIC, "Mace chain (mapthing #%s) needs to be tagged to a #9 parameter line (trying to find tag %d).\n", sizeu1(mthingi), mthing->angle); - return; - } -/* -mapthing - -MTF_AMBUSH : - MT_SPRINGBALLPOINT - upgrade from yellow to red spring - anything else - bigger mace/chain theory -MTF_OBJECTSPECIAL - force silent -MTF_GRAVFLIP - flips objects, doesn't affect chain arrangements -Parameter value : number of "spokes" - -linedef - -ML_NOCLIMB : - MT_CHAINPOINT/MT_CHAINMACEPOINT with ML_EFFECT1 applied - Direction not controllable - anything else - no functionality -ML_EFFECT1 : Swings instead of spins -ML_EFFECT2 : Linktype is replaced with macetype for all spokes not ending in chains (inverted for MT_FIREBARPOINT) -ML_EFFECT3 : Spawn a bonus linktype at the hinge point -ML_EFFECT4 : Don't clip inside the ground -ML_EFFECT5 : Don't stop thinking when too far away -*/ - mlength = abs(lines[line].dx >> FRACBITS); - mspeed = abs(lines[line].dy >> (FRACBITS - 4)); - mphase = (sides[lines[line].sidenum[0]].textureoffset >> FRACBITS) % 360; - if ((mminlength = -sides[lines[line].sidenum[0]].rowoffset>>FRACBITS) < 0) - mminlength = 0; - else if (mminlength > mlength-1) - mminlength = mlength-1; - mpitch = (lines[line].frontsector->floorheight >> FRACBITS) % 360; - myaw = (lines[line].frontsector->ceilingheight >> FRACBITS) % 360; - - mnumspokes = mthing->extrainfo + 1; - mspokeangle = FixedAngle((360*FRACUNIT)/mnumspokes)>>ANGLETOFINESHIFT; - - if (lines[line].backsector) - { - mpinch = (lines[line].backsector->floorheight >> FRACBITS) % 360; - mroll = (lines[line].backsector->ceilingheight >> FRACBITS) % 360; - mnumnospokes = (sides[lines[line].sidenum[1]].textureoffset >> FRACBITS); - if ((mwidth = sides[lines[line].sidenum[1]].rowoffset >> FRACBITS) < 0) - mwidth = 0; - } - else - mpinch = mroll = mnumnospokes = mwidth = 0; - - CONS_Debug(DBG_GAMELOGIC, "Mace/Chain (mapthing #%s):\n" - "Length is %d (minus %d)\n" - "Speed is %d\n" - "Phase is %d\n" - "Yaw is %d\n" - "Pitch is %d\n" - "No. of spokes is %d (%d antispokes)\n" - "Pinch is %d\n" - "Roll is %d\n" - "Width is %d\n", - sizeu1(mthingi), mlength, mminlength, mspeed, mphase, myaw, mpitch, mnumspokes, mnumnospokes, mpinch, mroll, mwidth); - - if (mnumnospokes > 0 && (mnumnospokes < mnumspokes)) - mnumnospokes = mnumspokes/mnumnospokes; - else - mnumnospokes = ((mobj->type == MT_CHAINMACEPOINT) ? (mnumspokes) : 0); - - mobj->lastlook = mspeed; - mobj->movecount = mobj->lastlook; - mobj->angle = FixedAngle(myaw*FRACUNIT); - doangle = false; - mobj->threshold = (FixedAngle(mpitch*FRACUNIT)>>ANGLETOFINESHIFT); - mobj->movefactor = mpinch; - mobj->movedir = 0; - - // Mobjtype selection - switch(mobj->type) - { - case MT_SPRINGBALLPOINT: - macetype = ((mthing->options & MTF_AMBUSH) - ? MT_REDSPRINGBALL - : MT_YELLOWSPRINGBALL); - chainlink = MT_SMALLMACECHAIN; - break; - case MT_FIREBARPOINT: - macetype = ((mthing->options & MTF_AMBUSH) - ? MT_BIGFIREBAR - : MT_SMALLFIREBAR); - chainlink = MT_NULL; - break; - case MT_CUSTOMMACEPOINT: - macetype = (mobjtype_t)sides[lines[line].sidenum[0]].toptexture; - if (lines[line].backsector) - chainlink = (mobjtype_t)sides[lines[line].sidenum[1]].toptexture; - else - chainlink = MT_NULL; - break; - case MT_CHAINPOINT: - if (mthing->options & MTF_AMBUSH) - { - macetype = MT_BIGGRABCHAIN; - chainlink = MT_BIGMACECHAIN; - } - else - { - macetype = MT_SMALLGRABCHAIN; - chainlink = MT_SMALLMACECHAIN; - } - mchainlike = true; - break; - default: - if (mthing->options & MTF_AMBUSH) - { - macetype = MT_BIGMACE; - chainlink = MT_BIGMACECHAIN; - } - else - { - macetype = MT_SMALLMACE; - chainlink = MT_SMALLMACECHAIN; - } - break; - } - - if (!macetype && !chainlink) - break; - - if (mobj->type == MT_CHAINPOINT) - { - if (!mlength) - break; - } - else - mlength++; - - firsttype = macetype; - - // Adjustable direction - if (lines[line].flags & ML_NOCLIMB) - mobj->flags |= MF_SLIDEME; - - // Swinging - if (lines[line].flags & ML_EFFECT1) - { - mobj->flags2 |= MF2_STRONGBOX; - mmin = ((mnumnospokes > 1) ? 1 : 0); - } - else - mmin = mnumspokes; - - // If over distance away, don't move UNLESS this flag is applied - if (lines[line].flags & ML_EFFECT5) - mobj->flags2 |= MF2_BOSSNOTRAP; - - // Make the links the same type as the end - repeated below - if ((mobj->type != MT_CHAINPOINT) && (((lines[line].flags & ML_EFFECT2) == ML_EFFECT2) != (mobj->type == MT_FIREBARPOINT))) // exclusive or - { - linktype = macetype; - radiusfactor = 2; // Double the radius. - } - else - radiusfactor = (((linktype = chainlink) == MT_NULL) ? 2 : 1); - - if (!mchainlike) - mchainlike = (firsttype == chainlink); - widthfactor = (mchainlike ? 1 : 2); - - mflagsapply = ((lines[line].flags & ML_EFFECT4) ? 0 : (MF_NOCLIP|MF_NOCLIPHEIGHT)); - mflags2apply = ((mthing->options & MTF_OBJECTFLIP) ? MF2_OBJECTFLIP : 0); - meflagsapply = ((mthing->options & MTF_OBJECTFLIP) ? MFE_VERTICALFLIP : 0); - - msound = (mchainlike ? 0 : (mwidth & 1)); - - // Quick and easy preparatory variable setting - mphase = (FixedAngle(mphase*FRACUNIT)>>ANGLETOFINESHIFT); - mroll = (FixedAngle(mroll*FRACUNIT)>>ANGLETOFINESHIFT); - -#define makemace(mobjtype, dist, moreflags2) {\ - spawnee = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobjtype);\ - P_SetTarget(&spawnee->tracer, mobj);\ - spawnee->threshold = mphase;\ - spawnee->friction = mroll;\ - spawnee->movefactor = mwidthset;\ - spawnee->movecount = dist;\ - spawnee->angle = myaw;\ - spawnee->flags |= (MF_NOGRAVITY|mflagsapply);\ - spawnee->flags2 |= (mflags2apply|moreflags2);\ - spawnee->eflags |= meflagsapply;\ - P_SetTarget(&hprev->hnext, spawnee);\ - P_SetTarget(&spawnee->hprev, hprev);\ - hprev = spawnee;\ -} - - mdosound = (mspeed && !(mthing->options & MTF_OBJECTSPECIAL)); - mdocenter = (macetype && (lines[line].flags & ML_EFFECT3)); - - // The actual spawning of spokes - while (mnumspokes-- > 0) - { - // Offsets - if (lines[line].flags & ML_EFFECT1) // Swinging - mroll = (mroll - mspokeangle) & FINEMASK; - else // Spinning - mphase = (mphase - mspokeangle) & FINEMASK; - - if (mnumnospokes && !(mnumspokes % mnumnospokes)) // Skipping a "missing" spoke - { - if (mobj->type != MT_CHAINMACEPOINT) - continue; - - linktype = chainlink; - firsttype = ((mthing->options & MTF_AMBUSH) ? MT_BIGGRABCHAIN : MT_SMALLGRABCHAIN); - mmaxlength = 1 + (mlength - 1)*radiusfactor; - radiusfactor = widthfactor = 1; - } - else - { - if (mobj->type == MT_CHAINMACEPOINT) - { - // Make the links the same type as the end - repeated above - if (lines[line].flags & ML_EFFECT2) - { - linktype = macetype; - radiusfactor = 2; - } - else - radiusfactor = (((linktype = chainlink) == MT_NULL) ? 2 : 1); - - firsttype = macetype; - widthfactor = 2; - } - - mmaxlength = mlength; - } - - mwidthset = mwidth; - mlengthset = mminlength; - - if (mdocenter) // Innermost link - makemace(linktype, 0, 0); - - // Out from the center... - if (linktype) - { - while ((++mlengthset) < mmaxlength) - makemace(linktype, radiusfactor*mlengthset, 0); - } - else - mlengthset = mmaxlength; - - // Outermost mace/link - if (firsttype) - makemace(firsttype, radiusfactor*mlengthset, MF2_AMBUSH); - - if (!mwidth) - { - if (mdosound && mnumspokes <= mmin) // Can it make a sound? - spawnee->flags2 |= MF2_BOSSNOTRAP; - } - else - { - // Across the bar! - if (!firsttype) - mwidthset = -mwidth; - else if (mwidth > 0) - { - while ((mwidthset -= widthfactor) > -mwidth) - { - makemace(firsttype, radiusfactor*mlengthset, MF2_AMBUSH); - if (mdosound && (mwidthset == msound) && mnumspokes <= mmin) // Can it make a sound? - spawnee->flags2 |= MF2_BOSSNOTRAP; - } - } - else - { - while ((mwidthset += widthfactor) < -mwidth) - { - makemace(firsttype, radiusfactor*mlengthset, MF2_AMBUSH); - if (mdosound && (mwidthset == msound) && mnumspokes <= mmin) // Can it make a sound? - spawnee->flags2 |= MF2_BOSSNOTRAP; - } - } - mwidth = -mwidth; - - // Outermost mace/link again! - if (firsttype) - makemace(firsttype, radiusfactor*(mlengthset--), MF2_AMBUSH); - - // ...and then back into the center! - if (linktype) - while (mlengthset > mminlength) - makemace(linktype, radiusfactor*(mlengthset--), 0); - - if (mdocenter) // Innermost link - makemace(linktype, 0, 0); - } - } - -#undef makemace - + if (!P_SetupMace(mthing, mobj, doangle)) + return false; break; - } case MT_PARTICLEGEN: - { - fixed_t radius, speed; - INT32 type, numdivisions, anglespeed, ticcount; - angle_t angledivision; - INT32 line; - const size_t mthingi = (size_t)(mthing - mapthings); - - // Find the corresponding linedef special, using angle as tag - line = P_FindSpecialLineFromTag(15, mthing->angle, -1); - - if (line == -1) - { - CONS_Debug(DBG_GAMELOGIC, "Particle generator (mapthing #%s) needs to be tagged to a #15 parameter line (trying to find tag %d).\n", sizeu1(mthingi), mthing->angle); - return; - } - - if (sides[lines[line].sidenum[0]].toptexture) - type = sides[lines[line].sidenum[0]].toptexture; // Set as object type in p_setup.c... - else - type = (INT32)MT_PARTICLE; - - if (!lines[line].backsector - || (ticcount = (sides[lines[line].sidenum[1]].textureoffset >> FRACBITS)) < 1) - ticcount = 3; - - numdivisions = (mthing->options >> ZSHIFT); - - if (numdivisions) - { - radius = R_PointToDist2(lines[line].v1->x, lines[line].v1->y, lines[line].v2->x, lines[line].v2->y); - anglespeed = (sides[lines[line].sidenum[0]].rowoffset >> FRACBITS) % 360; - angledivision = 360/numdivisions; - } - else - { - numdivisions = 1; // Simple trick to make A_ParticleSpawn simpler. - radius = 0; - anglespeed = 0; - angledivision = 0; - } - - speed = abs(sides[lines[line].sidenum[0]].textureoffset); - if (mthing->options & MTF_OBJECTFLIP) - speed *= -1; - - CONS_Debug(DBG_GAMELOGIC, "Particle Generator (mapthing #%s):\n" - "Radius is %d\n" - "Speed is %d\n" - "Anglespeed is %d\n" - "Numdivisions is %d\n" - "Angledivision is %d\n" - "Type is %d\n" - "Tic seperation is %d\n", - sizeu1(mthingi), radius, speed, anglespeed, numdivisions, angledivision, type, ticcount); - - mobj->angle = 0; - mobj->movefactor = speed; - mobj->lastlook = numdivisions; - mobj->movedir = angledivision*ANG1; - mobj->movecount = anglespeed*ANG1; - mobj->friction = radius; - mobj->threshold = type; - mobj->reactiontime = ticcount; - mobj->cvmem = line; - mobj->watertop = mobj->waterbottom = 0; - + if (!P_SetupParticleGen(mthing, mobj)) + return false; break; - } case MT_ROCKSPAWNER: mobj->threshold = mthing->angle; mobj->movecount = mthing->extrainfo; @@ -12519,7 +12648,7 @@ ML_EFFECT5 : Don't stop thinking when too far away // Lower 4 bits specify the angle of // the bumper in 30 degree increments. mobj->threshold = (mthing->options & 15) % 12; // It loops over, etc - P_SetMobjState(mobj, mobj->info->spawnstate+mobj->threshold); + P_SetMobjState(mobj, mobj->info->spawnstate + mobj->threshold); break; case MT_EGGCAPSULE: if (mthing->angle <= 0) @@ -12536,122 +12665,8 @@ ML_EFFECT5 : Don't stop thinking when too far away mobj->health = mthing->extrainfo; break; case MT_NIGHTSDRONE: - { - boolean flip = mthing->options & MTF_OBJECTFLIP; - boolean topaligned = (mthing->options & MTF_OBJECTSPECIAL) && !(mthing->options & MTF_EXTRA); - boolean middlealigned = (mthing->options & MTF_EXTRA) && !(mthing->options & MTF_OBJECTSPECIAL); - boolean bottomoffsetted = !(mthing->options & MTF_OBJECTSPECIAL) && !(mthing->options & MTF_EXTRA); - - INT16 timelimit = mthing->angle & 0xFFF; - fixed_t hitboxradius = ((mthing->angle & 0xF000) >> 12) * 32 * FRACUNIT; - fixed_t hitboxheight = mthing->extrainfo * 32 * FRACUNIT; - fixed_t oldheight = mobj->height; - fixed_t dronemanoffset, goaloffset, sparkleoffset, droneboxmandiff, dronemangoaldiff; - - if (timelimit > 0) - mobj->health = timelimit; - - if (hitboxradius > 0) - mobj->radius = hitboxradius; - - if (hitboxheight > 0) - mobj->height = hitboxheight; - else - mobj->height = mobjinfo[MT_NIGHTSDRONE].height; - - droneboxmandiff = max(mobj->height - mobjinfo[MT_NIGHTSDRONE_MAN].height, 0); - dronemangoaldiff = max(mobjinfo[MT_NIGHTSDRONE_MAN].height - mobjinfo[MT_NIGHTSDRONE_GOAL].height, 0); - - if (flip && mobj->height != oldheight) - P_TeleportMove(mobj, mobj->x, mobj->y, mobj->z - (mobj->height - oldheight)); - - if (!flip) - { - if (topaligned) // Align droneman to top of hitbox - { - dronemanoffset = droneboxmandiff; - goaloffset = dronemangoaldiff / 2 + dronemanoffset; - } - else if (middlealigned) // Align droneman to center of hitbox - { - dronemanoffset = droneboxmandiff / 2; - goaloffset = dronemangoaldiff / 2 + dronemanoffset; - } - else if (bottomoffsetted) - { - dronemanoffset = 24*FRACUNIT; - goaloffset = dronemangoaldiff + dronemanoffset; - } - else - { - dronemanoffset = 0; - goaloffset = dronemangoaldiff / 2 + dronemanoffset; - } - - sparkleoffset = goaloffset - FixedMul(15*FRACUNIT, mobj->scale); - } - else - { - mobj->eflags |= MFE_VERTICALFLIP; - mobj->flags2 |= MF2_OBJECTFLIP; - - if (topaligned) // Align droneman to top of hitbox - { - dronemanoffset = 0; - goaloffset = dronemangoaldiff / 2 + dronemanoffset; - } - else if (middlealigned) // Align droneman to center of hitbox - { - dronemanoffset = droneboxmandiff / 2; - goaloffset = dronemangoaldiff / 2 + dronemanoffset; - } - else if (bottomoffsetted) - { - dronemanoffset = droneboxmandiff - FixedMul(24*FRACUNIT, mobj->scale); - goaloffset = dronemangoaldiff + dronemanoffset; - } - else - { - dronemanoffset = droneboxmandiff; - goaloffset = dronemangoaldiff / 2 + dronemanoffset; - } - - sparkleoffset = goaloffset + FixedMul(15*FRACUNIT, mobj->scale); - } - - // spawn visual elements - { - mobj_t *goalpost = P_SpawnMobjFromMobj(mobj, 0, 0, goaloffset, MT_NIGHTSDRONE_GOAL); - mobj_t *sparkle = P_SpawnMobjFromMobj(mobj, 0, 0, sparkleoffset, MT_NIGHTSDRONE_SPARKLING); - mobj_t *droneman = P_SpawnMobjFromMobj(mobj, 0, 0, dronemanoffset, MT_NIGHTSDRONE_MAN); - - P_SetTarget(&mobj->target, goalpost); - P_SetTarget(&goalpost->target, sparkle); - P_SetTarget(&goalpost->tracer, droneman); - - // correct Z position - if (flip) - { - P_TeleportMove(goalpost, goalpost->x, goalpost->y, mobj->z + goaloffset); - P_TeleportMove(sparkle, sparkle->x, sparkle->y, mobj->z + sparkleoffset); - P_TeleportMove(droneman, droneman->x, droneman->y, mobj->z + dronemanoffset); - } - - // Remember position preference for later - mobj->flags &= ~(MF_SLIDEME | MF_GRENADEBOUNCE); - if (topaligned) - mobj->flags |= MF_SLIDEME; - else if (middlealigned) - mobj->flags |= MF_GRENADEBOUNCE; - else if (!bottomoffsetted) - mobj->flags |= MF_SLIDEME | MF_GRENADEBOUNCE; - - // Remember old Z position and flags for correction detection - goalpost->movefactor = mobj->z; - goalpost->friction = mobj->height; - goalpost->threshold = mobj->flags & (MF_SLIDEME | MF_GRENADEBOUNCE); - } - } + if (!P_SetupNiGHTSDrone(mthing, mobj)) + return false; break; case MT_HIVEELEMENTAL: if (mthing->extrainfo) @@ -12662,7 +12677,7 @@ ML_EFFECT5 : Don't stop thinking when too far away case MT_GLAREGOYLEDOWN: case MT_GLAREGOYLELONG: if (mthing->angle >= 360) - mobj->tics += 7*(mthing->angle / 360) + 1; // starting delay + mobj->tics += 7*(mthing->angle/360) + 1; // starting delay break; case MT_DSZSTALAGMITE: case MT_DSZ2STALAGMITE: @@ -12673,39 +12688,39 @@ ML_EFFECT5 : Don't stop thinking when too far away } break; case MT_THZTREE: - { // Spawn the branches - angle_t mobjangle = FixedAngle((mthing->angle % 113)<angle = mobjangle + ANGLE_22h; - P_SpawnMobjFromMobj(mobj, 0, 1*FRACUNIT, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_157h; - P_SpawnMobjFromMobj(mobj, -1*FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_270; - } - break; + { // Spawn the branches + angle_t mobjangle = FixedAngle((mthing->angle % 113) << FRACBITS); + P_SpawnMobjFromMobj(mobj, FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_22h; + P_SpawnMobjFromMobj(mobj, 0, FRACUNIT, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_157h; + P_SpawnMobjFromMobj(mobj, -FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_270; + } + break; case MT_CEZPOLE1: case MT_CEZPOLE2: - { // Spawn the banner - angle_t mobjangle = FixedAngle(mthing->angle<type == MT_CEZPOLE1) ? MT_CEZBANNER1 : MT_CEZBANNER2))->angle = mobjangle + ANGLE_90; - } - break; + { // Spawn the banner + angle_t mobjangle = FixedAngle(mthing->angle << FRACBITS); + P_SpawnMobjFromMobj(mobj, + P_ReturnThrustX(mobj, mobjangle, 4 << FRACBITS), + P_ReturnThrustY(mobj, mobjangle, 4 << FRACBITS), + 0, ((mobj->type == MT_CEZPOLE1) ? MT_CEZBANNER1 : MT_CEZBANNER2))->angle = mobjangle + ANGLE_90; + } + break; case MT_HHZTREE_TOP: - { // Spawn the branches - angle_t mobjangle = FixedAngle(mthing->angle<angle << FRACBITS) & (ANGLE_90 - 1); + mobj_t* leaf; #define doleaf(x, y) \ leaf = P_SpawnMobjFromMobj(mobj, x, y, 0, MT_HHZTREE_PART);\ leaf->angle = mobjangle;\ P_SetMobjState(leaf, leaf->info->seestate);\ mobjangle += ANGLE_90 - doleaf(1*FRACUNIT, 0); - doleaf(0, 1*FRACUNIT); - doleaf(-1*FRACUNIT, 0); - doleaf(0, -1*FRACUNIT); + doleaf(FRACUNIT, 0); + doleaf(0, FRACUNIT); + doleaf(-FRACUNIT, 0); + doleaf(0, -FRACUNIT); #undef doleaf - } - break; + } + break; case MT_SMASHINGSPIKEBALL: if (mthing->angle > 0) mobj->tics += mthing->angle; @@ -12736,94 +12751,27 @@ ML_EFFECT5 : Don't stop thinking when too far away angle_t fa = (angle >> ANGLETOFINESHIFT) & FINEMASK; fixed_t xoffs = FINECOSINE(fa); fixed_t yoffs = FINESINE(fa); - mobj_t *leaf = P_SpawnMobjFromMobj(mobj, xoffs, yoffs, 0, MT_BIGFERNLEAF); + mobj_t* leaf = P_SpawnMobjFromMobj(mobj, xoffs, yoffs, 0, MT_BIGFERNLEAF); leaf->angle = angle; angle += ANGLE_45; } break; } case MT_REDBOOSTER: - { - angle_t angle = FixedAngle(mthing->angle << FRACBITS); - fixed_t x1 = FINECOSINE((angle >> ANGLETOFINESHIFT) & FINEMASK); - fixed_t y1 = FINESINE((angle >> ANGLETOFINESHIFT) & FINEMASK); - fixed_t x2 = FINECOSINE(((angle+ANGLE_90) >> ANGLETOFINESHIFT) & FINEMASK); - fixed_t y2 = FINESINE(((angle+ANGLE_90) >> ANGLETOFINESHIFT) & FINEMASK); - - mobj_t *seg = P_SpawnMobjFromMobj(mobj, 26*x1, 26*y1, 0, MT_BOOSTERSEG); - seg->angle = angle-ANGLE_90; - P_SetMobjState(seg, S_REDBOOSTERSEG_FACE); - seg = P_SpawnMobjFromMobj(mobj, -26*x1, -26*y1, 0, MT_BOOSTERSEG); - seg->angle = angle+ANGLE_90; - P_SetMobjState(seg, S_REDBOOSTERSEG_FACE); - seg = P_SpawnMobjFromMobj(mobj, 21*x2, 21*y2, 0, MT_BOOSTERSEG); - seg->angle = angle; - P_SetMobjState(seg, S_REDBOOSTERSEG_LEFT); - seg = P_SpawnMobjFromMobj(mobj, -21*x2, -21*y2, 0, MT_BOOSTERSEG); - seg->angle = angle; - P_SetMobjState(seg, S_REDBOOSTERSEG_RIGHT); - - seg = P_SpawnMobjFromMobj(mobj, 13*(x1+x2), 13*(y1+y2), 0, MT_BOOSTERROLLER); - seg->angle = angle; - P_SetMobjState(seg, S_REDBOOSTERROLLER); - seg = P_SpawnMobjFromMobj(mobj, 13*(x1-x2), 13*(y1-y2), 0, MT_BOOSTERROLLER); - seg->angle = angle; - P_SetMobjState(seg, S_REDBOOSTERROLLER); - seg = P_SpawnMobjFromMobj(mobj, -13*(x1+x2), -13*(y1+y2), 0, MT_BOOSTERROLLER); - seg->angle = angle; - P_SetMobjState(seg, S_REDBOOSTERROLLER); - seg = P_SpawnMobjFromMobj(mobj, -13*(x1-x2), -13*(y1-y2), 0, MT_BOOSTERROLLER); - seg->angle = angle; - P_SetMobjState(seg, S_REDBOOSTERROLLER); - break; - } case MT_YELLOWBOOSTER: - { - angle_t angle = FixedAngle(mthing->angle << FRACBITS); - fixed_t x1 = FINECOSINE((angle >> ANGLETOFINESHIFT) & FINEMASK); - fixed_t y1 = FINESINE((angle >> ANGLETOFINESHIFT) & FINEMASK); - fixed_t x2 = FINECOSINE(((angle+ANGLE_90) >> ANGLETOFINESHIFT) & FINEMASK); - fixed_t y2 = FINESINE(((angle+ANGLE_90) >> ANGLETOFINESHIFT) & FINEMASK); - - mobj_t *seg = P_SpawnMobjFromMobj(mobj, 26*x1, 26*y1, 0, MT_BOOSTERSEG); - seg->angle = angle-ANGLE_90; - P_SetMobjState(seg, S_YELLOWBOOSTERSEG_FACE); - seg = P_SpawnMobjFromMobj(mobj, -26*x1, -26*y1, 0, MT_BOOSTERSEG); - seg->angle = angle+ANGLE_90; - P_SetMobjState(seg, S_YELLOWBOOSTERSEG_FACE); - seg = P_SpawnMobjFromMobj(mobj, 21*x2, 21*y2, 0, MT_BOOSTERSEG); - seg->angle = angle; - P_SetMobjState(seg, S_YELLOWBOOSTERSEG_LEFT); - seg = P_SpawnMobjFromMobj(mobj, -21*x2, -21*y2, 0, MT_BOOSTERSEG); - seg->angle = angle; - P_SetMobjState(seg, S_YELLOWBOOSTERSEG_RIGHT); - - seg = P_SpawnMobjFromMobj(mobj, 13*(x1+x2), 13*(y1+y2), 0, MT_BOOSTERROLLER); - seg->angle = angle; - P_SetMobjState(seg, S_YELLOWBOOSTERROLLER); - seg = P_SpawnMobjFromMobj(mobj, 13*(x1-x2), 13*(y1-y2), 0, MT_BOOSTERROLLER); - seg->angle = angle; - P_SetMobjState(seg, S_YELLOWBOOSTERROLLER); - seg = P_SpawnMobjFromMobj(mobj, -13*(x1+x2), -13*(y1+y2), 0, MT_BOOSTERROLLER); - seg->angle = angle; - P_SetMobjState(seg, S_YELLOWBOOSTERROLLER); - seg = P_SpawnMobjFromMobj(mobj, -13*(x1-x2), -13*(y1-y2), 0, MT_BOOSTERROLLER); - seg->angle = angle; - P_SetMobjState(seg, S_YELLOWBOOSTERROLLER); + if (!P_SetupBooster(mthing, mobj, mobj->type == MT_REDBOOSTER)) + return false; break; - } - default: - break; - } + case MT_AXIS: + // Inverted if uppermost bit is set + if (mthing->angle & 16384) + mobj->flags2 |= MF2_AMBUSH; - if (mobj->flags & MF_BOSS) - { - if (mthing->options & MTF_OBJECTSPECIAL) // No egg trap for this boss - mobj->flags2 |= MF2_BOSSNOTRAP; - } - - if (i == MT_AXIS || i == MT_AXISTRANSFER || i == MT_AXISTRANSFERLINE) // Axis Points - { + if (mthing->angle > 0) + mobj->radius = (mthing->angle & 16383) << FRACBITS; + // FALLTHRU + case MT_AXISTRANSFER: + case MT_AXISTRANSFERLINE: // Mare it belongs to mobj->threshold = min(mthing->extrainfo, 7); @@ -12831,38 +12779,29 @@ ML_EFFECT5 : Don't stop thinking when too far away mobj->health = mthing->options; mobj->flags2 |= MF2_AXIS; - - if (i == MT_AXIS) - { - // Inverted if uppermost bit is set - if (mthing->angle & 16384) - mobj->flags2 |= MF2_AMBUSH; - - if (mthing->angle > 0) - mobj->radius = (mthing->angle & 16383)*FRACUNIT; - } - } - else if (i == MT_TOKEN) - { + break; + case MT_TOKEN: // We advanced tokenbits earlier due to the return check. // Subtract 1 here for the correct value. mobj->health = 1 << (tokenbits - 1); - } - else if (i == MT_CYBRAKDEMON && mthing->options & MTF_AMBUSH) + break; + case MT_CYBRAKDEMON: + if (mthing->options & MTF_AMBUSH) + { + mobj_t* elecmobj; + elecmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_CYBRAKDEMON_ELECTRIC_BARRIER); + P_SetTarget(&elecmobj->target, mobj); + elecmobj->angle = FixedAngle(mthing->angle << FRACBITS); + elecmobj->destscale = mobj->scale*2; + P_SetScale(elecmobj, elecmobj->destscale); + } + break; + case MT_STARPOST: { - mobj_t *elecmobj; - elecmobj = P_SpawnMobj(x, y, z, MT_CYBRAKDEMON_ELECTRIC_BARRIER); - P_SetTarget(&elecmobj->target, mobj); - elecmobj->angle = FixedAngle(mthing->angle<destscale = mobj->scale*2; - P_SetScale(elecmobj, elecmobj->destscale); - } - else if (i == MT_STARPOST) - { - thinker_t *th; - mobj_t *mo2; + thinker_t* th; + mobj_t* mo2; boolean foundanother = false; - mobj->health = (mthing->angle / 360) + 1; + mobj->health = (mthing->angle/360) + 1; // See if other starposts exist in this level that have the same value. for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) @@ -12870,7 +12809,7 @@ ML_EFFECT5 : Don't stop thinking when too far away if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) continue; - mo2 = (mobj_t *)th; + mo2 = (mobj_t*)th; if (mo2 == mobj) continue; @@ -12884,14 +12823,14 @@ ML_EFFECT5 : Don't stop thinking when too far away if (!foundanother) numstarposts++; + break; } - else if (i == MT_SPIKE) - { + case MT_SPIKE: // Pop up spikes! if (mthing->options & MTF_OBJECTSPECIAL) { mobj->flags &= ~MF_SCENERY; - mobj->fuse = (16 - mthing->extrainfo) * (mthing->angle + mobj->info->speed) / 16; + mobj->fuse = (16 - mthing->extrainfo)*(mthing->angle + mobj->info->speed)/16; if (mthing->options & MTF_EXTRA) P_SetMobjState(mobj, mobj->info->meleestate); } @@ -12903,14 +12842,13 @@ ML_EFFECT5 : Don't stop thinking when too far away mobj->flags |= MF_SOLID; P_SetThingPosition(mobj); } - } - else if (i == MT_WALLSPIKE) - { + break; + case MT_WALLSPIKE: // Pop up spikes! if (mthing->options & MTF_OBJECTSPECIAL) { mobj->flags &= ~MF_SCENERY; - mobj->fuse = (16 - mthing->extrainfo) * ((mthing->angle/360) + mobj->info->speed) / 16; + mobj->fuse = (16 - mthing->extrainfo)*((mthing->angle/360) + mobj->info->speed)/16; if (mthing->options & MTF_EXTRA) P_SetMobjState(mobj, mobj->info->meleestate); } @@ -12918,64 +12856,51 @@ ML_EFFECT5 : Don't stop thinking when too far away if (!(mthing->options & MTF_AMBUSH) && !metalrecording) { P_UnsetThingPosition(mobj); - mobj->flags &= ~(MF_NOBLOCKMAP|MF_NOCLIPHEIGHT); + mobj->flags &= ~(MF_NOBLOCKMAP | MF_NOCLIPHEIGHT); mobj->flags |= MF_SOLID; P_SetThingPosition(mobj); } // spawn base { - const angle_t mobjangle = FixedAngle(mthing->angle<angle << FRACBITS); // the mobj's own angle hasn't been set quite yet so... const fixed_t baseradius = mobj->radius - mobj->scale; - mobj_t *base = P_SpawnMobj( - mobj->x - P_ReturnThrustX(mobj, mobjangle, baseradius), - mobj->y - P_ReturnThrustY(mobj, mobjangle, baseradius), - mobj->z, MT_WALLSPIKEBASE); + mobj_t* base = P_SpawnMobj( + mobj->x - P_ReturnThrustX(mobj, mobjangle, baseradius), + mobj->y - P_ReturnThrustY(mobj, mobjangle, baseradius), + mobj->z, MT_WALLSPIKEBASE); base->angle = mobjangle + ANGLE_90; base->destscale = mobj->destscale; P_SetScale(base, mobj->scale); P_SetTarget(&base->target, mobj); P_SetTarget(&mobj->tracer, base); } - } - - //count 10 ring boxes into the number of rings equation too. - if (i == MT_RING_BOX && nummaprings >= 0) - nummaprings += 10; - - if (i == MT_BIGTUMBLEWEED || i == MT_LITTLETUMBLEWEED) - { + break; + case MT_RING_BOX: + //count 10 ring boxes into the number of rings equation too. + if (nummaprings >= 0) + nummaprings += 10; + break; + case MT_BIGTUMBLEWEED: + case MT_LITTLETUMBLEWEED: if (mthing->options & MTF_AMBUSH) { - mobj->momz += FixedMul(16*FRACUNIT, mobj->scale); - - if (P_RandomChance(FRACUNIT/2)) - mobj->momx += FixedMul(16*FRACUNIT, mobj->scale); - else - mobj->momx -= FixedMul(16*FRACUNIT, mobj->scale); - - if (P_RandomChance(FRACUNIT/2)) - mobj->momy += FixedMul(16*FRACUNIT, mobj->scale); - else - mobj->momy -= FixedMul(16*FRACUNIT,mobj->scale); + fixed_t offset = FixedMul(16*FRACUNIT, mobj->scale); + mobj->momx += P_RandomChance(FRACUNIT/2) ? offset : -offset; + mobj->momy += P_RandomChance(FRACUNIT/2) ? offset : -offset; + mobj->momz += offset; } - } - - // CTF flag pointers - if (i == MT_REDFLAG) - { + break; + case MT_REDFLAG: redflag = mobj; rflagpoint = mobj->spawnpoint; - } - if (i == MT_BLUEFLAG) - { + break; + case MT_BLUEFLAG: blueflag = mobj; bflagpoint = mobj->spawnpoint; - } - - // special push/pull stuff - if (i == MT_PUSH || i == MT_PULL) - { + break; + case MT_PUSH: + case MT_PULL: mobj->health = 0; // Default behaviour: pushing uses XY, fading uses XYZ if (mthing->options & MTF_AMBUSH) @@ -12984,14 +12909,68 @@ ML_EFFECT5 : Don't stop thinking when too far away mobj->health |= 2; // If object special is set, fade using XY if (G_IsSpecialStage(gamemap)) - { - if (i == MT_PUSH) - P_SetMobjState(mobj, S_GRAVWELLGREEN); - if (i == MT_PULL) - P_SetMobjState(mobj, S_GRAVWELLRED); - } + P_SetMobjState(mobj, (mobj->type == MT_PUSH) ? S_GRAVWELLGREEN : S_GRAVWELLRED); + break; + default: + break; } + if (mobj->flags & MF_BOSS) + { + if (mthing->options & MTF_OBJECTSPECIAL) // No egg trap for this boss + mobj->flags2 |= MF2_BOSSNOTRAP; + } + + return true; +} + +// +// P_SpawnMapThing +// The fields of the mapthing should +// already be in host byte order. +// +void P_SpawnMapThing(mapthing_t *mthing) +{ + mobjtype_t i; + mobj_t *mobj; + fixed_t x, y, z; + boolean doangle = true; + + if (!mthing->type) + return; // Ignore type-0 things as NOPs + + if (mthing->type == 3328) // 3D Mode start Thing + return; + + if (!objectplacing && P_SpawnNonMobjMapThing(mthing)) + return; + + i = P_GetMobjtype(mthing->type); + if (i == MT_UNKNOWN) + CONS_Alert(CONS_WARNING, M_GetText("Unknown thing type %d placed at (%d, %d)\n"), mthing->type, mthing->x, mthing->y); + + // Skip all returning/substitution code in objectplace. + if (!objectplacing) + { + if (!P_AllowMobjSpawn(mthing, i)) + return; + + i = P_GetMobjtypeSubstitute(mthing, i); + if (i == MT_NULL) // Don't spawn mobj + return; + } + + // spawn it + x = mthing->x << FRACBITS; + y = mthing->y << FRACBITS; + z = P_GetMobjSpawnHeight(i, mthing, x, y); + + mobj = P_SpawnMobj(x, y, z, i); + mobj->spawnpoint = mthing; + + if (!P_SetupSpawnedMapThing(mthing, mobj, &doangle)) + return; + if (doangle) mobj->angle = FixedAngle(mthing->angle< Date: Mon, 23 Dec 2019 19:08:40 +0100 Subject: [PATCH 152/195] P_SpawnMapThing(): Separate handling of MTF_AMBUSH and MTF_OBJECTSPECIAL in its own functions --- src/p_mobj.c | 120 ++++++++++++++++++++++++++------------------------- 1 file changed, 61 insertions(+), 59 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 0397451d0..04411f585 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11598,6 +11598,12 @@ static fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* offset = 288*FRACUNIT; break; + // Horizontal springs, may float additional units with MTF_AMBUSH. + case MT_YELLOWHORIZ: + case MT_REDHORIZ: + case MT_BLUEHORIZ: + offset += mthing->options & MTF_AMBUSH ? 16*FRACUNIT : 0; + // Ring-like items, may float additional units with MTF_AMBUSH. case MT_SPIKEBALL: case MT_EMERALDSPAWN: @@ -12924,6 +12930,59 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean return true; } +static void P_SetAmbush(mobj_t *mobj) +{ + if (mobj->type == MT_YELLOWDIAG || mobj->type == MT_REDDIAG || mobj->type == MT_BLUEDIAG) + mobj->angle += ANGLE_22h; + + if (mobj->flags & MF_NIGHTSITEM) + { + // Spawn already displayed + mobj->flags |= MF_SPECIAL; + mobj->flags &= ~MF_NIGHTSITEM; + } + + if (mobj->flags & MF_PUSHABLE) + mobj->flags &= ~MF_PUSHABLE; + + if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0) + { + // flag for strong/weak random boxes + // any monitor with nonzero speed is allowed to respawn like this + mobj->flags2 |= MF2_AMBUSH; + } + + else if (mobj->type != MT_AXIS && + mobj->type != MT_AXISTRANSFER && + mobj->type != MT_AXISTRANSFERLINE && + mobj->type != MT_NIGHTSBUMPER && + mobj->type != MT_STARPOST) + mobj->flags2 |= MF2_AMBUSH; +} + +static void P_SetObjectSpecial(mobj_t *mobj) +{ + if (mobj->type == MT_YELLOWDIAG || mobj->type == MT_REDDIAG || mobj->type == MT_BLUEDIAG) + mobj->flags |= MF_NOGRAVITY; + + if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0) + { + // flag for strong/weak random boxes + // any monitor with nonzero speed is allowed to respawn like this + mobj->flags2 |= MF2_STRONGBOX; + } + + // Requires you to be in bonus time to activate + if (mobj->flags & MF_NIGHTSITEM) + mobj->flags2 |= MF2_STRONGBOX; + + // Pushables bounce and slide coolly with object special flag set + if (mobj->flags & MF_PUSHABLE) + { + mobj->flags2 |= MF2_SLIDEPUSH; + mobj->flags |= MF_BOUNCE; + } +} // // P_SpawnMapThing // The fields of the mapthing should @@ -12988,67 +13047,10 @@ void P_SpawnMapThing(mapthing_t *mthing) else { if (mthing->options & MTF_AMBUSH) - { - if (i == MT_YELLOWDIAG || i == MT_REDDIAG || i == MT_BLUEDIAG) - mobj->angle += ANGLE_22h; - - if (i == MT_YELLOWHORIZ || i == MT_REDHORIZ || i == MT_BLUEHORIZ) - { - if (mthing->options & MTF_OBJECTFLIP) - mobj->z -= 16*FRACUNIT; - else - mobj->z += 16*FRACUNIT; - } - - - if (mobj->flags & MF_NIGHTSITEM) - { - // Spawn already displayed - mobj->flags |= MF_SPECIAL; - mobj->flags &= ~MF_NIGHTSITEM; - } - - if (mobj->flags & MF_PUSHABLE) - mobj->flags &= ~MF_PUSHABLE; - - if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0) - { - // flag for strong/weak random boxes - // any monitor with nonzero speed is allowed to respawn like this - mobj->flags2 |= MF2_AMBUSH; - } - - else if (mthing->type != mobjinfo[MT_AXIS].doomednum && - mthing->type != mobjinfo[MT_AXISTRANSFER].doomednum && - mthing->type != mobjinfo[MT_AXISTRANSFERLINE].doomednum && - mthing->type != mobjinfo[MT_NIGHTSBUMPER].doomednum && - mthing->type != mobjinfo[MT_STARPOST].doomednum) - mobj->flags2 |= MF2_AMBUSH; - } + P_SetAmbush(mobj); if (mthing->options & MTF_OBJECTSPECIAL) - { - if (i == MT_YELLOWDIAG || i == MT_REDDIAG || i == MT_BLUEDIAG) - mobj->flags |= MF_NOGRAVITY; - - if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0) - { - // flag for strong/weak random boxes - // any monitor with nonzero speed is allowed to respawn like this - mobj->flags2 |= MF2_STRONGBOX; - } - - // Requires you to be in bonus time to activate - if (mobj->flags & MF_NIGHTSITEM) - mobj->flags2 |= MF2_STRONGBOX; - - // Pushables bounce and slide coolly with object special flag set - if (mobj->flags & MF_PUSHABLE) - { - mobj->flags2 |= MF2_SLIDEPUSH; - mobj->flags |= MF_BOUNCE; - } - } + P_SetObjectSpecial(mobj); } // Generic reverse gravity for individual objects flag. From 2b3922a8f3a4aefb316b508cfdaaa42eac57d269 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Mon, 23 Dec 2019 20:12:45 +0100 Subject: [PATCH 153/195] Set mthing->mobj before the flags handling code, since at this point the setup can't fail anymore --- src/p_mobj.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 04411f585..1acecbb76 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -13033,12 +13033,11 @@ void P_SpawnMapThing(mapthing_t *mthing) if (doangle) mobj->angle = FixedAngle(mthing->angle<mobj = mobj; + // ignore MTF_ flags and return early if (i == MT_NIGHTSBUMPER) - { - mthing->mobj = mobj; return; - } if ((mthing->options & MTF_AMBUSH) && (mthing->options & MTF_OBJECTSPECIAL) @@ -13073,8 +13072,6 @@ void P_SpawnMapThing(mapthing_t *mthing) // Final set of not being able to draw nightsitems. if (mobj->flags & MF_NIGHTSITEM) mobj->flags2 |= MF2_DONTDRAW; - - mthing->mobj = mobj; } static void P_SpawnHoop(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z, sector_t* sec, INT32 hoopsize, fixed_t sizefactor) From 24f8d4ef519a8541e24df3b47a2c9293d053ff11 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Mon, 23 Dec 2019 21:17:12 +0100 Subject: [PATCH 154/195] Made a mapthing-independent version of P_GetMobjSpawnHeight so P_SpawnHoopsAndRings subfunctions can use it instead of duplicating code. --- src/p_mobj.c | 144 +++++++++++++++++---------------------------------- 1 file changed, 48 insertions(+), 96 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 1acecbb76..54e603fe9 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11559,10 +11559,39 @@ void P_MovePlayerToStarpost(INT32 playernum) mapthing_t *huntemeralds[MAXHUNTEMERALDS]; INT32 numhuntemeralds; - -static fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mthing, const fixed_t x, const fixed_t y) +static fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, const fixed_t y, const fixed_t offset, const boolean flip) { const subsector_t *ss = R_PointInSubsector(x, y); + + // Axis objects snap to the floor. + if (mobjtype == MT_AXIS || mobjtype == MT_AXISTRANSFER || mobjtype == MT_AXISTRANSFERLINE) + return ONFLOORZ; + + if (!offset) // Snap to the surfaces when there's no offset set. + { + if (flip) + return ONCEILINGZ; + else + return ONFLOORZ; + } + + // Establish height. + if (flip) + return ( +#ifdef ESLOPE + ss->sector->c_slope ? P_GetZAt(ss->sector->c_slope, x, y) : +#endif + ss->sector->ceilingheight) - offset - mobjinfo[mobjtype].height; + else + return ( +#ifdef ESLOPE + ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) : +#endif + ss->sector->floorheight) + offset; +} + +static fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mthing, const fixed_t x, const fixed_t y) +{ fixed_t offset = mthing->z << FRACBITS; boolean flip = (!!(mobjinfo[mobjtype].flags & MF_SPAWNCEILING) ^ !!(mthing->options & MTF_OBJECTFLIP)); @@ -11573,12 +11602,6 @@ static fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* flip = false; break; - // Axis objects snap to the floor. - case MT_AXIS: - case MT_AXISTRANSFER: - case MT_AXISTRANSFERLINE: - return ONFLOORZ; - // Objects with a non-zero default height. case MT_CRAWLACOMMANDER: case MT_DETON: @@ -11626,27 +11649,7 @@ static fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* offset += mthing->options & MTF_AMBUSH ? 24*FRACUNIT : 0; } - if (!offset) // Snap to the surfaces when there's no offset set. - { - if (flip) - return ONCEILINGZ; - else - return ONFLOORZ; - } - - // Establish height. - if (flip) - return ( -#ifdef ESLOPE - ss->sector->c_slope ? P_GetZAt(ss->sector->c_slope, x, y) : -#endif - ss->sector->ceilingheight) - offset - mobjinfo[mobjtype].height; - else - return ( -#ifdef ESLOPE - ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) : -#endif - ss->sector->floorheight) + offset; + return P_GetMobjSpawnHeight(mobjtype, x, y, offset, flip); } static boolean P_SpawnNonMobjMapThing(mapthing_t *mthing) @@ -13022,7 +13025,7 @@ void P_SpawnMapThing(mapthing_t *mthing) // spawn it x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; - z = P_GetMobjSpawnHeight(i, mthing, x, y); + z = P_GetMapThingSpawnHeight(i, mthing, x, y); mobj = P_SpawnMobj(x, y, z, i); mobj->spawnpoint = mthing; @@ -13074,7 +13077,7 @@ void P_SpawnMapThing(mapthing_t *mthing) mobj->flags2 |= MF2_DONTDRAW; } -static void P_SpawnHoop(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z, sector_t* sec, INT32 hoopsize, fixed_t sizefactor) +static void P_SpawnHoop(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z, INT32 hoopsize, fixed_t sizefactor) { mobj_t *mobj = NULL; mobj_t *nextmobj = NULL; @@ -13085,11 +13088,7 @@ static void P_SpawnHoop(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z, sec angle_t fa; TVector v, *res; - z += -#ifdef ESLOPE - sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : -#endif - sec->floorheight; + z = P_GetMobjSpawnHeight(MT_HOOP, x, y, z, false); hoopcenter = P_SpawnMobj(x, y, z, MT_HOOPCENTER); hoopcenter->spawnpoint = mthing; @@ -13209,7 +13208,7 @@ static void P_SpawnRingItem(mapthing_t *mthing, fixed_t x, fixed_t y, boolean bo ringthing = (gametype == GT_CTF) ? MT_BLUETEAMRING : MT_RING; } - z = P_GetMobjSpawnHeight(ringthing, mthing, x, y); + z = P_GetMapThingSpawnHeight(ringthing, mthing, x, y); mobj = P_SpawnMobj(x, y, z, ringthing); mobj->spawnpoint = mthing; @@ -13230,11 +13229,10 @@ static void P_SpawnRingItem(mapthing_t *mthing, fixed_t x, fixed_t y, boolean bo P_SetMobjState(mobj, mobj->info->seestate); } -static void P_SpawnVerticalSpringRings(mapthing_t *mthing, fixed_t x, fixed_t y, sector_t* sec, boolean nightsreplace) +static void P_SpawnVerticalSpringRings(mapthing_t *mthing, fixed_t x, fixed_t y, fixed_t z, boolean nightsreplace) { mobjtype_t ringthing = MT_RING; mobj_t* mobj = NULL; - fixed_t z; INT32 r; INT32 dist = 64*FRACUNIT; @@ -13247,26 +13245,7 @@ static void P_SpawnVerticalSpringRings(mapthing_t *mthing, fixed_t x, fixed_t y, if (nightsreplace) ringthing = MT_NIGHTSSTAR; - if (mthing->options & MTF_OBJECTFLIP) - { - z = ( -#ifdef ESLOPE - sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : -#endif - sec->ceilingheight) - mobjinfo[ringthing].height; - if (mthing->z) - z -= (mthing->z << FRACBITS); - } - else - { - z = ( -#ifdef ESLOPE - sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : -#endif - sec->floorheight); - if (mthing->z) - z += (mthing->z << FRACBITS); - } + z = P_GetMobjSpawnHeight(ringthing, x, y, z, mthing->options & MTF_OBJECTFLIP); for (r = 1; r <= 5; r++) { @@ -13292,11 +13271,10 @@ static void P_SpawnVerticalSpringRings(mapthing_t *mthing, fixed_t x, fixed_t y, } } -static void P_SpawnDiagonalSpringRings(mapthing_t* mthing, fixed_t x, fixed_t y, sector_t* sec, boolean nightsreplace) +static void P_SpawnDiagonalSpringRings(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z, boolean nightsreplace) { mobjtype_t ringthing = MT_RING; mobj_t *mobj = NULL; - fixed_t z; INT32 r; angle_t closestangle, fa; @@ -13313,26 +13291,7 @@ static void P_SpawnDiagonalSpringRings(mapthing_t* mthing, fixed_t x, fixed_t y, closestangle = FixedAngle(mthing->angle << FRACBITS); fa = (closestangle >> ANGLETOFINESHIFT); - if (mthing->options & MTF_OBJECTFLIP) - { - z = ( -#ifdef ESLOPE - sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : -#endif - sec->ceilingheight) - mobjinfo[ringthing].height; - if (mthing->z) - z -= (mthing->z << FRACBITS); - } - else - { - z = ( -#ifdef ESLOPE - sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : -#endif - sec->floorheight); - if (mthing->z) - z += (mthing->z << FRACBITS); - } + z = P_GetMobjSpawnHeight(ringthing, x, y, z, mthing->options & MTF_OBJECTFLIP); for (r = 1; r <= iterations; r++) { @@ -13361,11 +13320,11 @@ static void P_SpawnDiagonalSpringRings(mapthing_t* mthing, fixed_t x, fixed_t y, } } -static void P_SpawnItemCircle(mapthing_t* mthing, fixed_t x, fixed_t y, sector_t* sec, boolean bonustime, boolean nightsreplace) +static void P_SpawnItemCircle(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z, boolean bonustime, boolean nightsreplace) { mobjtype_t ringthing = MT_RING; mobj_t *mobj = NULL; - fixed_t z, finalx, finaly, finalz; + fixed_t finalx, finaly, finalz; angle_t closestangle, fa; INT32 i; TVector v, *res; @@ -13378,13 +13337,7 @@ static void P_SpawnItemCircle(mapthing_t* mthing, fixed_t x, fixed_t y, sector_t size = 192*FRACUNIT; } - z = -#ifdef ESLOPE - sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : -#endif - sec->floorheight; - if (mthing->z) - z += (mthing->z << FRACBITS); + z = P_GetMobjSpawnHeight(ringthing, x, y, z, false); closestangle = FixedAngle(mthing->angle << FRACBITS); @@ -13462,7 +13415,6 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) fixed_t x = mthing->x << FRACBITS; fixed_t y = mthing->y << FRACBITS; fixed_t z = mthing->z << FRACBITS; - sector_t *sec = R_PointInSubsector(x, y)->sector; boolean nightsreplace = ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)); switch (mthing->type) @@ -13470,11 +13422,11 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) // Special placement patterns case 600: // 5 vertical rings (yellow spring) case 601: // 5 vertical rings (red spring) - P_SpawnVerticalSpringRings(mthing, x, y, sec, nightsreplace); + P_SpawnVerticalSpringRings(mthing, x, y, z, nightsreplace); return; case 602: // 5 diagonal rings (yellow spring) case 603: // 10 diagonal rings (red spring) - P_SpawnDiagonalSpringRings(mthing, x, y, sec, nightsreplace); + P_SpawnDiagonalSpringRings(mthing, x, y, z, nightsreplace); return; case 604: // Circle of rings (8 items) case 605: // Circle of rings (16 bits) @@ -13482,16 +13434,16 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) case 607: // Circle of blue spheres (16 items) case 608: // Circle of rings and blue spheres (8 items) case 609: // Circle of rings and blue spheres (16 items) - P_SpawnItemCircle(mthing, x, y, sec, bonustime, nightsreplace); + P_SpawnItemCircle(mthing, x, y, z, bonustime, nightsreplace); return; // Hoops case 1705: // Generic NiGHTS hoop - P_SpawnHoop(mthing, x, y, z, sec, 24, 4*FRACUNIT); + P_SpawnHoop(mthing, x, y, z, 24, 4*FRACUNIT); return; case 1713: // Customizable NiGHTS hoop // For each flag add 16 fracunits to the size // Default (0 flags) is 32 fracunits - P_SpawnHoop(mthing, x, y, z, sec, 8 + (4*(mthing->options & 0xF)), 4*FRACUNIT); + P_SpawnHoop(mthing, x, y, z, 8 + (4*(mthing->options & 0xF)), 4*FRACUNIT); return; default: // All manners of rings and coins P_SpawnRingItem(mthing, x, y, bonustime, nightsreplace); From 6939da01641bc950f99b0080055d9729e16c2c3b Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Mon, 23 Dec 2019 21:35:03 +0100 Subject: [PATCH 155/195] Turned nightsreplace into a macro so we have don't have to keep dragging it along as a function parameter --- src/p_mobj.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 54e603fe9..aa19716df 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -13182,7 +13182,9 @@ static void P_SpawnHoop(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z, INT } while (hoopsize >= 8); } -static void P_SpawnRingItem(mapthing_t *mthing, fixed_t x, fixed_t y, boolean bonustime, boolean nightsreplace) +#define nightsreplace ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) + +static void P_SpawnRingItem(mapthing_t *mthing, fixed_t x, fixed_t y, boolean bonustime) { mobjtype_t ringthing = MT_RING; mobj_t *mobj = NULL; @@ -13229,7 +13231,7 @@ static void P_SpawnRingItem(mapthing_t *mthing, fixed_t x, fixed_t y, boolean bo P_SetMobjState(mobj, mobj->info->seestate); } -static void P_SpawnVerticalSpringRings(mapthing_t *mthing, fixed_t x, fixed_t y, fixed_t z, boolean nightsreplace) +static void P_SpawnVerticalSpringRings(mapthing_t *mthing, fixed_t x, fixed_t y, fixed_t z) { mobjtype_t ringthing = MT_RING; mobj_t* mobj = NULL; @@ -13271,7 +13273,7 @@ static void P_SpawnVerticalSpringRings(mapthing_t *mthing, fixed_t x, fixed_t y, } } -static void P_SpawnDiagonalSpringRings(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z, boolean nightsreplace) +static void P_SpawnDiagonalSpringRings(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z) { mobjtype_t ringthing = MT_RING; mobj_t *mobj = NULL; @@ -13320,7 +13322,7 @@ static void P_SpawnDiagonalSpringRings(mapthing_t* mthing, fixed_t x, fixed_t y, } } -static void P_SpawnItemCircle(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z, boolean bonustime, boolean nightsreplace) +static void P_SpawnItemCircle(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z, boolean bonustime) { mobjtype_t ringthing = MT_RING; mobj_t *mobj = NULL; @@ -13415,18 +13417,17 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) fixed_t x = mthing->x << FRACBITS; fixed_t y = mthing->y << FRACBITS; fixed_t z = mthing->z << FRACBITS; - boolean nightsreplace = ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)); switch (mthing->type) { // Special placement patterns case 600: // 5 vertical rings (yellow spring) case 601: // 5 vertical rings (red spring) - P_SpawnVerticalSpringRings(mthing, x, y, z, nightsreplace); + P_SpawnVerticalSpringRings(mthing, x, y, z); return; case 602: // 5 diagonal rings (yellow spring) case 603: // 10 diagonal rings (red spring) - P_SpawnDiagonalSpringRings(mthing, x, y, z, nightsreplace); + P_SpawnDiagonalSpringRings(mthing, x, y, z); return; case 604: // Circle of rings (8 items) case 605: // Circle of rings (16 bits) @@ -13434,7 +13435,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) case 607: // Circle of blue spheres (16 items) case 608: // Circle of rings and blue spheres (8 items) case 609: // Circle of rings and blue spheres (16 items) - P_SpawnItemCircle(mthing, x, y, z, bonustime, nightsreplace); + P_SpawnItemCircle(mthing, x, y, z, bonustime); return; // Hoops case 1705: // Generic NiGHTS hoop @@ -13446,7 +13447,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) P_SpawnHoop(mthing, x, y, z, 8 + (4*(mthing->options & 0xF)), 4*FRACUNIT); return; default: // All manners of rings and coins - P_SpawnRingItem(mthing, x, y, bonustime, nightsreplace); + P_SpawnRingItem(mthing, x, y, bonustime); } } From d0f7877fd03c75c4a94528d8d9bfb6ce2c8ed09b Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 23 Dec 2019 18:33:39 -0300 Subject: [PATCH 156/195] Turn noglobals into setglobals, move the extra global variable handling to gamestateglobals. --- src/lua_script.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/lua_script.c b/src/lua_script.c index 13592815b..759f858a0 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -79,8 +79,22 @@ FUNCNORETURN static int LUA_Panic(lua_State *L) #endif } +// See lib_getenum in dehacked.c. +static boolean gamestateglobals(const char *csname, lua_State *L) +{ + if (fastcmp(csname,"redscore")) + redscore = (UINT32)luaL_checkinteger(L, 2); + else if (fastcmp(csname,"bluescore")) + bluescore = (UINT32)luaL_checkinteger(L, 2); + else + return false; + + // Global variable set, so return and don't error. + return true; +} + // This function decides which global variables you are allowed to set. -static int noglobals(lua_State *L) +static int setglobals(lua_State *L) { const char *csname; char *name; @@ -106,16 +120,8 @@ static int noglobals(lua_State *L) return 0; } - if (fastcmp(csname,"redscore")) - { - redscore = (UINT32)luaL_checkinteger(L, 2); + if (gamestateglobals(csname, L)) return 0; - } - else if (fastcmp(csname,"bluescore")) - { - bluescore = (UINT32)luaL_checkinteger(L, 2); - return 0; - } Z_Free(name); return luaL_error(L, "Implicit global " LUA_QS " prevented. Create a local variable instead.", csname); @@ -155,7 +161,7 @@ static void LUA_ClearState(void) // lock the global namespace lua_getmetatable(L, LUA_GLOBALSINDEX); - lua_pushcfunction(L, noglobals); + lua_pushcfunction(L, setglobals); lua_setfield(L, -2, "__newindex"); lua_newtable(L); lua_setfield(L, -2, "__metatable"); From 7425591815bb87a962196ab5da13f9398986c6e3 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 23 Dec 2019 18:37:38 -0300 Subject: [PATCH 157/195] Add pointlimit and timelimit to Lua. --- src/dehacked.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/dehacked.c b/src/dehacked.c index e3fac0a4b..0d8f230e0 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -10828,6 +10828,12 @@ static inline int lib_getenum(lua_State *L) } else if (fastcmp(word,"redscore")) { lua_pushinteger(L, redscore); return 1; + } else if (fastcmp(word,"timelimit")) { + lua_pushinteger(L, cv_timelimit.value); + return 1; + } else if (fastcmp(word,"pointlimit")) { + lua_pushinteger(L, cv_pointlimit.value); + return 1; // begin map vars } else if (fastcmp(word,"spstage_start")) { lua_pushinteger(L, spstage_start); From 5ebd84c3e734feea8099b00ae864b98e6548a0ff Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 23 Dec 2019 18:49:23 -0300 Subject: [PATCH 158/195] Move ALL the Lua global variable stuff into lua_script.c. --- src/dehacked.c | 208 +----------------------------------------- src/lua_script.c | 228 +++++++++++++++++++++++++++++++++++++++++++++-- src/lua_script.h | 2 + 3 files changed, 224 insertions(+), 214 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 0d8f230e0..d1e18a1d7 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -10777,213 +10777,7 @@ static inline int lib_getenum(lua_State *L) // DYNAMIC variables too!! // Try not to add anything that would break netgames or timeattack replays here. // You know, like consoleplayer, displayplayer, secondarydisplayplayer, or gametime. - if (fastcmp(word,"gamemap")) { - lua_pushinteger(L, gamemap); - return 1; - } else if (fastcmp(word,"maptol")) { - lua_pushinteger(L, maptol); - return 1; - } else if (fastcmp(word,"ultimatemode")) { - lua_pushboolean(L, ultimatemode != 0); - return 1; - } else if (fastcmp(word,"mariomode")) { - lua_pushboolean(L, mariomode != 0); - return 1; - } else if (fastcmp(word,"twodlevel")) { - lua_pushboolean(L, twodlevel != 0); - return 1; - } else if (fastcmp(word,"circuitmap")) { - lua_pushboolean(L, circuitmap); - return 1; - } else if (fastcmp(word,"netgame")) { - lua_pushboolean(L, netgame); - return 1; - } else if (fastcmp(word,"multiplayer")) { - lua_pushboolean(L, multiplayer); - return 1; - } else if (fastcmp(word,"modeattacking")) { - lua_pushboolean(L, modeattacking); - return 1; - } else if (fastcmp(word,"splitscreen")) { - lua_pushboolean(L, splitscreen); - return 1; - } else if (fastcmp(word,"gamecomplete")) { - lua_pushboolean(L, gamecomplete); - return 1; - } else if (fastcmp(word,"devparm")) { - lua_pushboolean(L, devparm); - return 1; - } else if (fastcmp(word,"modifiedgame")) { - lua_pushboolean(L, modifiedgame && !savemoddata); - return 1; - } else if (fastcmp(word,"menuactive")) { - lua_pushboolean(L, menuactive); - return 1; - } else if (fastcmp(word,"paused")) { - lua_pushboolean(L, paused); - return 1; - } else if (fastcmp(word,"bluescore")) { - lua_pushinteger(L, bluescore); - return 1; - } else if (fastcmp(word,"redscore")) { - lua_pushinteger(L, redscore); - return 1; - } else if (fastcmp(word,"timelimit")) { - lua_pushinteger(L, cv_timelimit.value); - return 1; - } else if (fastcmp(word,"pointlimit")) { - lua_pushinteger(L, cv_pointlimit.value); - return 1; - // begin map vars - } else if (fastcmp(word,"spstage_start")) { - lua_pushinteger(L, spstage_start); - return 1; - } else if (fastcmp(word,"sstage_start")) { - lua_pushinteger(L, sstage_start); - return 1; - } else if (fastcmp(word,"sstage_end")) { - lua_pushinteger(L, sstage_end); - return 1; - } else if (fastcmp(word,"smpstage_start")) { - lua_pushinteger(L, smpstage_start); - return 1; - } else if (fastcmp(word,"smpstage_end")) { - lua_pushinteger(L, smpstage_end); - return 1; - } else if (fastcmp(word,"titlemap")) { - lua_pushinteger(L, titlemap); - return 1; - } else if (fastcmp(word,"titlemapinaction")) { - lua_pushboolean(L, (titlemapinaction != TITLEMAP_OFF)); - return 1; - } else if (fastcmp(word,"bootmap")) { - lua_pushinteger(L, bootmap); - return 1; - } else if (fastcmp(word,"tutorialmap")) { - lua_pushinteger(L, tutorialmap); - return 1; - } else if (fastcmp(word,"tutorialmode")) { - lua_pushboolean(L, tutorialmode); - return 1; - // end map vars - // begin CTF colors - } else if (fastcmp(word,"skincolor_redteam")) { - lua_pushinteger(L, skincolor_redteam); - return 1; - } else if (fastcmp(word,"skincolor_blueteam")) { - lua_pushinteger(L, skincolor_blueteam); - return 1; - } else if (fastcmp(word,"skincolor_redring")) { - lua_pushinteger(L, skincolor_redring); - return 1; - } else if (fastcmp(word,"skincolor_bluering")) { - lua_pushinteger(L, skincolor_bluering); - return 1; - // end CTF colors - // begin timers - } else if (fastcmp(word,"invulntics")) { - lua_pushinteger(L, invulntics); - return 1; - } else if (fastcmp(word,"sneakertics")) { - lua_pushinteger(L, sneakertics); - return 1; - } else if (fastcmp(word,"flashingtics")) { - lua_pushinteger(L, flashingtics); - return 1; - } else if (fastcmp(word,"tailsflytics")) { - lua_pushinteger(L, tailsflytics); - return 1; - } else if (fastcmp(word,"underwatertics")) { - lua_pushinteger(L, underwatertics); - return 1; - } else if (fastcmp(word,"spacetimetics")) { - lua_pushinteger(L, spacetimetics); - return 1; - } else if (fastcmp(word,"extralifetics")) { - lua_pushinteger(L, extralifetics); - return 1; - } else if (fastcmp(word,"nightslinktics")) { - lua_pushinteger(L, nightslinktics); - return 1; - } else if (fastcmp(word,"gameovertics")) { - lua_pushinteger(L, gameovertics); - return 1; - } else if (fastcmp(word,"ammoremovaltics")) { - lua_pushinteger(L, ammoremovaltics); - return 1; - // end timers - } else if (fastcmp(word,"gametype")) { - lua_pushinteger(L, gametype); - return 1; - } else if (fastcmp(word,"gametyperules")) { - lua_pushinteger(L, gametyperules); - return 1; - } else if (fastcmp(word,"leveltime")) { - lua_pushinteger(L, leveltime); - return 1; - } else if (fastcmp(word,"curWeather")) { - lua_pushinteger(L, curWeather); - return 1; - } else if (fastcmp(word,"globalweather")) { - lua_pushinteger(L, globalweather); - return 1; - } else if (fastcmp(word,"levelskynum")) { - lua_pushinteger(L, levelskynum); - return 1; - } else if (fastcmp(word,"globallevelskynum")) { - lua_pushinteger(L, globallevelskynum); - return 1; - } else if (fastcmp(word,"mapmusname")) { - lua_pushstring(L, mapmusname); - return 1; - } else if (fastcmp(word,"mapmusflags")) { - lua_pushinteger(L, mapmusflags); - return 1; - } else if (fastcmp(word,"mapmusposition")) { - lua_pushinteger(L, mapmusposition); - return 1; - // local player variables, by popular request - } else if (fastcmp(word,"consoleplayer")) { // player controlling console (aka local player 1) - if (consoleplayer < 0 || !playeringame[consoleplayer]) - return 0; - LUA_PushUserdata(L, &players[consoleplayer], META_PLAYER); - return 1; - } else if (fastcmp(word,"displayplayer")) { // player visible on screen (aka display player 1) - if (displayplayer < 0 || !playeringame[displayplayer]) - return 0; - LUA_PushUserdata(L, &players[displayplayer], META_PLAYER); - return 1; - } else if (fastcmp(word,"secondarydisplayplayer")) { // local/display player 2, for splitscreen - if (!splitscreen || secondarydisplayplayer < 0 || !playeringame[secondarydisplayplayer]) - return 0; - LUA_PushUserdata(L, &players[secondarydisplayplayer], META_PLAYER); - return 1; - // end local player variables - } else if (fastcmp(word,"server")) { - if ((!multiplayer || !netgame) && !playeringame[serverplayer]) - return 0; - LUA_PushUserdata(L, &players[serverplayer], META_PLAYER); - return 1; - } else if (fastcmp(word,"admin")) { // BACKWARDS COMPATIBILITY HACK: This was replaced with IsPlayerAdmin(), but some 2.1 Lua scripts still use the admin variable. It now points to the first admin player in the array. - LUA_Deprecated(L, "admin", "IsPlayerAdmin(player)"); - if (!playeringame[adminplayers[0]] || IsPlayerAdmin(serverplayer)) - return 0; - LUA_PushUserdata(L, &players[adminplayers[0]], META_PLAYER); - return 1; - } else if (fastcmp(word,"emeralds")) { - lua_pushinteger(L, emeralds); - return 1; - } else if (fastcmp(word,"gravity")) { - lua_pushinteger(L, gravity); - return 1; - } else if (fastcmp(word,"VERSIONSTRING")) { - lua_pushstring(L, VERSIONSTRING); - return 1; - } else if (fastcmp(word, "token")) { - lua_pushinteger(L, token); - return 1; - } - return 0; + return LUA_PushGlobals(L, word); } int LUA_EnumLib(lua_State *L) diff --git a/src/lua_script.c b/src/lua_script.c index 759f858a0..4b5e72938 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -18,7 +18,9 @@ #include "w_wad.h" #include "p_setup.h" #include "r_state.h" +#include "r_sky.h" #include "g_game.h" +#include "f_finale.h" #include "byteptr.h" #include "p_saveg.h" #include "p_local.h" @@ -79,18 +81,230 @@ FUNCNORETURN static int LUA_Panic(lua_State *L) #endif } -// See lib_getenum in dehacked.c. -static boolean gamestateglobals(const char *csname, lua_State *L) +// Moved here from lib_getenum. +int LUA_PushGlobals(lua_State *L, const char *word) { - if (fastcmp(csname,"redscore")) + if (fastcmp(word,"gamemap")) { + lua_pushinteger(L, gamemap); + return 1; + } else if (fastcmp(word,"maptol")) { + lua_pushinteger(L, maptol); + return 1; + } else if (fastcmp(word,"ultimatemode")) { + lua_pushboolean(L, ultimatemode != 0); + return 1; + } else if (fastcmp(word,"mariomode")) { + lua_pushboolean(L, mariomode != 0); + return 1; + } else if (fastcmp(word,"twodlevel")) { + lua_pushboolean(L, twodlevel != 0); + return 1; + } else if (fastcmp(word,"circuitmap")) { + lua_pushboolean(L, circuitmap); + return 1; + } else if (fastcmp(word,"netgame")) { + lua_pushboolean(L, netgame); + return 1; + } else if (fastcmp(word,"multiplayer")) { + lua_pushboolean(L, multiplayer); + return 1; + } else if (fastcmp(word,"modeattacking")) { + lua_pushboolean(L, modeattacking); + return 1; + } else if (fastcmp(word,"splitscreen")) { + lua_pushboolean(L, splitscreen); + return 1; + } else if (fastcmp(word,"gamecomplete")) { + lua_pushboolean(L, gamecomplete); + return 1; + } else if (fastcmp(word,"devparm")) { + lua_pushboolean(L, devparm); + return 1; + } else if (fastcmp(word,"modifiedgame")) { + lua_pushboolean(L, modifiedgame && !savemoddata); + return 1; + } else if (fastcmp(word,"menuactive")) { + lua_pushboolean(L, menuactive); + return 1; + } else if (fastcmp(word,"paused")) { + lua_pushboolean(L, paused); + return 1; + } else if (fastcmp(word,"bluescore")) { + lua_pushinteger(L, bluescore); + return 1; + } else if (fastcmp(word,"redscore")) { + lua_pushinteger(L, redscore); + return 1; + } else if (fastcmp(word,"timelimit")) { + lua_pushinteger(L, cv_timelimit.value); + return 1; + } else if (fastcmp(word,"pointlimit")) { + lua_pushinteger(L, cv_pointlimit.value); + return 1; + // begin map vars + } else if (fastcmp(word,"spstage_start")) { + lua_pushinteger(L, spstage_start); + return 1; + } else if (fastcmp(word,"sstage_start")) { + lua_pushinteger(L, sstage_start); + return 1; + } else if (fastcmp(word,"sstage_end")) { + lua_pushinteger(L, sstage_end); + return 1; + } else if (fastcmp(word,"smpstage_start")) { + lua_pushinteger(L, smpstage_start); + return 1; + } else if (fastcmp(word,"smpstage_end")) { + lua_pushinteger(L, smpstage_end); + return 1; + } else if (fastcmp(word,"titlemap")) { + lua_pushinteger(L, titlemap); + return 1; + } else if (fastcmp(word,"titlemapinaction")) { + lua_pushboolean(L, (titlemapinaction != TITLEMAP_OFF)); + return 1; + } else if (fastcmp(word,"bootmap")) { + lua_pushinteger(L, bootmap); + return 1; + } else if (fastcmp(word,"tutorialmap")) { + lua_pushinteger(L, tutorialmap); + return 1; + } else if (fastcmp(word,"tutorialmode")) { + lua_pushboolean(L, tutorialmode); + return 1; + // end map vars + // begin CTF colors + } else if (fastcmp(word,"skincolor_redteam")) { + lua_pushinteger(L, skincolor_redteam); + return 1; + } else if (fastcmp(word,"skincolor_blueteam")) { + lua_pushinteger(L, skincolor_blueteam); + return 1; + } else if (fastcmp(word,"skincolor_redring")) { + lua_pushinteger(L, skincolor_redring); + return 1; + } else if (fastcmp(word,"skincolor_bluering")) { + lua_pushinteger(L, skincolor_bluering); + return 1; + // end CTF colors + // begin timers + } else if (fastcmp(word,"invulntics")) { + lua_pushinteger(L, invulntics); + return 1; + } else if (fastcmp(word,"sneakertics")) { + lua_pushinteger(L, sneakertics); + return 1; + } else if (fastcmp(word,"flashingtics")) { + lua_pushinteger(L, flashingtics); + return 1; + } else if (fastcmp(word,"tailsflytics")) { + lua_pushinteger(L, tailsflytics); + return 1; + } else if (fastcmp(word,"underwatertics")) { + lua_pushinteger(L, underwatertics); + return 1; + } else if (fastcmp(word,"spacetimetics")) { + lua_pushinteger(L, spacetimetics); + return 1; + } else if (fastcmp(word,"extralifetics")) { + lua_pushinteger(L, extralifetics); + return 1; + } else if (fastcmp(word,"nightslinktics")) { + lua_pushinteger(L, nightslinktics); + return 1; + } else if (fastcmp(word,"gameovertics")) { + lua_pushinteger(L, gameovertics); + return 1; + } else if (fastcmp(word,"ammoremovaltics")) { + lua_pushinteger(L, ammoremovaltics); + return 1; + // end timers + } else if (fastcmp(word,"gametype")) { + lua_pushinteger(L, gametype); + return 1; + } else if (fastcmp(word,"gametyperules")) { + lua_pushinteger(L, gametyperules); + return 1; + } else if (fastcmp(word,"leveltime")) { + lua_pushinteger(L, leveltime); + return 1; + } else if (fastcmp(word,"curWeather")) { + lua_pushinteger(L, curWeather); + return 1; + } else if (fastcmp(word,"globalweather")) { + lua_pushinteger(L, globalweather); + return 1; + } else if (fastcmp(word,"levelskynum")) { + lua_pushinteger(L, levelskynum); + return 1; + } else if (fastcmp(word,"globallevelskynum")) { + lua_pushinteger(L, globallevelskynum); + return 1; + } else if (fastcmp(word,"mapmusname")) { + lua_pushstring(L, mapmusname); + return 1; + } else if (fastcmp(word,"mapmusflags")) { + lua_pushinteger(L, mapmusflags); + return 1; + } else if (fastcmp(word,"mapmusposition")) { + lua_pushinteger(L, mapmusposition); + return 1; + // local player variables, by popular request + } else if (fastcmp(word,"consoleplayer")) { // player controlling console (aka local player 1) + if (consoleplayer < 0 || !playeringame[consoleplayer]) + return 0; + LUA_PushUserdata(L, &players[consoleplayer], META_PLAYER); + return 1; + } else if (fastcmp(word,"displayplayer")) { // player visible on screen (aka display player 1) + if (displayplayer < 0 || !playeringame[displayplayer]) + return 0; + LUA_PushUserdata(L, &players[displayplayer], META_PLAYER); + return 1; + } else if (fastcmp(word,"secondarydisplayplayer")) { // local/display player 2, for splitscreen + if (!splitscreen || secondarydisplayplayer < 0 || !playeringame[secondarydisplayplayer]) + return 0; + LUA_PushUserdata(L, &players[secondarydisplayplayer], META_PLAYER); + return 1; + // end local player variables + } else if (fastcmp(word,"server")) { + if ((!multiplayer || !netgame) && !playeringame[serverplayer]) + return 0; + LUA_PushUserdata(L, &players[serverplayer], META_PLAYER); + return 1; + } else if (fastcmp(word,"admin")) { // BACKWARDS COMPATIBILITY HACK: This was replaced with IsPlayerAdmin(), but some 2.1 Lua scripts still use the admin variable. It now points to the first admin player in the array. + LUA_Deprecated(L, "admin", "IsPlayerAdmin(player)"); + if (!playeringame[adminplayers[0]] || IsPlayerAdmin(serverplayer)) + return 0; + LUA_PushUserdata(L, &players[adminplayers[0]], META_PLAYER); + return 1; + } else if (fastcmp(word,"emeralds")) { + lua_pushinteger(L, emeralds); + return 1; + } else if (fastcmp(word,"gravity")) { + lua_pushinteger(L, gravity); + return 1; + } else if (fastcmp(word,"VERSIONSTRING")) { + lua_pushstring(L, VERSIONSTRING); + return 1; + } else if (fastcmp(word, "token")) { + lua_pushinteger(L, token); + return 1; + } + return 0; +} + +// See the above. +int LUA_CheckGlobals(lua_State *L, const char *word) +{ + if (fastcmp(word, "redscore")) redscore = (UINT32)luaL_checkinteger(L, 2); - else if (fastcmp(csname,"bluescore")) + else if (fastcmp(word, "bluescore")) bluescore = (UINT32)luaL_checkinteger(L, 2); else - return false; + return 0; // Global variable set, so return and don't error. - return true; + return 1; } // This function decides which global variables you are allowed to set. @@ -120,7 +334,7 @@ static int setglobals(lua_State *L) return 0; } - if (gamestateglobals(csname, L)) + if (LUA_CheckGlobals(L, csname)) return 0; Z_Free(name); diff --git a/src/lua_script.h b/src/lua_script.h index 4f66d3f8a..8f27dcb4c 100644 --- a/src/lua_script.h +++ b/src/lua_script.h @@ -54,6 +54,8 @@ void LUA_InvalidatePlayer(player_t *player); void LUA_Step(void); void LUA_Archive(void); void LUA_UnArchive(void); +int LUA_PushGlobals(lua_State *L, const char *word); +int LUA_CheckGlobals(lua_State *L, const char *word); void Got_Luacmd(UINT8 **cp, INT32 playernum); // lua_consolelib.c void LUA_CVarChanged(const char *name); // lua_consolelib.c int Lua_optoption(lua_State *L, int narg, From edddc3e64e43351e99368605cc4c09edd6cbe289 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 23 Dec 2019 18:54:25 -0300 Subject: [PATCH 159/195] Custom gametype constant support for Lua. --- src/lua_baselib.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 5f9d3dbf6..b0935983e 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -2642,6 +2642,7 @@ static int lib_gAddGametype(lua_State *L) lua_Integer i; const char *gtname = NULL; + const char *gtconst = NULL; const char *gtdescription = NULL; INT16 newgtidx = 0; UINT32 newgtrules = 0; @@ -2678,39 +2679,43 @@ static int lib_gAddGametype(lua_State *L) if (!lua_isstring(L, 3)) TYPEERROR("name", LUA_TSTRING) gtname = Z_StrDup(lua_tostring(L, 3)); - } else if (i == 2 || (k && fasticmp(k, "rules"))) { + } else if (i == 2 || (k && fasticmp(k, "identifier"))) { + if (!lua_isstring(L, 3)) + TYPEERROR("identifier", LUA_TSTRING) + gtconst = Z_StrDup(lua_tostring(L, 3)); + } else if (i == 3 || (k && fasticmp(k, "rules"))) { if (!lua_isnumber(L, 3)) TYPEERROR("rules", LUA_TNUMBER) newgtrules = (UINT32)lua_tointeger(L, 3); - } else if (i == 3 || (k && fasticmp(k, "typeoflevel"))) { + } else if (i == 4 || (k && fasticmp(k, "typeoflevel"))) { if (!lua_isnumber(L, 3)) TYPEERROR("typeoflevel", LUA_TNUMBER) newgttol = (UINT32)lua_tointeger(L, 3); - } else if (i == 4 || (k && fasticmp(k, "rankingtype"))) { + } else if (i == 5 || (k && fasticmp(k, "rankingtype"))) { if (!lua_isnumber(L, 3)) TYPEERROR("rankingtype", LUA_TNUMBER) newgtrankingstype = (INT16)lua_tointeger(L, 3); - } else if (i == 5 || (k && fasticmp(k, "intermissiontype"))) { + } else if (i == 6 || (k && fasticmp(k, "intermissiontype"))) { if (!lua_isnumber(L, 3)) TYPEERROR("intermissiontype", LUA_TNUMBER) newgtinttype = (int)lua_tointeger(L, 3); - } else if (i == 6 || (k && fasticmp(k, "defaultpointlimit"))) { + } else if (i == 7 || (k && fasticmp(k, "defaultpointlimit"))) { if (!lua_isnumber(L, 3)) TYPEERROR("defaultpointlimit", LUA_TNUMBER) newgtpointlimit = (INT32)lua_tointeger(L, 3); - } else if (i == 7 || (k && fasticmp(k, "defaulttimelimit"))) { + } else if (i == 8 || (k && fasticmp(k, "defaulttimelimit"))) { if (!lua_isnumber(L, 3)) TYPEERROR("defaulttimelimit", LUA_TNUMBER) newgttimelimit = (INT32)lua_tointeger(L, 3); - } else if (i == 8 || (k && fasticmp(k, "description"))) { + } else if (i == 9 || (k && fasticmp(k, "description"))) { if (!lua_isstring(L, 3)) TYPEERROR("description", LUA_TSTRING) gtdescription = Z_StrDup(lua_tostring(L, 3)); - } else if (i == 9 || (k && fasticmp(k, "headerleftcolor"))) { + } else if (i == 10 || (k && fasticmp(k, "headerleftcolor"))) { if (!lua_isnumber(L, 3)) TYPEERROR("headerleftcolor", LUA_TNUMBER) newgtleftcolor = (UINT8)lua_tointeger(L, 3); - } else if (i == 10 || (k && fasticmp(k, "headerrightcolor"))) { + } else if (i == 11 || (k && fasticmp(k, "headerrightcolor"))) { if (!lua_isnumber(L, 3)) TYPEERROR("headerrightcolor", LUA_TNUMBER) newgtrightcolor = (UINT8)lua_tointeger(L, 3); @@ -2753,7 +2758,9 @@ static int lib_gAddGametype(lua_State *L) Gametype_Names[newgtidx] = gtname; // Write the constant name. - G_AddGametypeConstant(newgtidx, gtname); + if (gtconst == NULL) + gtconst = gtname; + G_AddGametypeConstant(newgtidx, gtconst); // Update gametype_cons_t accordingly. G_UpdateGametypeSelections(); From d050e04dae61594149b2f029f2f872119b6d3f2e Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 23 Dec 2019 18:58:33 -0300 Subject: [PATCH 160/195] Bail out if there are no more free gametype slots. --- src/lua_baselib.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index b0935983e..e5d477549 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -2734,6 +2734,10 @@ static int lib_gAddGametype(lua_State *L) // pop gametype table lua_pop(L, 1); + // Ran out of gametype slots + if (gametypecount == NUMGAMETYPEFREESLOTS) + return luaL_error(L, "Ran out of free gametype slots!"); + // Set defaults if (gtname == NULL) gtname = Z_StrDup("Unnamed gametype"); From 50dd0a71db5a38ad4ccb1d2c0bee3b112b0ca8bf Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Mon, 23 Dec 2019 22:58:58 +0100 Subject: [PATCH 161/195] Turn size and number of items for item circle into function parameters (in preparation for UDMF) --- src/p_mobj.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index aa19716df..b4ac43e21 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -13322,7 +13322,7 @@ static void P_SpawnDiagonalSpringRings(mapthing_t* mthing, fixed_t x, fixed_t y, } } -static void P_SpawnItemCircle(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z, boolean bonustime) +static void P_SpawnItemCircle(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z, INT32 numitems, fixed_t size, boolean bonustime) { mobjtype_t ringthing = MT_RING; mobj_t *mobj = NULL; @@ -13330,14 +13330,6 @@ static void P_SpawnItemCircle(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t angle_t closestangle, fa; INT32 i; TVector v, *res; - INT32 numitems = 8; - INT32 size = 96*FRACUNIT; - - if (mthing->type & 1) - { - numitems = 16; - size = 192*FRACUNIT; - } z = P_GetMobjSpawnHeight(ringthing, x, y, z, false); @@ -13430,13 +13422,17 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) P_SpawnDiagonalSpringRings(mthing, x, y, z); return; case 604: // Circle of rings (8 items) - case 605: // Circle of rings (16 bits) + case 605: // Circle of rings (16 items) case 606: // Circle of blue spheres (8 items) case 607: // Circle of blue spheres (16 items) case 608: // Circle of rings and blue spheres (8 items) case 609: // Circle of rings and blue spheres (16 items) - P_SpawnItemCircle(mthing, x, y, z, bonustime); + { + INT32 numitems = (mthing->type & 1) ? 16 : 8; + fixed_t size = (mthing->type & 1) ? 192*FRACUNIT : 96*FRACUNIT; + P_SpawnItemCircle(mthing, x, y, z, numitems, size, bonustime); return; + } // Hoops case 1705: // Generic NiGHTS hoop P_SpawnHoop(mthing, x, y, z, 24, 4*FRACUNIT); From bbe946ac1e8d741536d62224fa9c89651eaaa28e Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 23 Dec 2019 19:00:46 -0300 Subject: [PATCH 162/195] Bail out earlier. --- src/lua_baselib.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index e5d477549..20eaa2048 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -2660,6 +2660,10 @@ static int lib_gAddGametype(lua_State *L) if (!lua_lumploading) return luaL_error(L, "This function cannot be called from within a hook or coroutine!"); + // Ran out of gametype slots + if (gametypecount == NUMGAMETYPEFREESLOTS) + return luaL_error(L, "Ran out of free gametype slots!"); + #define FIELDERROR(f, e) luaL_error(L, "bad value for " LUA_QL(f) " in table passed to " LUA_QL("G_AddGametype") " (%s)", e); #define TYPEERROR(f, t) FIELDERROR(f, va("%s expected, got %s", lua_typename(L, t), luaL_typename(L, -1))) @@ -2734,10 +2738,6 @@ static int lib_gAddGametype(lua_State *L) // pop gametype table lua_pop(L, 1); - // Ran out of gametype slots - if (gametypecount == NUMGAMETYPEFREESLOTS) - return luaL_error(L, "Ran out of free gametype slots!"); - // Set defaults if (gtname == NULL) gtname = Z_StrDup("Unnamed gametype"); From e9f69b9c6a07c3bbda1aec57def1f20cc2c457d9 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 23 Dec 2019 19:08:57 -0300 Subject: [PATCH 163/195] Add sstimer to LUA_PushGlobals. --- src/lua_script.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lua_script.c b/src/lua_script.c index 4b5e72938..eb1afaf09 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -228,6 +228,9 @@ int LUA_PushGlobals(lua_State *L, const char *word) } else if (fastcmp(word,"leveltime")) { lua_pushinteger(L, leveltime); return 1; + } else if (fastcmp(word,"sstimer")) { + lua_pushinteger(L, sstimer); + return 1; } else if (fastcmp(word,"curWeather")) { lua_pushinteger(L, curWeather); return 1; From bb1f43d37458ecb699c7860983f6cc7ea003a86b Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 23 Dec 2019 19:16:10 -0300 Subject: [PATCH 164/195] Add gametyperules to LUA_CheckGlobals. --- src/lua_script.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lua_script.c b/src/lua_script.c index eb1afaf09..18d9a87c2 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -299,7 +299,9 @@ int LUA_PushGlobals(lua_State *L, const char *word) // See the above. int LUA_CheckGlobals(lua_State *L, const char *word) { - if (fastcmp(word, "redscore")) + if (fastcmp(word, "gametyperules")) + gametyperules = (UINT32)luaL_checkinteger(L, 2); + else if (fastcmp(word, "redscore")) redscore = (UINT32)luaL_checkinteger(L, 2); else if (fastcmp(word, "bluescore")) bluescore = (UINT32)luaL_checkinteger(L, 2); From 630c06b7b0a40b99d04d04f07903d78d41cab8a7 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 23 Dec 2019 19:24:06 -0300 Subject: [PATCH 165/195] Turn GTR_CHASECAM into GTR_FIRSTPERSON. --- src/dehacked.c | 2 +- src/doomstat.h | 6 +++--- src/g_game.c | 16 ++++++++-------- src/p_setup.c | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index d1e18a1d7..ee079aad1 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8870,7 +8870,7 @@ static const char *const GAMETYPERULE_LIST[] = { "HIDETIME", "HIDEFROZEN", "BLINDFOLDED", - "CHASECAM", + "FIRSTPERSON", "MATCHEMERALDS", "TEAMFLAGS", "PITYSHIELD", diff --git a/src/doomstat.h b/src/doomstat.h index 0ab8c1bff..940d2d60c 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -389,7 +389,7 @@ enum GameType // Game type rules enum GameTypeRules { - GTR_CAMPAIGN = 1, // Linear Co-op map progression. Don't allow random maps. + GTR_CAMPAIGN = 1, // Linear Co-op map progression, don't allow random maps GTR_RINGSLINGER = 1<<1, // Outside of Co-op, Competition, and Race (overriden by cv_ringslinger) GTR_SPECTATORS = 1<<2, // Outside of Co-op, Competition, and Race GTR_FRIENDLYFIRE = 1<<3, // Always allow friendly fire @@ -402,12 +402,12 @@ enum GameTypeRules GTR_HIDETIME = 1<<10, // Hide time (Tag and Hide and Seek) GTR_HIDEFROZEN = 1<<11, // Frozen after hide time (Hide and Seek, but not Tag) GTR_BLINDFOLDED = 1<<12, // Blindfolded view (Tag and Hide and Seek) - GTR_CHASECAM = 1<<13, // Prefer chasecam at map load (All platform gametypes) + GTR_FIRSTPERSON = 1<<13, // First person camera GTR_MATCHEMERALDS = 1<<14, // Ringslinger emeralds (Match and CTF) GTR_TEAMFLAGS = 1<<15, // Gametype has team flags (CTF) GTR_PITYSHIELD = 1<<16, // Award pity shield GTR_DEATHPENALTY = 1<<17, // Death score penalty - GTR_NOSPECTATORSPAWN = 1<<18, // For use with GTR_SPECTATORS - spawn in the map instead of with the spectators + GTR_NOSPECTATORSPAWN = 1<<18, // Use with GTR_SPECTATORS, spawn in the map instead of with the spectators GTR_DEATHMATCHSTARTS = 1<<19, // Use deathmatch starts GTR_SPECIALSTAGES = 1<<20, // Allow special stages GTR_EMERALDTOKENS = 1<<21, // Spawn emerald tokens diff --git a/src/g_game.c b/src/g_game.c index b29824b1c..34524c8f9 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3167,24 +3167,24 @@ const char *Gametype_ConstantNames[NUMGAMETYPES] = UINT32 gametypedefaultrules[NUMGAMETYPES] = { // Co-op - GTR_CAMPAIGN|GTR_LIVES|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_EMERALDHUNT|GTR_EMERALDTOKENS|GTR_SPECIALSTAGES, + GTR_CAMPAIGN|GTR_LIVES|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_EMERALDHUNT|GTR_EMERALDTOKENS|GTR_SPECIALSTAGES, // Competition - GTR_RACE|GTR_LIVES|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_EMERALDTOKENS|GTR_ALLOWEXIT, + GTR_RACE|GTR_LIVES|GTR_SPAWNENEMIES|GTR_EMERALDTOKENS|GTR_ALLOWEXIT, // Race - GTR_RACE|GTR_CHASECAM|GTR_SPAWNENEMIES|GTR_ALLOWEXIT, + GTR_RACE|GTR_SPAWNENEMIES|GTR_ALLOWEXIT, // Match - GTR_RINGSLINGER|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_MATCHEMERALDS|GTR_PITYSHIELD|GTR_DEATHPENALTY, + GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_MATCHEMERALDS|GTR_PITYSHIELD|GTR_DEATHPENALTY, // Team Match - GTR_RINGSLINGER|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_PITYSHIELD, + GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_PITYSHIELD, // Tag - GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED, + GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED, // Hide and Seek - GTR_RINGSLINGER|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED, + GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED, // CTF - GTR_RINGSLINGER|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_MATCHEMERALDS|GTR_TEAMFLAGS|GTR_PITYSHIELD, + GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_MATCHEMERALDS|GTR_TEAMFLAGS|GTR_PITYSHIELD, }; // diff --git a/src/p_setup.c b/src/p_setup.c index 821f8bcd5..34f0cf882 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2673,7 +2673,7 @@ boolean P_SetupLevel(boolean skipprecip) // chasecam on in chaos, race, coop // chasecam off in match, tag, capture the flag - chase = (gametyperules & GTR_CHASECAM) || (maptol & TOL_2D); + chase = (!(gametyperules & GTR_FIRSTPERSON)) || (maptol & TOL_2D); if (!dedicated) { From ffd6cf4acad17ba5f1c60a42dcf19d56e2f75db3 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Tue, 24 Dec 2019 00:10:29 +0100 Subject: [PATCH 166/195] Replaced functions for spawning premade rows of rings with a function for spawning a generic row of rings (groundwork for UDMF) --- src/p_mobj.c | 76 ++++++++++------------------------------------------ 1 file changed, 14 insertions(+), 62 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index b4ac43e21..f25690ed8 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -13231,58 +13231,13 @@ static void P_SpawnRingItem(mapthing_t *mthing, fixed_t x, fixed_t y, boolean bo P_SetMobjState(mobj, mobj->info->seestate); } -static void P_SpawnVerticalSpringRings(mapthing_t *mthing, fixed_t x, fixed_t y, fixed_t z) -{ - mobjtype_t ringthing = MT_RING; - mobj_t* mobj = NULL; - INT32 r; - - INT32 dist = 64*FRACUNIT; - if (mthing->type == 601) - dist = 128*FRACUNIT; - - if (ultimatemode) - return; // No rings in Ultimate! - - if (nightsreplace) - ringthing = MT_NIGHTSSTAR; - - z = P_GetMobjSpawnHeight(ringthing, x, y, z, mthing->options & MTF_OBJECTFLIP); - - for (r = 1; r <= 5; r++) - { - if (mthing->options & MTF_OBJECTFLIP) - z -= dist; - else - z += dist; - - mobj = P_SpawnMobj(x, y, z, ringthing); - - if (mthing->options & MTF_OBJECTFLIP) - { - mobj->eflags |= MFE_VERTICALFLIP; - mobj->flags2 |= MF2_OBJECTFLIP; - } - - mobj->angle = FixedAngle(mthing->angle << FRACBITS); - if (mthing->options & MTF_AMBUSH) - mobj->flags2 |= MF2_AMBUSH; - - if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR)) - P_SetMobjState(mobj, mobj->info->seestate); - } -} - -static void P_SpawnDiagonalSpringRings(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z) +static void P_SpawnItemRow(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z, INT32 numitems, fixed_t horizontalspacing, fixed_t verticalspacing, INT16 fixedangle) { mobjtype_t ringthing = MT_RING; mobj_t *mobj = NULL; INT32 r; - angle_t closestangle, fa; - - INT32 iterations = 5; - if (mthing->type == 603) - iterations = 10; + angle_t angle = FixedAngle(fixedangle << FRACBITS); + angle_t fineangle = (angle >> ANGLETOFINESHIFT) & FINEMASK; if (ultimatemode) return; // No rings in Ultimate! @@ -13290,20 +13245,13 @@ static void P_SpawnDiagonalSpringRings(mapthing_t* mthing, fixed_t x, fixed_t y, if (nightsreplace) ringthing = MT_NIGHTSSTAR; - closestangle = FixedAngle(mthing->angle << FRACBITS); - fa = (closestangle >> ANGLETOFINESHIFT); - z = P_GetMobjSpawnHeight(ringthing, x, y, z, mthing->options & MTF_OBJECTFLIP); - for (r = 1; r <= iterations; r++) + for (r = 0; r < numitems; r++) { - x += FixedMul(64*FRACUNIT, FINECOSINE(fa)); - y += FixedMul(64*FRACUNIT, FINESINE(fa)); - - if (mthing->options & MTF_OBJECTFLIP) - z -= 64*FRACUNIT; - else - z += 64*FRACUNIT; + x += FixedMul(horizontalspacing, FINECOSINE(fineangle)); + y += FixedMul(horizontalspacing, FINESINE(fineangle)); + z += (mthing->options & MTF_OBJECTFLIP) ? -verticalspacing : verticalspacing; mobj = P_SpawnMobj(x, y, z, ringthing); @@ -13313,7 +13261,7 @@ static void P_SpawnDiagonalSpringRings(mapthing_t* mthing, fixed_t x, fixed_t y, mobj->flags2 |= MF2_OBJECTFLIP; } - mobj->angle = closestangle; + mobj->angle = angle; if (mthing->options & MTF_AMBUSH) mobj->flags2 |= MF2_AMBUSH; @@ -13414,12 +13362,16 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) { // Special placement patterns case 600: // 5 vertical rings (yellow spring) + P_SpawnItemRow(mthing, x, y, z, 5, 0, 64*FRACUNIT, 0); + return; case 601: // 5 vertical rings (red spring) - P_SpawnVerticalSpringRings(mthing, x, y, z); + P_SpawnItemRow(mthing, x, y, z, 5, 0, 128*FRACUNIT, 0); return; case 602: // 5 diagonal rings (yellow spring) + P_SpawnItemRow(mthing, x, y, z, 5, 64*FRACUNIT, 64*FRACUNIT, mthing->angle); + return; case 603: // 10 diagonal rings (red spring) - P_SpawnDiagonalSpringRings(mthing, x, y, z); + P_SpawnItemRow(mthing, x, y, z, 10, 64*FRACUNIT, 64*FRACUNIT, mthing->angle); return; case 604: // Circle of rings (8 items) case 605: // Circle of rings (16 items) From a657392d397cb71af3851be3ae08788fd8c338e2 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 23 Dec 2019 20:22:57 -0300 Subject: [PATCH 167/195] ViewpointSwitch improvements. --- src/d_clisrv.c | 14 +++++++++++--- src/d_netcmd.c | 8 ++++++++ src/g_game.c | 25 ++++++++++++++++++------- src/lua_hook.h | 2 +- src/lua_hooklib.c | 12 +++++++----- src/p_user.c | 14 ++++++++++++++ 6 files changed, 59 insertions(+), 16 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index c0dec7ff7..cad27f52c 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2486,6 +2486,17 @@ static void CL_RemovePlayer(INT32 playernum, INT32 reason) (void)reason; #endif + // don't look through someone's view who isn't there + if (playernum == displayplayer) + { +#ifdef HAVE_BLUA + // Call ViewpointSwitch hooks here. + // The viewpoint was forcibly changed. + LUAh_ViewpointSwitch(&players[consoleplayer], &players[displayplayer], true); +#endif + displayplayer = consoleplayer; + } + // Reset player data CL_ClearPlayer(playernum); @@ -2503,9 +2514,6 @@ static void CL_RemovePlayer(INT32 playernum, INT32 reason) RemoveAdminPlayer(playernum); // don't stay admin after you're gone } - if (playernum == displayplayer) - displayplayer = consoleplayer; // don't look through someone's view who isn't there - #ifdef HAVE_BLUA LUA_InvalidatePlayer(&players[playernum]); #endif diff --git a/src/d_netcmd.c b/src/d_netcmd.c index be8b90c78..4e14ca25f 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2900,7 +2900,15 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) //reset view if you are changed, or viewing someone who was changed. if (playernum == consoleplayer || displayplayer == playernum) + { +#ifdef HAVE_BLUA + // Call ViewpointSwitch hooks here. + // The viewpoint was forcibly changed. + if (displayplayer != consoleplayer) // You're already viewing yourself. No big deal. + LUAh_ViewpointSwitch(&players[playernum], &players[displayplayer], true); +#endif displayplayer = consoleplayer; + } if (G_GametypeHasTeams()) { diff --git a/src/g_game.c b/src/g_game.c index 34524c8f9..ead7e8c5c 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1379,7 +1379,14 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) //Reset away view if a command is given. if ((cmd->forwardmove || cmd->sidemove || cmd->buttons) && displayplayer != consoleplayer) + { +#ifdef HAVE_BLUA + // Call ViewpointSwitch hooks here. + // The viewpoint was forcibly changed. + LUAh_ViewpointSwitch(player, &players[displayplayer], true); +#endif displayplayer = consoleplayer; + } } // like the g_buildticcmd 1 but using mouse2, gamcontrolbis, ... @@ -2021,6 +2028,11 @@ boolean G_Responder(event_t *ev) if (gamestate == GS_LEVEL && ev->type == ev_keydown && (ev->data1 == KEY_F12 || ev->data1 == gamecontrol[gc_viewpoint][0] || ev->data1 == gamecontrol[gc_viewpoint][1])) { + // ViewpointSwitch Lua hook. +#ifdef HAVE_BLUA + UINT8 canSwitchView = 0; +#endif + if (splitscreen || !netgame) displayplayer = consoleplayer; else @@ -2036,13 +2048,12 @@ boolean G_Responder(event_t *ev) continue; #ifdef HAVE_BLUA - { - UINT8 canSwitchView = LUAh_ViewpointSwitch(&players[consoleplayer], &players[displayplayer]); - if (canSwitchView == 1) // Set viewpoint to this player - break; - else if (canSwitchView == 2) // Skip this player - continue; - } + // Call ViewpointSwitch hooks here. + canSwitchView = LUAh_ViewpointSwitch(&players[consoleplayer], &players[displayplayer], false); + if (canSwitchView == 1) // Set viewpoint to this player + break; + else if (canSwitchView == 2) // Skip this player + continue; #endif if (players[displayplayer].spectator) diff --git a/src/lua_hook.h b/src/lua_hook.h index 8d780490e..68efbce93 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -96,6 +96,6 @@ UINT8 LUAh_PlayerCanDamage(player_t *player, mobj_t *mobj); // Hook for P_Player void LUAh_PlayerQuit(player_t *plr, int reason); // Hook for player quitting void LUAh_IntermissionThinker(void); // Hook for Y_Ticker boolean LUAh_TeamSwitch(player_t *player, int newteam, boolean fromspectators, boolean tryingautobalance, boolean tryingscramble); // Hook for team switching in... uh.... -UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer); // Hook for spy mode in G_Responder +UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced); // Hook for spy mode #endif diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index d213bd307..5383cbf0b 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -1397,8 +1397,8 @@ boolean LUAh_TeamSwitch(player_t *player, int newteam, boolean fromspectators, b return canSwitchTeam; } -// Hook for spy mode in G_Responder -UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer) +// Hook for spy mode +UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced) { hook_p hookp; UINT8 canSwitchView = 0; // 0 = default, 1 = force yes, 2 = force no. @@ -1417,12 +1417,14 @@ UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer) { LUA_PushUserdata(gL, player, META_PLAYER); LUA_PushUserdata(gL, newdisplayplayer, META_PLAYER); + lua_pushboolean(gL, forced); } lua_pushfstring(gL, FMT_HOOKID, hookp->id); lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + if (lua_pcall(gL, 3, 1, 0)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); diff --git a/src/p_user.c b/src/p_user.c index c8a329c35..4dbea87e3 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -10380,7 +10380,14 @@ boolean P_SpectatorJoinGame(player_t *player) //Reset away view if (P_IsLocalPlayer(player) && displayplayer != consoleplayer) + { +#ifdef HAVE_BLUA + // Call ViewpointSwitch hooks here. + // The viewpoint was forcibly changed. + LUAh_ViewpointSwitch(player, &players[displayplayer], true); +#endif displayplayer = consoleplayer; + } if (changeto == 1) CONS_Printf(M_GetText("%s switched to the %c%s%c.\n"), player_names[player-players], '\x85', M_GetText("Red team"), '\x80'); @@ -10422,7 +10429,14 @@ boolean P_SpectatorJoinGame(player_t *player) //Reset away view if (P_IsLocalPlayer(player) && displayplayer != consoleplayer) + { +#ifdef HAVE_BLUA + // Call ViewpointSwitch hooks here. + // The viewpoint was forcibly changed. + LUAh_ViewpointSwitch(player, &players[displayplayer], true); +#endif displayplayer = consoleplayer; + } if (gametype != GT_COOP) CONS_Printf(M_GetText("%s entered the game.\n"), player_names[player-players]); From 40b0c853b7af09216df00fd1bd575c33b90ba6ab Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 23 Dec 2019 23:19:48 -0300 Subject: [PATCH 168/195] Add IDENTIFIER to gametype DeHackEd. --- src/dehacked.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/dehacked.c b/src/dehacked.c index ee079aad1..12aa8f970 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1158,6 +1158,11 @@ static void readgametype(MYFILE *f, char *gtname) INT16 newgtrankingstype = -1; int newgtinttype = 0; char gtdescription[441]; + char gtconst[MAXLINELEN]; + + // Empty strings. + gtdescription[0] = '\0'; + gtconst[0] = '\0'; do { @@ -1231,6 +1236,12 @@ static void readgametype(MYFILE *f, char *gtname) // GTR_ newgtrules = (UINT32)get_number(word2); } + // Identifier + else if (fastcmp(word, "IDENTIFIER")) + { + // GT_ + strncpy(gtconst, word2, MAXLINELEN); + } // Point and time limits else if (fastcmp(word, "DEFAULTPOINTLIMIT")) newgtpointlimit = (INT32)i; @@ -1297,6 +1308,8 @@ static void readgametype(MYFILE *f, char *gtname) } } } while (!myfeof(f)); // finish when the line is empty + + // Free strings. Z_Free(s); if (word2lwr) Z_Free(word2lwr); @@ -1325,7 +1338,9 @@ static void readgametype(MYFILE *f, char *gtname) Gametype_Names[newgtidx] = Z_StrDup((const char *)gtname); // Write the constant name. - G_AddGametypeConstant(newgtidx, (const char *)gtname); + if (gtconst[0] == '\0') + strncpy(gtconst, gtname, MAXLINELEN); + G_AddGametypeConstant(newgtidx, (const char *)gtconst); // Update gametype_cons_t accordingly. G_UpdateGametypeSelections(); From d76c4eaba8680a9484ad6b8d2c339b073ea868d3 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Tue, 24 Dec 2019 00:14:25 -0300 Subject: [PATCH 169/195] Fix Lua HUD library crashes. --- src/lua_hudlib.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 0c0e79261..12ae1b5fc 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -1056,13 +1056,16 @@ int LUA_HudLib(lua_State *L) lua_rawseti(L, -2, 2); // HUD[2] = game rendering functions array lua_newtable(L); - lua_rawseti(L, -2, 3); // HUD[2] = scores rendering functions array + lua_rawseti(L, -2, 3); // HUD[3] = scores rendering functions array lua_newtable(L); - lua_rawseti(L, -2, 4); // HUD[3] = title rendering functions array + lua_rawseti(L, -2, 4); // HUD[4] = intermission rendering functions array lua_newtable(L); - lua_rawseti(L, -2, 5); // HUD[4] = title card rendering functions array + lua_rawseti(L, -2, 5); // HUD[5] = title rendering functions array + + lua_newtable(L); + lua_rawseti(L, -2, 6); // HUD[6] = title card rendering functions array lua_setfield(L, LUA_REGISTRYINDEX, "HUD"); luaL_newmetatable(L, META_HUDINFO); From ce3f526a5e2a427b16945dbf93c88388504e9670 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Tue, 24 Dec 2019 10:25:38 +0100 Subject: [PATCH 170/195] Ignore '=' and ';' when tokenizing, for textmap reading's sake. --- src/m_misc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/m_misc.c b/src/m_misc.c index d97383385..847f24905 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -1784,6 +1784,7 @@ char *M_GetToken(const char *inputString) || stringToUse[startPos] == '\n' || stringToUse[startPos] == '\0' || stringToUse[startPos] == '"' // we're treating this as whitespace because SLADE likes adding it for no good reason + || stringToUse[startPos] == '=' || stringToUse[startPos] == ';' // UDMF TEXTMAP. || inComment != 0) && startPos < stringLength) { @@ -1852,6 +1853,7 @@ char *M_GetToken(const char *inputString) && stringToUse[endPos] != '{' && stringToUse[endPos] != '}' && stringToUse[endPos] != '"' // see above + && stringToUse[endPos] != '=' && stringToUse[endPos] != ';' // UDMF TEXTMAP. && inComment == 0) && endPos < stringLength) { From 36996c8c9124310fd4a86161a0d3c8238546698f Mon Sep 17 00:00:00 2001 From: Nev3r Date: Tue, 24 Dec 2019 10:27:23 +0100 Subject: [PATCH 171/195] Treat strings inside ""s as a single token. --- src/m_misc.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/m_misc.c b/src/m_misc.c index 847f24905..b12e7371d 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -1783,7 +1783,6 @@ char *M_GetToken(const char *inputString) || stringToUse[startPos] == '\r' || stringToUse[startPos] == '\n' || stringToUse[startPos] == '\0' - || stringToUse[startPos] == '"' // we're treating this as whitespace because SLADE likes adding it for no good reason || stringToUse[startPos] == '=' || stringToUse[startPos] == ';' // UDMF TEXTMAP. || inComment != 0) && startPos < stringLength) @@ -1842,6 +1841,23 @@ char *M_GetToken(const char *inputString) texturesToken[1] = '\0'; return texturesToken; } + // Return entire string within quotes, except without the quotes. + else if (stringToUse[startPos] == '"') + { + endPos = ++startPos; + while (stringToUse[endPos] != '"' && endPos < stringLength) + endPos++; + + texturesTokenLength = endPos++ - startPos; + // Assign the memory. Don't forget an extra byte for the end of the string! + texturesToken = (char *)Z_Malloc((texturesTokenLength+1)*sizeof(char),PU_STATIC,NULL); + // Copy the string. + M_Memcpy(texturesToken, stringToUse+startPos, (size_t)texturesTokenLength); + // Make the final character NUL. + texturesToken[texturesTokenLength] = '\0'; + + return texturesToken; + } // Now find the end of the token. This includes several additional characters that are okay to capture as one character, but not trailing at the end of another token. endPos = startPos + 1; @@ -1852,7 +1868,6 @@ char *M_GetToken(const char *inputString) && stringToUse[endPos] != ',' && stringToUse[endPos] != '{' && stringToUse[endPos] != '}' - && stringToUse[endPos] != '"' // see above && stringToUse[endPos] != '=' && stringToUse[endPos] != ';' // UDMF TEXTMAP. && inComment == 0) && endPos < stringLength) From dd01fce1a84710a772a04521378dd6945fac991e Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Tue, 24 Dec 2019 10:50:49 +0100 Subject: [PATCH 172/195] Separate P_SpawnHoopsAndRings into different functions: -Hoops are spawned in P_SpawnHoop -Item patterns are spawned in P_SpawnItemPattern -Ring-like items are spawned normally via P_SpawnMapThing -Bonus time items are spawned via P_SpawnBonusTimeItem, which is a wrapper for P_SpawnMapThing --- src/m_cheat.c | 32 ++++------- src/p_mobj.c | 152 +++++++++++++++++++++++--------------------------- src/p_mobj.h | 6 +- src/p_saveg.c | 2 +- src/p_setup.c | 43 ++++++-------- 5 files changed, 102 insertions(+), 133 deletions(-) diff --git a/src/m_cheat.c b/src/m_cheat.c index 0451a5fb3..3d1fe5b7e 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -1186,7 +1186,7 @@ void OP_NightsObjectplace(player_t *player) mt->options = (mt->options & ~(UINT16)cv_opflags.value) | (UINT16)cv_ophoopflags.value; mt->angle = (INT16)(mt->angle+(INT16)((FixedInt(FixedDiv(temp*FRACUNIT, 360*(FRACUNIT/256))))<<8)); - P_SpawnHoopsAndRings(mt, false); + P_SpawnHoop(mt); } // This places a bumper! @@ -1249,7 +1249,7 @@ void OP_NightsObjectplace(player_t *player) return; mt = OP_CreateNewMapThing(player, (UINT16)mobjinfo[MT_BLUESPHERE].doomednum, false); - P_SpawnHoopsAndRings(mt, false); + P_SpawnMapThing(mt); } // This places a ring! @@ -1260,7 +1260,7 @@ void OP_NightsObjectplace(player_t *player) return; mt = OP_CreateNewMapThing(player, (UINT16)mobjinfo[MT_RING].doomednum, false); - P_SpawnHoopsAndRings(mt, false); + P_SpawnMapThing(mt); } // This places a custom object as defined in the console cv_mapthingnum. @@ -1292,15 +1292,10 @@ void OP_NightsObjectplace(player_t *player) mt = OP_CreateNewMapThing(player, (UINT16)cv_mapthingnum.value, false); mt->angle = angle; - if (mt->type == 300 // Ring - || mt->type == 308 || mt->type == 309 // Team Rings - || mt->type == 1706 // Sphere - || (mt->type >= 600 && mt->type <= 609) // Placement patterns - || mt->type == 1705 || mt->type == 1713 // NiGHTS Hoops - || mt->type == 1800) // Mario Coin - { - P_SpawnHoopsAndRings(mt, false); - } + if (mt->type >= 600 && mt->type <= 609) // Placement patterns + P_SpawnItemPattern(mt, false); + else if (mt->type == 1705 || mt->type == 1713) // NiGHTS Hoops + P_SpawnHoop(mt); else P_SpawnMapThing(mt); } @@ -1437,15 +1432,10 @@ void OP_ObjectplaceMovement(player_t *player) return; mt = OP_CreateNewMapThing(player, (UINT16)spawnthing, ceiling); - if (mt->type == 300 // Ring - || mt->type == 308 || mt->type == 309 // Team Rings - || mt->type == 1706 // Nights Wing - || (mt->type >= 600 && mt->type <= 609) // Placement patterns - || mt->type == 1705 || mt->type == 1713 // NiGHTS Hoops - || mt->type == 1800) // Mario Coin - { - P_SpawnHoopsAndRings(mt, false); - } + if (mt->type >= 600 && mt->type <= 609) // Placement patterns + P_SpawnItemPattern(mt, false); + else if (mt->type == 1705 || mt->type == 1713) // NiGHTS Hoops + P_SpawnHoop(mt); else P_SpawnMapThing(mt); diff --git a/src/p_mobj.c b/src/p_mobj.c index f25690ed8..606c65014 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11711,15 +11711,6 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i) { switch (i) { - case MT_RING: - case MT_COIN: - case MT_REDTEAMRING: - case MT_BLUETEAMRING: - case MT_BLUESPHERE: - case MT_BOMBSPHERE: - case MT_NIGHTSSTAR: - case MT_NIGHTSCHIP: - return false; // These are handled in P_SpawnHoopsAndRings(). case MT_EMERALD1: case MT_EMERALD2: case MT_EMERALD3: @@ -11786,8 +11777,12 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i) } if (metalrecording) // Metal Sonic can't use these things. - if (mobjinfo[i].flags & (MF_ENEMY|MF_BOSS) || i == MT_TOKEN || i == MT_STARPOST) + { + if ((mobjinfo[i].flags & (MF_ENEMY|MF_BOSS)) || i == MT_TOKEN || i == MT_STARPOST + || i == MT_RING || i == MT_BLUETEAMRING || i == MT_REDTEAMRING || i == MT_COIN + || i == MT_BLUESPHERE || i == MT_BOMBSPHERE || i == MT_NIGHTSCHIP || i == MT_NIGHTSSTAR) return false; + } if (!G_PlatformGametype()) { @@ -11825,7 +11820,9 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i) if (ultimatemode) { - if (i == MT_PITY_BOX || i == MT_ELEMENTAL_BOX || i == MT_ATTRACT_BOX + if (i == MT_RING || i == MT_REDTEAMRING || i == MT_BLUETEAMRING + || i == MT_COIN || i == MT_NIGHTSSTAR || i == MT_NIGHTSCHIP + || i == MT_PITY_BOX || i == MT_ELEMENTAL_BOX || i == MT_ATTRACT_BOX || i == MT_FORCE_BOX || i == MT_ARMAGEDDON_BOX || i == MT_WHIRLWIND_BOX || i == MT_FLAMEAURA_BOX || i == MT_BUBBLEWRAP_BOX || i == MT_THUNDERCOIN_BOX || i == MT_RING_BOX || i == MT_STARPOST) @@ -11838,6 +11835,8 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i) return true; } +#define nightsreplace ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) + static mobjtype_t P_GetMobjtypeSubstitute(mapthing_t *mthing, mobjtype_t i) { // Altering monitor spawns via cvars @@ -11881,8 +11880,23 @@ static mobjtype_t P_GetMobjtypeSubstitute(mapthing_t *mthing, mobjtype_t i) } } - if (gametype != GT_CTF && (i == MT_RING_BLUEBOX || i == MT_RING_REDBOX)) - return MT_RING_BOX; + if (nightsreplace) + { + if (i == MT_RING || i == MT_REDTEAMRING || i == MT_BLUETEAMRING || i == MT_COIN) + return MT_NIGHTSSTAR; + + if (i == MT_BLUESPHERE) + return MT_NIGHTSCHIP; + } + + if (gametype != GT_CTF) + { + if (i == MT_BLUETEAMRING || i == MT_REDTEAMRING) + return MT_RING; + + if (i == MT_RING_BLUEBOX || i == MT_RING_REDBOX) + return MT_RING_BOX; + } if (modeattacking && i == MT_1UP_BOX) // 1UPs -->> Score TVs { @@ -12920,6 +12934,10 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean if (G_IsSpecialStage(gamemap)) P_SetMobjState(mobj, (mobj->type == MT_PUSH) ? S_GRAVWELLGREEN : S_GRAVWELLRED); break; + case MT_NIGHTSSTAR: + if (maptol & TOL_XMAS) + P_SetMobjState(mobj, mobj->info->seestate); + break; default: break; } @@ -12991,21 +13009,21 @@ static void P_SetObjectSpecial(mobj_t *mobj) // The fields of the mapthing should // already be in host byte order. // -void P_SpawnMapThing(mapthing_t *mthing) +mobj_t *P_SpawnMapThing(mapthing_t *mthing) { mobjtype_t i; - mobj_t *mobj; + mobj_t *mobj = NULL; fixed_t x, y, z; boolean doangle = true; if (!mthing->type) - return; // Ignore type-0 things as NOPs + return mobj; // Ignore type-0 things as NOPs if (mthing->type == 3328) // 3D Mode start Thing - return; + return mobj; if (!objectplacing && P_SpawnNonMobjMapThing(mthing)) - return; + return mobj; i = P_GetMobjtype(mthing->type); if (i == MT_UNKNOWN) @@ -13015,11 +13033,11 @@ void P_SpawnMapThing(mapthing_t *mthing) if (!objectplacing) { if (!P_AllowMobjSpawn(mthing, i)) - return; + return mobj; i = P_GetMobjtypeSubstitute(mthing, i); if (i == MT_NULL) // Don't spawn mobj - return; + return mobj; } // spawn it @@ -13031,7 +13049,7 @@ void P_SpawnMapThing(mapthing_t *mthing) mobj->spawnpoint = mthing; if (!P_SetupSpawnedMapThing(mthing, mobj, &doangle)) - return; + return mobj; if (doangle) mobj->angle = FixedAngle(mthing->angle<options & MTF_AMBUSH) && (mthing->options & MTF_OBJECTSPECIAL) @@ -13075,9 +13093,11 @@ void P_SpawnMapThing(mapthing_t *mthing) // Final set of not being able to draw nightsitems. if (mobj->flags & MF_NIGHTSITEM) mobj->flags2 |= MF2_DONTDRAW; + + return mobj; } -static void P_SpawnHoop(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z, INT32 hoopsize, fixed_t sizefactor) +static void P_SpawnHoopInternal(mapthing_t *mthing, INT32 hoopsize, fixed_t sizefactor) { mobj_t *mobj = NULL; mobj_t *nextmobj = NULL; @@ -13087,8 +13107,9 @@ static void P_SpawnHoop(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z, INT INT32 i; angle_t fa; TVector v, *res; - - z = P_GetMobjSpawnHeight(MT_HOOP, x, y, z, false); + fixed_t x = mthing->x << FRACBITS; + fixed_t y = mthing->y << FRACBITS; + fixed_t z = P_GetMobjSpawnHeight(MT_HOOP, x, y, mthing->z << FRACBITS, false); hoopcenter = P_SpawnMobj(x, y, z, MT_HOOPCENTER); hoopcenter->spawnpoint = mthing; @@ -13182,56 +13203,27 @@ static void P_SpawnHoop(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z, INT } while (hoopsize >= 8); } -#define nightsreplace ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) - -static void P_SpawnRingItem(mapthing_t *mthing, fixed_t x, fixed_t y, boolean bonustime) +void P_SpawnHoop(mapthing_t *mthing) { - mobjtype_t ringthing = MT_RING; - mobj_t *mobj = NULL; - fixed_t z; + if (metalrecording) + return; - // Which ringthing to use - if (mthing->type == mobjinfo[MT_BLUESPHERE].doomednum) - ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE; - else if (mthing->type == mobjinfo[MT_BOMBSPHERE].doomednum) - ringthing = MT_BOMBSPHERE; - else - { - if (ultimatemode) - return; // No rings in Ultimate! - - if (nightsreplace) - ringthing = MT_NIGHTSSTAR; - else if (mthing->type == mobjinfo[MT_COIN].doomednum) - ringthing = MT_COIN; - else if (mthing->type == mobjinfo[MT_REDTEAMRING].doomednum) // No team rings in non-CTF - ringthing = (gametype == GT_CTF) ? MT_REDTEAMRING : MT_RING; - else if (mthing->type == mobjinfo[MT_BLUETEAMRING].doomednum) // Ditto - ringthing = (gametype == GT_CTF) ? MT_BLUETEAMRING : MT_RING; - } - - z = P_GetMapThingSpawnHeight(ringthing, mthing, x, y); - mobj = P_SpawnMobj(x, y, z, ringthing); - mobj->spawnpoint = mthing; - - if (mthing->options & MTF_OBJECTFLIP) - { - mobj->eflags |= MFE_VERTICALFLIP; - mobj->flags2 |= MF2_OBJECTFLIP; - } - - mobj->angle = FixedAngle(mthing->angle << FRACBITS); - mthing->mobj = mobj; - if (mthing->options & MTF_AMBUSH) - mobj->flags2 |= MF2_AMBUSH; - - if (bonustime && (ringthing == MT_BLUESPHERE || ringthing == MT_NIGHTSCHIP)) - P_SetMobjState(mobj, mobj->info->raisestate); - else if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR)) - P_SetMobjState(mobj, mobj->info->seestate); + if (mthing->type == 1705) // Generic hoop + P_SpawnHoopInternal(mthing, 24, 4*FRACUNIT); + else // Customizable hoop + // For each flag add 16 fracunits to the size + // Default (0 flags) is 32 fracunits + P_SpawnHoopInternal(mthing, 8 + (4*(mthing->options & 0xF)), 4*FRACUNIT); } -static void P_SpawnItemRow(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z, INT32 numitems, fixed_t horizontalspacing, fixed_t verticalspacing, INT16 fixedangle) +void P_SpawnBonusTimeItem(mapthing_t *mthing) +{ + mobj_t *mobj = P_SpawnMapThing(mthing); + if (mobj && (mobj->type == MT_BLUESPHERE || mobj->type == MT_NIGHTSCHIP)) + P_SetMobjState(mobj, mobj->info->raisestate); +} + +static void P_SpawnItemRow(mapthing_t *mthing, fixed_t x, fixed_t y, fixed_t z, INT32 numitems, fixed_t horizontalspacing, fixed_t verticalspacing, INT16 fixedangle) { mobjtype_t ringthing = MT_RING; mobj_t *mobj = NULL; @@ -13270,7 +13262,7 @@ static void P_SpawnItemRow(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z, } } -static void P_SpawnItemCircle(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z, INT32 numitems, fixed_t size, boolean bonustime) +static void P_SpawnItemCircle(mapthing_t *mthing, fixed_t x, fixed_t y, fixed_t z, INT32 numitems, fixed_t size, boolean bonustime) { mobjtype_t ringthing = MT_RING; mobj_t *mobj = NULL; @@ -13352,12 +13344,15 @@ static void P_SpawnItemCircle(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t } } -void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) +void P_SpawnItemPattern(mapthing_t *mthing, boolean bonustime) { fixed_t x = mthing->x << FRACBITS; fixed_t y = mthing->y << FRACBITS; fixed_t z = mthing->z << FRACBITS; + if (metalrecording) + return; + switch (mthing->type) { // Special placement patterns @@ -13385,17 +13380,8 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) P_SpawnItemCircle(mthing, x, y, z, numitems, size, bonustime); return; } - // Hoops - case 1705: // Generic NiGHTS hoop - P_SpawnHoop(mthing, x, y, z, 24, 4*FRACUNIT); + default: return; - case 1713: // Customizable NiGHTS hoop - // For each flag add 16 fracunits to the size - // Default (0 flags) is 32 fracunits - P_SpawnHoop(mthing, x, y, z, 8 + (4*(mthing->options & 0xF)), 4*FRACUNIT); - return; - default: // All manners of rings and coins - P_SpawnRingItem(mthing, x, y, bonustime); } } diff --git a/src/p_mobj.h b/src/p_mobj.h index 40d850f16..9b015d23c 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -456,8 +456,10 @@ void P_MovePlayerToSpawn(INT32 playernum, mapthing_t *mthing); void P_MovePlayerToStarpost(INT32 playernum); void P_AfterPlayerSpawn(INT32 playernum); -void P_SpawnMapThing(mapthing_t *mthing); -void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime); +mobj_t *P_SpawnMapThing(mapthing_t *mthing); +void P_SpawnHoop(mapthing_t *mthing); +void P_SpawnBonusTimeItem(mapthing_t *mthing); +void P_SpawnItemPattern(mapthing_t *mthing, boolean bonustime); void P_SpawnHoopOfSomething(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, angle_t rotangle); void P_SpawnPrecipitation(void); void P_SpawnParaloop(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, statenum_t nstate, angle_t rotangle, boolean spawncenter); diff --git a/src/p_saveg.c b/src/p_saveg.c index c876713e4..86224d936 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -2545,7 +2545,7 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) if (mapthings[spawnpointnum].type == 1705 || mapthings[spawnpointnum].type == 1713) // NiGHTS Hoop special case { - P_SpawnHoopsAndRings(&mapthings[spawnpointnum], false); + P_SpawnHoop(&mapthings[spawnpointnum]); return NULL; } diff --git a/src/p_setup.c b/src/p_setup.c index bc736588e..46fe118c4 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -765,7 +765,7 @@ static void P_LoadRawNodes(UINT8 *data) // // P_ReloadRings -// Used by NiGHTS, clears all ring/wing/etc items and respawns them +// Used by NiGHTS, clears all ring/sphere/hoop/etc items and respawns them // void P_ReloadRings(void) { @@ -812,18 +812,21 @@ void P_ReloadRings(void) { // Notice an omission? We handle hoops differently. if (mt->type == mobjinfo[MT_RING].doomednum || mt->type == mobjinfo[MT_COIN].doomednum - || mt->type == mobjinfo[MT_REDTEAMRING].doomednum || mt->type == mobjinfo[MT_BLUETEAMRING].doomednum - || mt->type == mobjinfo[MT_BLUESPHERE].doomednum || mt->type == mobjinfo[MT_BOMBSPHERE].doomednum - || (mt->type >= 600 && mt->type <= 609)) // circles and diagonals + || mt->type == mobjinfo[MT_REDTEAMRING].doomednum || mt->type == mobjinfo[MT_BLUETEAMRING].doomednum + || mt->type == mobjinfo[MT_BLUESPHERE].doomednum || mt->type == mobjinfo[MT_BOMBSPHERE].doomednum) { mt->mobj = NULL; - - P_SpawnHoopsAndRings(mt, true); + P_SpawnBonusTimeItem(mt); + } + else if (mt->type >= 600 && mt->type <= 609) // Item patterns + { + mt->mobj = NULL; + P_SpawnItemPattern(mt, true); } } for (i = 0; i < numHoops; i++) { - P_SpawnHoopsAndRings(hoopsToRespawn[i], false); + P_SpawnHoop(hoopsToRespawn[i]); } } @@ -1017,30 +1020,18 @@ static void P_LoadThings(boolean loademblems) continue; mt->mobj = NULL; - P_SpawnMapThing(mt); + + if (mt->type >= 600 && mt->type <= 609) // item patterns + P_SpawnItemPattern(mt, false); + else if (mt->type == 1705 || mt->type == 1713) // hoops + P_SpawnHoop(mt); + else // Everything else + P_SpawnMapThing(mt); } // random emeralds for hunt if (numhuntemeralds) P_SpawnEmeraldHunt(); - - if (metalrecording) // Metal Sonic gets no rings to distract him. - return; - - // Run through the list of mapthings again to spawn hoops and rings - mt = mapthings; - for (i = 0; i < nummapthings; i++, mt++) - { - if (mt->type == mobjinfo[MT_RING].doomednum || mt->type == mobjinfo[MT_COIN].doomednum - || mt->type == mobjinfo[MT_REDTEAMRING].doomednum || mt->type == mobjinfo[MT_BLUETEAMRING].doomednum - || mt->type == mobjinfo[MT_BLUESPHERE].doomednum || mt->type == mobjinfo[MT_BOMBSPHERE].doomednum - || (mt->type >= 600 && mt->type <= 609) // circles and diagonals - || mt->type == 1705 || mt->type == 1713) // hoops - { - mt->mobj = NULL; - P_SpawnHoopsAndRings(mt, false); - } - } } // Experimental groovy write function! From 2dac47a54c4757871f5b8ee907ddd96b2daaf664 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Tue, 24 Dec 2019 12:19:13 +0100 Subject: [PATCH 173/195] Allow P_SpawnItemRow to spawn arbitrary mobjtypes (will be used in UDMF) --- src/p_mobj.c | 173 +++++++++++++++++++++++++++------------------------ 1 file changed, 90 insertions(+), 83 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 606c65014..427f3526d 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11567,14 +11567,6 @@ static fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, if (mobjtype == MT_AXIS || mobjtype == MT_AXISTRANSFER || mobjtype == MT_AXISTRANSFERLINE) return ONFLOORZ; - if (!offset) // Snap to the surfaces when there's no offset set. - { - if (flip) - return ONCEILINGZ; - else - return ONFLOORZ; - } - // Establish height. if (flip) return ( @@ -11649,6 +11641,14 @@ static fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthin offset += mthing->options & MTF_AMBUSH ? 24*FRACUNIT : 0; } + if (!offset) // Snap to the surfaces when there's no offset set. + { + if (flip) + return ONCEILINGZ; + else + return ONFLOORZ; + } + return P_GetMobjSpawnHeight(mobjtype, x, y, offset, flip); } @@ -11703,6 +11703,13 @@ static boolean P_SpawnNonMobjMapThing(mapthing_t *mthing) || (mthing->type >= 600 && mthing->type <= 609) // Special placement patterns || mthing->type == 1705 || mthing->type == 1713) // Hoops return true; // These are handled elsewhere. + else if (mthing->type == mobjinfo[MT_EMERHUNT].doomednum) + { + // Emerald Hunt is Coop only. Don't spawn the emerald yet, but save the spawnpoint for later. + if (gametype == GT_COOP && numhuntemeralds < MAXHUNTEMERALDS) + huntemeralds[numhuntemeralds++] = mthing; + return true; + } return false; } @@ -11728,14 +11735,6 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i) return false; break; - case MT_EMERHUNT: - // Emerald Hunt is Coop only. - if (gametype != GT_COOP) - return false; - - if (numhuntemeralds < MAXHUNTEMERALDS) - huntemeralds[numhuntemeralds++] = mthing; - return false; case MT_EMERALDSPAWN: if (!cv_powerstones.value) return false; @@ -13004,47 +13003,12 @@ static void P_SetObjectSpecial(mobj_t *mobj) mobj->flags |= MF_BOUNCE; } } -// -// P_SpawnMapThing -// The fields of the mapthing should -// already be in host byte order. -// -mobj_t *P_SpawnMapThing(mapthing_t *mthing) + +mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y, fixed_t z, mobjtype_t i) { - mobjtype_t i; mobj_t *mobj = NULL; - fixed_t x, y, z; boolean doangle = true; - if (!mthing->type) - return mobj; // Ignore type-0 things as NOPs - - if (mthing->type == 3328) // 3D Mode start Thing - return mobj; - - if (!objectplacing && P_SpawnNonMobjMapThing(mthing)) - return mobj; - - i = P_GetMobjtype(mthing->type); - if (i == MT_UNKNOWN) - CONS_Alert(CONS_WARNING, M_GetText("Unknown thing type %d placed at (%d, %d)\n"), mthing->type, mthing->x, mthing->y); - - // Skip all returning/substitution code in objectplace. - if (!objectplacing) - { - if (!P_AllowMobjSpawn(mthing, i)) - return mobj; - - i = P_GetMobjtypeSubstitute(mthing, i); - if (i == MT_NULL) // Don't spawn mobj - return mobj; - } - - // spawn it - x = mthing->x << FRACBITS; - y = mthing->y << FRACBITS; - z = P_GetMapThingSpawnHeight(i, mthing, x, y); - mobj = P_SpawnMobj(x, y, z, i); mobj->spawnpoint = mthing; @@ -13052,7 +13016,7 @@ mobj_t *P_SpawnMapThing(mapthing_t *mthing) return mobj; if (doangle) - mobj->angle = FixedAngle(mthing->angle<angle = FixedAngle(mthing->angle << FRACBITS); mthing->mobj = mobj; @@ -13061,8 +13025,8 @@ mobj_t *P_SpawnMapThing(mapthing_t *mthing) return mobj; if ((mthing->options & MTF_AMBUSH) - && (mthing->options & MTF_OBJECTSPECIAL) - && (mobj->flags & MF_PUSHABLE)) + && (mthing->options & MTF_OBJECTSPECIAL) + && (mobj->flags & MF_PUSHABLE)) mobj->flags2 |= MF2_CLASSICPUSH; else { @@ -13097,6 +13061,47 @@ mobj_t *P_SpawnMapThing(mapthing_t *mthing) return mobj; } +// +// P_SpawnMapThing +// The fields of the mapthing should +// already be in host byte order. +// +mobj_t *P_SpawnMapThing(mapthing_t *mthing) +{ + mobjtype_t i; + mobj_t *mobj = NULL; + fixed_t x, y, z; + + if (!mthing->type) + return mobj; // Ignore type-0 things as NOPs + + if (mthing->type == 3328) // 3D Mode start Thing + return mobj; + + if (!objectplacing && P_SpawnNonMobjMapThing(mthing)) + return mobj; + + i = P_GetMobjtype(mthing->type); + if (i == MT_UNKNOWN) + CONS_Alert(CONS_WARNING, M_GetText("Unknown thing type %d placed at (%d, %d)\n"), mthing->type, mthing->x, mthing->y); + + // Skip all returning/substitution code in objectplace. + if (!objectplacing) + { + if (!P_AllowMobjSpawn(mthing, i)) + return mobj; + + i = P_GetMobjtypeSubstitute(mthing, i); + if (i == MT_NULL) // Don't spawn mobj + return mobj; + } + + x = mthing->x << FRACBITS; + y = mthing->y << FRACBITS; + z = P_GetMapThingSpawnHeight(i, mthing, x, y); + return P_SpawnMobjFromMapThing(mthing, x, y, z, i); +} + static void P_SpawnHoopInternal(mapthing_t *mthing, INT32 hoopsize, fixed_t sizefactor) { mobj_t *mobj = NULL; @@ -13223,21 +13228,29 @@ void P_SpawnBonusTimeItem(mapthing_t *mthing) P_SetMobjState(mobj, mobj->info->raisestate); } -static void P_SpawnItemRow(mapthing_t *mthing, fixed_t x, fixed_t y, fixed_t z, INT32 numitems, fixed_t horizontalspacing, fixed_t verticalspacing, INT16 fixedangle) +static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t itemtype, INT32 numitems, fixed_t horizontalspacing, fixed_t verticalspacing, INT16 fixedangle, boolean bonustime) { - mobjtype_t ringthing = MT_RING; + mapthing_t dummything = *mthing; mobj_t *mobj = NULL; + fixed_t x = mthing->x << FRACBITS; + fixed_t y = mthing->y << FRACBITS; + fixed_t z = mthing->z << FRACBITS; INT32 r; angle_t angle = FixedAngle(fixedangle << FRACBITS); angle_t fineangle = (angle >> ANGLETOFINESHIFT) & FINEMASK; - if (ultimatemode) - return; // No rings in Ultimate! + dummything.type = mobjinfo[itemtype].doomednum; + // Skip all returning/substitution code in objectplace. + if (!objectplacing) + { + if (!P_AllowMobjSpawn(&dummything, itemtype)) + return; - if (nightsreplace) - ringthing = MT_NIGHTSSTAR; - - z = P_GetMobjSpawnHeight(ringthing, x, y, z, mthing->options & MTF_OBJECTFLIP); + itemtype = P_GetMobjtypeSubstitute(&dummything, itemtype); + if (itemtype == MT_NULL) // Don't spawn + return; + } + z = P_GetMobjSpawnHeight(itemtype, x, y, z, mthing->options & MTF_OBJECTFLIP); for (r = 0; r < numitems; r++) { @@ -13245,20 +13258,14 @@ static void P_SpawnItemRow(mapthing_t *mthing, fixed_t x, fixed_t y, fixed_t z, y += FixedMul(horizontalspacing, FINESINE(fineangle)); z += (mthing->options & MTF_OBJECTFLIP) ? -verticalspacing : verticalspacing; - mobj = P_SpawnMobj(x, y, z, ringthing); + mobj = P_SpawnMobjFromMapThing(&dummything, x, y, z, itemtype); - if (mthing->options & MTF_OBJECTFLIP) - { - mobj->eflags |= MFE_VERTICALFLIP; - mobj->flags2 |= MF2_OBJECTFLIP; - } + if (!mobj) + continue; - mobj->angle = angle; - if (mthing->options & MTF_AMBUSH) - mobj->flags2 |= MF2_AMBUSH; - - if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR)) - P_SetMobjState(mobj, mobj->info->seestate); + mobj->spawnpoint = NULL; + if (bonustime && (mobj->type == MT_BLUESPHERE || mobj->type == MT_NIGHTSCHIP)) + P_SetMobjState(mobj, mobj->info->raisestate); } } @@ -13271,6 +13278,9 @@ static void P_SpawnItemCircle(mapthing_t *mthing, fixed_t x, fixed_t y, fixed_t INT32 i; TVector v, *res; + if (metalrecording) + return; + z = P_GetMobjSpawnHeight(ringthing, x, y, z, false); closestangle = FixedAngle(mthing->angle << FRACBITS); @@ -13350,23 +13360,20 @@ void P_SpawnItemPattern(mapthing_t *mthing, boolean bonustime) fixed_t y = mthing->y << FRACBITS; fixed_t z = mthing->z << FRACBITS; - if (metalrecording) - return; - switch (mthing->type) { // Special placement patterns case 600: // 5 vertical rings (yellow spring) - P_SpawnItemRow(mthing, x, y, z, 5, 0, 64*FRACUNIT, 0); + P_SpawnItemRow(mthing, MT_RING, 5, 0, 64*FRACUNIT, 0, bonustime); return; case 601: // 5 vertical rings (red spring) - P_SpawnItemRow(mthing, x, y, z, 5, 0, 128*FRACUNIT, 0); + P_SpawnItemRow(mthing, MT_RING, 5, 0, 128*FRACUNIT, 0, bonustime); return; case 602: // 5 diagonal rings (yellow spring) - P_SpawnItemRow(mthing, x, y, z, 5, 64*FRACUNIT, 64*FRACUNIT, mthing->angle); + P_SpawnItemRow(mthing, MT_RING, 5, 64*FRACUNIT, 64*FRACUNIT, mthing->angle, bonustime); return; case 603: // 10 diagonal rings (red spring) - P_SpawnItemRow(mthing, x, y, z, 10, 64*FRACUNIT, 64*FRACUNIT, mthing->angle); + P_SpawnItemRow(mthing, MT_RING, 10, 64*FRACUNIT, 64*FRACUNIT, mthing->angle, bonustime); return; case 604: // Circle of rings (8 items) case 605: // Circle of rings (16 items) From 72a1571937a6c4e33fb80b23969018b241769c71 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Tue, 24 Dec 2019 12:38:16 +0100 Subject: [PATCH 174/195] Allow P_SpawnItemCircle to spawn arbitrary mobjtypes (will be used in UDMF) --- src/p_mobj.c | 113 ++++++++++++++++++++------------------------------- 1 file changed, 45 insertions(+), 68 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 427f3526d..a72c59421 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -13269,97 +13269,66 @@ static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t itemtype, INT32 numite } } -static void P_SpawnItemCircle(mapthing_t *mthing, fixed_t x, fixed_t y, fixed_t z, INT32 numitems, fixed_t size, boolean bonustime) +static void P_SpawnItemCircle(mapthing_t *mthing, mobjtype_t *itemtypes, UINT8 numitemtypes, INT32 numitems, fixed_t size, boolean bonustime) { - mobjtype_t ringthing = MT_RING; - mobj_t *mobj = NULL; - fixed_t finalx, finaly, finalz; - angle_t closestangle, fa; + mapthing_t dummything; + mobj_t* mobj = NULL; + fixed_t x = mthing->x << FRACBITS; + fixed_t y = mthing->y << FRACBITS; + fixed_t z = mthing->z << FRACBITS; + angle_t angle = FixedAngle(mthing->angle << FRACBITS); + angle_t fa; INT32 i; TVector v, *res; - if (metalrecording) - return; - - z = P_GetMobjSpawnHeight(ringthing, x, y, z, false); - - closestangle = FixedAngle(mthing->angle << FRACBITS); - - switch (mthing->type) + for (i = 0; i < numitemtypes; i++) { - case 604: - case 605: - if (ultimatemode) - return; // No rings in Ultimate! - if (nightsreplace) - ringthing = MT_NIGHTSSTAR; - break; - case 608: - case 609: - /*ringthing = (i & 1) ? MT_RING : MT_BLUESPHERE; -- i == 0 is bluesphere - break;*/ - case 606: - case 607: - ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE; - break; - default: - break; - } + dummything = *mthing; + dummything.type = mobjinfo[itemtypes[i]].doomednum; + // Skip all returning/substitution code in objectplace. + if (!objectplacing) + { + if (!P_AllowMobjSpawn(&dummything, itemtypes[i])) + { + itemtypes[i] = MT_NULL; + continue; + } + + itemtypes[i] = P_GetMobjtypeSubstitute(&dummything, itemtypes[i]); + } + } + z = P_GetMobjSpawnHeight(itemtypes[0], x, y, z, false); - // Create the hoop! for (i = 0; i < numitems; i++) { - if (mthing->type == 608 || mthing->type == 609) - { - if (i & 1) - { - if (ultimatemode) - continue; // No rings in Ultimate! - ringthing = (nightsreplace) ? MT_NIGHTSSTAR : MT_RING; - } - else - ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE; - } + mobjtype_t itemtype = itemtypes[i % numitemtypes]; + if (itemtype == MT_NULL) + continue; + dummything.type = mobjinfo[itemtype].doomednum; - fa = i * FINEANGLES/numitems; + fa = i*FINEANGLES/numitems; v[0] = FixedMul(FINECOSINE(fa), size); v[1] = 0; v[2] = FixedMul(FINESINE(fa), size); v[3] = FRACUNIT; - res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle)); + res = VectorMatrixMultiply(v, *RotateZMatrix(angle)); M_Memcpy(&v, res, sizeof(v)); - finalx = x + v[0]; - finaly = y + v[1]; - finalz = z + v[2]; + mobj = P_SpawnMobjFromMapThing(&dummything, x + v[0], y + v[1], z + v[2], itemtype); + + if (!mobj) + continue; - mobj = P_SpawnMobj(finalx, finaly, finalz, ringthing); mobj->z -= mobj->height/2; - - if (mthing->options & MTF_OBJECTFLIP) - { - mobj->eflags |= MFE_VERTICALFLIP; - mobj->flags2 |= MF2_OBJECTFLIP; - } - - mobj->angle = closestangle; - if (mthing->options & MTF_AMBUSH) - mobj->flags2 |= MF2_AMBUSH; - - if (bonustime && (ringthing == MT_BLUESPHERE || ringthing == MT_NIGHTSCHIP)) + mobj->spawnpoint = NULL; + if (bonustime && (mobj->type == MT_BLUESPHERE || mobj->type == MT_NIGHTSCHIP)) P_SetMobjState(mobj, mobj->info->raisestate); - else if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR)) - P_SetMobjState(mobj, mobj->info->seestate); } } void P_SpawnItemPattern(mapthing_t *mthing, boolean bonustime) { - fixed_t x = mthing->x << FRACBITS; - fixed_t y = mthing->y << FRACBITS; - fixed_t z = mthing->z << FRACBITS; - switch (mthing->type) { // Special placement patterns @@ -13379,12 +13348,20 @@ void P_SpawnItemPattern(mapthing_t *mthing, boolean bonustime) case 605: // Circle of rings (16 items) case 606: // Circle of blue spheres (8 items) case 607: // Circle of blue spheres (16 items) + { + INT32 numitems = (mthing->type & 1) ? 16 : 8; + fixed_t size = (mthing->type & 1) ? 192*FRACUNIT : 96*FRACUNIT; + mobjtype_t itemtypes[1] = { (mthing->type & 1) ? MT_RING : MT_BLUESPHERE }; + P_SpawnItemCircle(mthing, itemtypes, 1, numitems, size, bonustime); + return; + } case 608: // Circle of rings and blue spheres (8 items) case 609: // Circle of rings and blue spheres (16 items) { INT32 numitems = (mthing->type & 1) ? 16 : 8; fixed_t size = (mthing->type & 1) ? 192*FRACUNIT : 96*FRACUNIT; - P_SpawnItemCircle(mthing, x, y, z, numitems, size, bonustime); + mobjtype_t itemtypes[2] = { MT_RING, MT_BLUESPHERE }; + P_SpawnItemCircle(mthing, itemtypes, 2, numitems, size, bonustime); return; } default: From ac3a57aaf54802b0942c4b4b9c97a940136fbb35 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Tue, 24 Dec 2019 12:47:44 +0100 Subject: [PATCH 175/195] Allow P_SpawnItemRow to spawn different item types in the same row --- src/p_mobj.c | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index a72c59421..88397e43b 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -13228,9 +13228,9 @@ void P_SpawnBonusTimeItem(mapthing_t *mthing) P_SetMobjState(mobj, mobj->info->raisestate); } -static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t itemtype, INT32 numitems, fixed_t horizontalspacing, fixed_t verticalspacing, INT16 fixedangle, boolean bonustime) +static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t* itemtypes, UINT8 numitemtypes, INT32 numitems, fixed_t horizontalspacing, fixed_t verticalspacing, INT16 fixedangle, boolean bonustime) { - mapthing_t dummything = *mthing; + mapthing_t dummything; mobj_t *mobj = NULL; fixed_t x = mthing->x << FRACBITS; fixed_t y = mthing->y << FRACBITS; @@ -13239,21 +13239,31 @@ static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t itemtype, INT32 numite angle_t angle = FixedAngle(fixedangle << FRACBITS); angle_t fineangle = (angle >> ANGLETOFINESHIFT) & FINEMASK; - dummything.type = mobjinfo[itemtype].doomednum; - // Skip all returning/substitution code in objectplace. - if (!objectplacing) + for (r = 0; r < numitemtypes; r++) { - if (!P_AllowMobjSpawn(&dummything, itemtype)) - return; + dummything = *mthing; + dummything.type = mobjinfo[itemtypes[r]].doomednum; + // Skip all returning/substitution code in objectplace. + if (!objectplacing) + { + if (!P_AllowMobjSpawn(&dummything, itemtypes[r])) + { + itemtypes[r] = MT_NULL; + continue; + } - itemtype = P_GetMobjtypeSubstitute(&dummything, itemtype); - if (itemtype == MT_NULL) // Don't spawn - return; + itemtypes[r] = P_GetMobjtypeSubstitute(&dummything, itemtypes[r]); + } } - z = P_GetMobjSpawnHeight(itemtype, x, y, z, mthing->options & MTF_OBJECTFLIP); + z = P_GetMobjSpawnHeight(itemtypes[0], x, y, z, mthing->options & MTF_OBJECTFLIP); for (r = 0; r < numitems; r++) { + mobjtype_t itemtype = itemtypes[r % numitemtypes]; + if (itemtype == MT_NULL) + continue; + dummything.type = mobjinfo[itemtype].doomednum; + x += FixedMul(horizontalspacing, FINECOSINE(fineangle)); y += FixedMul(horizontalspacing, FINESINE(fineangle)); z += (mthing->options & MTF_OBJECTFLIP) ? -verticalspacing : verticalspacing; @@ -13269,6 +13279,12 @@ static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t itemtype, INT32 numite } } +static void P_SpawnSingularItemRow(mapthing_t* mthing, mobjtype_t itemtype, INT32 numitems, fixed_t horizontalspacing, fixed_t verticalspacing, INT16 fixedangle, boolean bonustime) +{ + mobjtype_t itemtypes[1] = { itemtype }; + return P_SpawnItemRow(mthing, itemtypes, 1, numitems, horizontalspacing, verticalspacing, fixedangle, bonustime); +} + static void P_SpawnItemCircle(mapthing_t *mthing, mobjtype_t *itemtypes, UINT8 numitemtypes, INT32 numitems, fixed_t size, boolean bonustime) { mapthing_t dummything; @@ -13333,16 +13349,16 @@ void P_SpawnItemPattern(mapthing_t *mthing, boolean bonustime) { // Special placement patterns case 600: // 5 vertical rings (yellow spring) - P_SpawnItemRow(mthing, MT_RING, 5, 0, 64*FRACUNIT, 0, bonustime); + P_SpawnSingularItemRow(mthing, MT_RING, 5, 0, 64*FRACUNIT, 0, bonustime); return; case 601: // 5 vertical rings (red spring) - P_SpawnItemRow(mthing, MT_RING, 5, 0, 128*FRACUNIT, 0, bonustime); + P_SpawnSingularItemRow(mthing, MT_RING, 5, 0, 128*FRACUNIT, 0, bonustime); return; case 602: // 5 diagonal rings (yellow spring) - P_SpawnItemRow(mthing, MT_RING, 5, 64*FRACUNIT, 64*FRACUNIT, mthing->angle, bonustime); + P_SpawnSingularItemRow(mthing, MT_RING, 5, 64*FRACUNIT, 64*FRACUNIT, mthing->angle, bonustime); return; case 603: // 10 diagonal rings (red spring) - P_SpawnItemRow(mthing, MT_RING, 10, 64*FRACUNIT, 64*FRACUNIT, mthing->angle, bonustime); + P_SpawnSingularItemRow(mthing, MT_RING, 10, 64*FRACUNIT, 64*FRACUNIT, mthing->angle, bonustime); return; case 604: // Circle of rings (8 items) case 605: // Circle of rings (16 items) From a57f903933fd232dea79f3c3e02eaaa28e4ae355 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Tue, 24 Dec 2019 12:52:43 +0100 Subject: [PATCH 176/195] Move bonus time handling into new function P_SetBonusTime() --- src/p_mobj.c | 20 ++++++++++++-------- src/p_mobj.h | 2 +- src/p_setup.c | 2 +- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 88397e43b..866ffaf70 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -13221,11 +13221,15 @@ void P_SpawnHoop(mapthing_t *mthing) P_SpawnHoopInternal(mthing, 8 + (4*(mthing->options & 0xF)), 4*FRACUNIT); } -void P_SpawnBonusTimeItem(mapthing_t *mthing) +void P_SetBonusTime(mobj_t *mobj) { - mobj_t *mobj = P_SpawnMapThing(mthing); - if (mobj && (mobj->type == MT_BLUESPHERE || mobj->type == MT_NIGHTSCHIP)) - P_SetMobjState(mobj, mobj->info->raisestate); + if (!mobj) + return; + + if (mobj->type != MT_BLUESPHERE && mobj->type != MT_NIGHTSCHIP) + return; + + P_SetMobjState(mobj, mobj->info->raisestate); } static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t* itemtypes, UINT8 numitemtypes, INT32 numitems, fixed_t horizontalspacing, fixed_t verticalspacing, INT16 fixedangle, boolean bonustime) @@ -13274,8 +13278,8 @@ static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t* itemtypes, UINT8 numi continue; mobj->spawnpoint = NULL; - if (bonustime && (mobj->type == MT_BLUESPHERE || mobj->type == MT_NIGHTSCHIP)) - P_SetMobjState(mobj, mobj->info->raisestate); + if (bonustime) + P_SetBonusTime(mobj); } } @@ -13338,8 +13342,8 @@ static void P_SpawnItemCircle(mapthing_t *mthing, mobjtype_t *itemtypes, UINT8 n mobj->z -= mobj->height/2; mobj->spawnpoint = NULL; - if (bonustime && (mobj->type == MT_BLUESPHERE || mobj->type == MT_NIGHTSCHIP)) - P_SetMobjState(mobj, mobj->info->raisestate); + if (bonustime) + P_SetBonusTime(mobj); } } diff --git a/src/p_mobj.h b/src/p_mobj.h index 9b015d23c..a272003c1 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -458,7 +458,7 @@ void P_AfterPlayerSpawn(INT32 playernum); mobj_t *P_SpawnMapThing(mapthing_t *mthing); void P_SpawnHoop(mapthing_t *mthing); -void P_SpawnBonusTimeItem(mapthing_t *mthing); +void P_SetBonusTime(mobj_t *mobj); void P_SpawnItemPattern(mapthing_t *mthing, boolean bonustime); void P_SpawnHoopOfSomething(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, angle_t rotangle); void P_SpawnPrecipitation(void); diff --git a/src/p_setup.c b/src/p_setup.c index 46fe118c4..41d61704f 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -816,7 +816,7 @@ void P_ReloadRings(void) || mt->type == mobjinfo[MT_BLUESPHERE].doomednum || mt->type == mobjinfo[MT_BOMBSPHERE].doomednum) { mt->mobj = NULL; - P_SpawnBonusTimeItem(mt); + P_SetBonusTime(P_SpawnMapThing(mt)); } else if (mt->type >= 600 && mt->type <= 609) // Item patterns { From 13eb71e1ee5910f07eeae15931d2873f4ed9d576 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Tue, 24 Dec 2019 12:58:12 +0100 Subject: [PATCH 177/195] Fixed missing break in offset handling for horizontal springs --- src/p_mobj.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index 866ffaf70..13f75b94a 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11618,6 +11618,7 @@ static fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthin case MT_REDHORIZ: case MT_BLUEHORIZ: offset += mthing->options & MTF_AMBUSH ? 16*FRACUNIT : 0; + break; // Ring-like items, may float additional units with MTF_AMBUSH. case MT_SPIKEBALL: From 0aa3c9b0a3655ae0ef86b435991a2fa0e9ed1f7d Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Tue, 24 Dec 2019 13:01:17 +0100 Subject: [PATCH 178/195] Fixed missing break in offset handling for horizontal springs --- src/p_mobj.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index 1acecbb76..e8186b752 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11603,6 +11603,7 @@ static fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* case MT_REDHORIZ: case MT_BLUEHORIZ: offset += mthing->options & MTF_AMBUSH ? 16*FRACUNIT : 0; + break; // Ring-like items, may float additional units with MTF_AMBUSH. case MT_SPIKEBALL: From b740daf5bfc89b252ed2cf302af423323f77a44f Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Tue, 24 Dec 2019 16:09:00 -0300 Subject: [PATCH 179/195] GTR_HURTMESSAGES --- src/dehacked.c | 1 + src/doomstat.h | 1 + src/p_inter.c | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/dehacked.c b/src/dehacked.c index 12aa8f970..18c4077be 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8899,6 +8899,7 @@ static const char *const GAMETYPERULE_LIST[] = { "ALLOWEXIT", "NOTITLECARD", "OVERTIME", + "HURTMESSAGES", NULL }; diff --git a/src/doomstat.h b/src/doomstat.h index 940d2d60c..6a708dc9b 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -416,6 +416,7 @@ enum GameTypeRules GTR_ALLOWEXIT = 1<<24, // Allow exit sectors GTR_NOTITLECARD = 1<<25, // Don't show the title card GTR_OVERTIME = 1<<26, // Allow overtime + GTR_HURTMESSAGES = 1<<27, // Hit and death messages }; // String names for gametypes diff --git a/src/p_inter.c b/src/p_inter.c index 08e8a62a1..8643b4275 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1888,7 +1888,7 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour char targetname[MAXPLAYERNAME+4]; char sourcename[MAXPLAYERNAME+4]; - if (G_PlatformGametype()) + if (!(gametyperules & (GTR_RINGSLINGER|GTR_HURTMESSAGES))) return; // Not in coop, etc. if (!player) From 5b4d587b1ae9df2e3aed431429ddb617b733b68c Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Tue, 24 Dec 2019 16:12:05 -0300 Subject: [PATCH 180/195] Don't warn about missing CTF starts if the gametype doesn't have team flags. --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index ead7e8c5c..91e788e1c 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2720,7 +2720,7 @@ mapthing_t *G_FindCTFStart(INT32 playernum) if (!numredctfstarts && !numbluectfstarts) //why even bother, eh? { - if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer)) + if ((gametyperules & GTR_TEAMFLAGS) && (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer))) CONS_Alert(CONS_WARNING, M_GetText("No CTF starts in this map!\n")); return NULL; } From 9d28351b5ce78cdc61cd22fe751062534e355384 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 24 Dec 2019 11:14:21 -0800 Subject: [PATCH 181/195] I'm an idiot --- src/sdl/i_system.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index a5e536bf5..52186baae 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -675,7 +675,7 @@ static inline void I_ShutdownConsole(void){} // // StartupKeyboard // -void I_RegisterSignals (void) +static void I_RegisterSignals (void) { #ifdef SIGINT signal(SIGINT , quit_handler); From 9319014d8d5d80420dbcc926c8dfa349f5fc9e9d Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Tue, 24 Dec 2019 16:22:25 -0300 Subject: [PATCH 182/195] Title card fixes. --- src/g_game.c | 19 ++++++++++++++++++- src/g_game.h | 1 + src/st_stuff.c | 9 +++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 91e788e1c..32d69b301 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1895,7 +1895,7 @@ void G_StartTitleCard(void) // The title card has been disabled for this map. // Oh well. - if ((mapheaderinfo[gamemap-1]->levelflags & LF_NOTITLECARD) || (gametyperules & GTR_NOTITLECARD)) + if (!G_IsTitleCardAvailable()) { WipeStageTitle = false; return; @@ -1938,6 +1938,23 @@ void G_PreLevelTitleCard(void) } } +// +// Returns true if the current level has a title card. +// +boolean G_IsTitleCardAvailable(void) +{ + // The current level header explicitly disabled the title card. + if (mapheaderinfo[gamemap-1]->levelflags & LF_NOTITLECARD) + return false; + + // The current gametype doesn't have a title card. + if (gametyperules & GTR_NOTITLECARD) + return false; + + // The title card is available. + return true; +} + INT32 pausedelay = 0; boolean pausebreakkey = false; static INT32 camtoggledelay, camtoggledelay2 = 0; diff --git a/src/g_game.h b/src/g_game.h index 4e577f51a..238dd1964 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -143,6 +143,7 @@ void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar, void G_DoLoadLevel(boolean resetplayer); void G_StartTitleCard(void); void G_PreLevelTitleCard(void); +boolean G_IsTitleCardAvailable(void); void G_DeferedPlayDemo(const char *demo); // Can be called by the startup code or M_Responder, calls P_SetupLevel. diff --git a/src/st_stuff.c b/src/st_stuff.c index 6ff73e03a..3299c9d39 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1216,6 +1216,9 @@ void ST_startTitleCard(void) // void ST_preDrawTitleCard(void) { + if (!G_IsTitleCardAvailable()) + return; + if (lt_ticker >= (lt_endtime + TICRATE)) return; @@ -1231,6 +1234,9 @@ void ST_preDrawTitleCard(void) // void ST_runTitleCard(void) { + if (!G_IsTitleCardAvailable()) + return; + if (lt_ticker >= (lt_endtime + TICRATE)) return; @@ -1284,6 +1290,9 @@ void ST_drawTitleCard(void) INT32 zzticker; patch_t *actpat, *zigzag, *zztext; + if (!G_IsTitleCardAvailable()) + return; + #ifdef HAVE_BLUA if (!LUA_HudEnabled(hud_stagetitle)) goto luahook; From c61c1e2514588418d04c410784466cdae7ed9bdc Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Tue, 24 Dec 2019 16:30:18 -0300 Subject: [PATCH 183/195] Turn the babysitting deterrent into its own rule. --- src/dehacked.c | 1 + src/doomstat.h | 3 ++- src/g_game.c | 14 +++++++------- src/p_mobj.c | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 18c4077be..b598d40ac 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8900,6 +8900,7 @@ static const char *const GAMETYPERULE_LIST[] = { "NOTITLECARD", "OVERTIME", "HURTMESSAGES", + "SPAWNINVUL", NULL }; diff --git a/src/doomstat.h b/src/doomstat.h index 6a708dc9b..2e3fe9b36 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -386,7 +386,7 @@ enum GameType }; // If you alter this list, update dehacked.c, MISC_ChangeGameTypeMenu in m_menu.c, and Gametype_Names in g_game.c -// Game type rules +// Gametype rules enum GameTypeRules { GTR_CAMPAIGN = 1, // Linear Co-op map progression, don't allow random maps @@ -417,6 +417,7 @@ enum GameTypeRules GTR_NOTITLECARD = 1<<25, // Don't show the title card GTR_OVERTIME = 1<<26, // Allow overtime GTR_HURTMESSAGES = 1<<27, // Hit and death messages + GTR_SPAWNINVUL = 1<<28, // Babysitting deterrent }; // String names for gametypes diff --git a/src/g_game.c b/src/g_game.c index 32d69b301..b39205f50 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3197,22 +3197,22 @@ UINT32 gametypedefaultrules[NUMGAMETYPES] = // Co-op GTR_CAMPAIGN|GTR_LIVES|GTR_SPAWNENEMIES|GTR_ALLOWEXIT|GTR_EMERALDHUNT|GTR_EMERALDTOKENS|GTR_SPECIALSTAGES, // Competition - GTR_RACE|GTR_LIVES|GTR_SPAWNENEMIES|GTR_EMERALDTOKENS|GTR_ALLOWEXIT, + GTR_RACE|GTR_LIVES|GTR_SPAWNENEMIES|GTR_EMERALDTOKENS|GTR_SPAWNINVUL|GTR_ALLOWEXIT, // Race - GTR_RACE|GTR_SPAWNENEMIES|GTR_ALLOWEXIT, + GTR_RACE|GTR_SPAWNENEMIES|GTR_SPAWNINVUL|GTR_ALLOWEXIT, // Match - GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_MATCHEMERALDS|GTR_PITYSHIELD|GTR_DEATHPENALTY, + GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_MATCHEMERALDS|GTR_SPAWNINVUL|GTR_PITYSHIELD|GTR_DEATHPENALTY, // Team Match - GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_PITYSHIELD, + GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_SPAWNINVUL|GTR_PITYSHIELD, // Tag - GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED, + GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED|GTR_SPAWNINVUL, // Hide and Seek - GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED, + GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_TAG|GTR_SPECTATORS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_HIDETIME|GTR_BLINDFOLDED|GTR_SPAWNINVUL, // CTF - GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_MATCHEMERALDS|GTR_TEAMFLAGS|GTR_PITYSHIELD, + GTR_RINGSLINGER|GTR_FIRSTPERSON|GTR_SPECTATORS|GTR_TEAMS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_MATCHEMERALDS|GTR_TEAMFLAGS|GTR_SPAWNINVUL|GTR_PITYSHIELD, }; // diff --git a/src/p_mobj.c b/src/p_mobj.c index a10e6b3ba..d841ede05 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11297,7 +11297,7 @@ void P_SpawnPlayer(INT32 playernum) p->skincolor = skincolor_blueteam; } - if ((netgame || multiplayer) && (gametype != GT_COOP || leveltime) && !p->spectator && !(maptol & TOL_NIGHTS)) + if ((netgame || multiplayer) && ((gametyperules & GTR_SPAWNINVUL) || leveltime) && !p->spectator && !(maptol & TOL_NIGHTS)) p->powers[pw_flashing] = flashingtics-1; // Babysitting deterrent mobj = P_SpawnMobj(0, 0, 0, MT_PLAYER); From be063c454a7c8ecc4fbda2aa5079ea94c0c39500 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 24 Dec 2019 11:37:37 -0800 Subject: [PATCH 184/195] Fix NOPNG compiling --- src/r_data.c | 2 -- src/r_plane.c | 2 ++ src/sdl/mixer_sound.c | 38 ++++++++++++++++--------------- src/w_wad.c | 52 +++++++++++++++---------------------------- 4 files changed, 40 insertions(+), 54 deletions(-) diff --git a/src/r_data.c b/src/r_data.c index 12e0702c1..cecd4840c 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -536,9 +536,7 @@ static UINT8 *R_GenerateTexture(size_t texnum) } // multi-patch textures (or 'composite') -#ifndef NO_PNG_LUMPS multipatch: -#endif texture->holes = false; texture->flip = 0; blocksize = (texture->width * 4) + (texture->width * texture->height); diff --git a/src/r_plane.c b/src/r_plane.c index 3214fa23d..5d5e1f20d 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -788,6 +788,8 @@ static UINT8 *R_GetTextureFlat(levelflat_t *levelflat, boolean leveltexture, boo patch_t *patch = NULL; boolean texturechanged = (leveltexture ? (levelflat->u.texture.num != levelflat->u.texture.lastnum) : false); + (void)ispng; + // Check if the texture changed. if (leveltexture && (!texturechanged)) { diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index 369d04ced..b60dab14c 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -9,6 +9,26 @@ /// \file /// \brief SDL Mixer interface for sound +#ifdef HAVE_LIBGME +#ifdef HAVE_ZLIB +#ifndef _MSC_VER +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif +#endif + +#ifndef _LFS64_LARGEFILE +#define _LFS64_LARGEFILE +#endif + +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 0 +#endif + +#include +#endif // HAVE_ZLIB +#endif // HAVE_LIBGME + #include "../doomdef.h" #include "../doomstat.h" // menuactive @@ -57,24 +77,6 @@ #include "gme/gme.h" #define GME_TREBLE 5.0f #define GME_BASS 1.0f - -#ifdef HAVE_ZLIB -#ifndef _MSC_VER -#ifndef _LARGEFILE64_SOURCE -#define _LARGEFILE64_SOURCE -#endif -#endif - -#ifndef _LFS64_LARGEFILE -#define _LFS64_LARGEFILE -#endif - -#ifndef _FILE_OFFSET_BITS -#define _FILE_OFFSET_BITS 0 -#endif - -#include "zlib.h" -#endif // HAVE_ZLIB #endif // HAVE_LIBGME static UINT16 BUFFERSIZE = 2048; diff --git a/src/w_wad.c b/src/w_wad.c index 950294b1f..86972118a 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -11,6 +11,24 @@ /// \file w_wad.c /// \brief Handles WAD file header, directory, lump I/O +#ifdef HAVE_ZLIB +#ifndef _MSC_VER +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif +#endif + +#ifndef _LFS64_LARGEFILE +#define _LFS64_LARGEFILE +#endif + +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 0 +#endif + +#include +#endif + #ifdef __GNUC__ #include #endif @@ -22,22 +40,6 @@ #include "lzf.h" #endif -#ifndef _FILE_OFFSET_BITS -#define _FILE_OFFSET_BITS 0 -#endif - -#ifndef _LARGEFILE64_SOURCE -#define _LARGEFILE64_SOURCE -#endif - -#ifndef _LFS64_LARGEFILE -#define _LFS64_LARGEFILE -#endif - -//#ifdef HAVE_ZLIB -#include "zlib.h" -//#endif // HAVE_ZLIB - #include "doomdef.h" #include "doomstat.h" #include "doomtype.h" @@ -77,24 +79,6 @@ int snprintf(char *str, size_t n, const char *fmt, ...); #define O_BINARY 0 #endif -#ifdef HAVE_ZLIB -#ifndef _MSC_VER -#ifndef _LARGEFILE64_SOURCE -#define _LARGEFILE64_SOURCE -#endif -#endif - -#ifndef _LFS64_LARGEFILE -#define _LFS64_LARGEFILE -#endif - -#ifndef _FILE_OFFSET_BITS -#define _FILE_OFFSET_BITS 0 -#endif - -#include "zlib.h" -#endif - typedef struct { From ddccfbd73d58a73d3f35eaa53b09d25289ae402f Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Tue, 24 Dec 2019 21:07:55 +0100 Subject: [PATCH 185/195] P_MobjThinker(): Separate scale thinking and scenery thinking into their own functions --- src/p_mobj.c | 1714 ++++++++++++++++++++++++++------------------------ 1 file changed, 878 insertions(+), 836 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 13f75b94a..ab435afce 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7143,6 +7143,881 @@ static void P_PyreFlyBurn(mobj_t *mobj, fixed_t hoffs, INT16 vrange, mobjtype_t particle->momz = momz; } +static void P_MobjScaleThink(mobj_t *mobj) +{ + fixed_t oldheight = mobj->height; + UINT8 correctionType = 0; // Don't correct Z position, just gain height + + if ((mobj->flags & MF_NOCLIPHEIGHT || (mobj->z > mobj->floorz && mobj->z + mobj->height < mobj->ceilingz)) + && mobj->type != MT_EGGMOBILE_FIRE) + correctionType = 1; // Correct Z position by centering + else if (mobj->eflags & MFE_VERTICALFLIP) + correctionType = 2; // Correct Z position by moving down + + if (abs(mobj->scale - mobj->destscale) < mobj->scalespeed) + P_SetScale(mobj, mobj->destscale); + else if (mobj->scale < mobj->destscale) + P_SetScale(mobj, mobj->scale + mobj->scalespeed); + else if (mobj->scale > mobj->destscale) + P_SetScale(mobj, mobj->scale - mobj->scalespeed); + + if (correctionType == 1) + mobj->z -= (mobj->height - oldheight)/2; + else if (correctionType == 2) + mobj->z -= mobj->height - oldheight; + + if (mobj->scale == mobj->destscale) + /// \todo Lua hook for "reached destscale"? + switch (mobj->type) + { + case MT_EGGMOBILE_FIRE: + mobj->destscale = FRACUNIT; + mobj->scalespeed = FRACUNIT>>4; + break; + default: + break; + } +} + +static void P_MaceSceneryThink(mobj_t *mobj) +{ + angle_t oldmovedir = mobj->movedir; + + // Always update movedir to prevent desyncing (in the traditional sense, not the netplay sense). + mobj->movedir = (mobj->movedir + mobj->lastlook) & FINEMASK; + + // If too far away and not deliberately spitting in the face of optimisation, don't think! + if (!(mobj->flags2 & MF2_BOSSNOTRAP)) + { + UINT8 i; + // Quick! Look through players! Don't move unless a player is relatively close by. + // The below is selected based on CEZ2's first room. I promise you it is a coincidence that it looks like the weed number. + for (i = 0; i < MAXPLAYERS; ++i) + if (playeringame[i] && players[i].mo + && P_AproxDistance(P_AproxDistance(mobj->x - players[i].mo->x, mobj->y - players[i].mo->y), mobj->z - players[i].mo->z) < (4200 << FRACBITS)) + break; // Stop looking. + if (i == MAXPLAYERS) + { + if (!(mobj->flags2 & MF2_BEYONDTHEGRAVE)) + { + mobj_t *ref = mobj; + + // stop/hide all your babies + while ((ref = ref->hnext)) + { + ref->eflags = (((ref->flags & MF_NOTHINK) ? 0 : 1) + | ((ref->flags & MF_NOCLIPTHING) ? 0 : 2) + | ((ref->flags2 & MF2_DONTDRAW) ? 0 : 4)); // oh my god this is nasty. + ref->flags |= MF_NOTHINK|MF_NOCLIPTHING; + ref->flags2 |= MF2_DONTDRAW; + ref->momx = ref->momy = ref->momz = 0; + } + + mobj->flags2 |= MF2_BEYONDTHEGRAVE; + } + return; // don't make bubble! + } + else if (mobj->flags2 & MF2_BEYONDTHEGRAVE) + { + mobj_t *ref = mobj; + + // start/show all your babies + while ((ref = ref->hnext)) + { + if (ref->eflags & 1) + ref->flags &= ~MF_NOTHINK; + if (ref->eflags & 2) + ref->flags &= ~MF_NOCLIPTHING; + if (ref->eflags & 4) + ref->flags2 &= ~MF2_DONTDRAW; + ref->eflags = 0; // le sign + } + + mobj->flags2 &= ~MF2_BEYONDTHEGRAVE; + } + } + + // Okay, time to MOVE + P_MaceRotate(mobj, mobj->movedir, oldmovedir); +} + +static boolean P_DrownNumbersSceneryThink(mobj_t *mobj) +{ + if (!mobj->target) + { + P_RemoveMobj(mobj); + return false; + } + if (!mobj->target->player || !(mobj->target->player->powers[pw_underwater] || mobj->target->player->powers[pw_spacetime])) + { + P_RemoveMobj(mobj); + return false; + } + mobj->x = mobj->target->x; + mobj->y = mobj->target->y; + + mobj->destscale = mobj->target->destscale; + P_SetScale(mobj, mobj->target->scale); + + if (mobj->target->eflags & MFE_VERTICALFLIP) + { + mobj->z = mobj->target->z - FixedMul(16*FRACUNIT, mobj->target->scale) - mobj->height; + if (mobj->target->player->pflags & PF_FLIPCAM) + mobj->eflags |= MFE_VERTICALFLIP; + } + else + mobj->z = mobj->target->z + (mobj->target->height) + FixedMul(8*FRACUNIT, mobj->target->scale); // Adjust height for height changes + + if (mobj->threshold <= 35) + mobj->flags2 |= MF2_DONTDRAW; + else + mobj->flags2 &= ~MF2_DONTDRAW; + if (mobj->threshold <= 30) + mobj->threshold = 40; + mobj->threshold--; + return true; +} + +static void P_FlameJetSceneryThink(mobj_t *mobj) +{ + mobj_t *flame; + fixed_t strength; + + if (!(mobj->flags2 & MF2_FIRING)) + return; + + if ((leveltime & 3) == 0) + return; + + // Wave the flames back and forth. Reactiontime determines which direction it's going. + if (mobj->fuse <= -16) + mobj->reactiontime = 1; + else if (mobj->fuse >= 16) + mobj->reactiontime = 0; + + if (mobj->reactiontime) + mobj->fuse += 2; + else + mobj->fuse -= 2; + + flame = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_FLAMEJETFLAME); + P_SetMobjState(flame, S_FLAMEJETFLAME4); + + flame->angle = mobj->angle; + + if (mobj->flags2 & MF2_AMBUSH) // Wave up and down instead of side-to-side + flame->momz = mobj->fuse << (FRACBITS - 2); + else + flame->angle += FixedAngle(mobj->fuse<movedir; + + P_InstaThrust(flame, flame->angle, strength); + S_StartSound(flame, sfx_fire); +} + +static void P_VerticalFlameJetSceneryThink(mobj_t *mobj) +{ + mobj_t *flame; + fixed_t strength; + + if (!(mobj->flags2 & MF2_FIRING)) + return; + + if ((leveltime & 3) == 0) + return; + + // Wave the flames back and forth. Reactiontime determines which direction it's going. + if (mobj->fuse <= -16) + mobj->reactiontime = 1; + else if (mobj->fuse >= 16) + mobj->reactiontime = 0; + + if (mobj->reactiontime) + mobj->fuse++; + else + mobj->fuse--; + + flame = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_FLAMEJETFLAME); + + strength = 20*FRACUNIT; + strength -= ((20*FRACUNIT)/16)*mobj->movedir; + + // If deaf'd, the object spawns on the ceiling. + if (mobj->flags2 & MF2_AMBUSH) + { + mobj->z = mobj->ceilingz - mobj->height; + flame->momz = -strength; + } + else + { + flame->momz = strength; + P_SetMobjState(flame, S_FLAMEJETFLAME7); + } + P_InstaThrust(flame, mobj->angle, FixedDiv(mobj->fuse*FRACUNIT, 3*FRACUNIT)); + S_StartSound(flame, sfx_fire); +} + +static boolean P_ParticleGenSceneryThink(mobj_t *mobj) +{ + if (!mobj->lastlook) + return false; + + if (!mobj->threshold) + return false; + + if (--mobj->fuse <= 0) + { + INT32 i = 0; + mobj_t *spawn; + fixed_t bottomheight, topheight; + INT32 type = mobj->threshold, line = mobj->cvmem; + + mobj->fuse = (tic_t)mobj->reactiontime; + + bottomheight = lines[line].frontsector->floorheight; + topheight = lines[line].frontsector->ceilingheight - mobjinfo[(mobjtype_t)type].height; + + if (mobj->waterbottom != bottomheight || mobj->watertop != topheight) + { + if (mobj->movefactor && (topheight > bottomheight)) + mobj->health = (tic_t)(FixedDiv((topheight - bottomheight), abs(mobj->movefactor)) >> FRACBITS); + else + mobj->health = 0; + + mobj->z = ((mobj->flags2 & MF2_OBJECTFLIP) ? topheight : bottomheight); + } + + if (!mobj->health) + return false; + + for (i = 0; i < mobj->lastlook; i++) + { + spawn = P_SpawnMobj( + mobj->x + FixedMul(FixedMul(mobj->friction, mobj->scale), FINECOSINE(mobj->angle >> ANGLETOFINESHIFT)), + mobj->y + FixedMul(FixedMul(mobj->friction, mobj->scale), FINESINE(mobj->angle >> ANGLETOFINESHIFT)), + mobj->z, + (mobjtype_t)mobj->threshold); + P_SetScale(spawn, mobj->scale); + spawn->momz = FixedMul(mobj->movefactor, spawn->scale); + spawn->destscale = spawn->scale/100; + spawn->scalespeed = spawn->scale/mobj->health; + spawn->tics = (tic_t)mobj->health; + spawn->flags2 |= (mobj->flags2 & MF2_OBJECTFLIP); + spawn->angle += P_RandomKey(36)*ANG10; // irrelevant for default objects but might make sense for some custom ones + + mobj->angle += mobj->movedir; + } + + mobj->angle += (angle_t)mobj->movecount; + } + + return true; +} + +static void P_RosySceneryThink(mobj_t *mobj) +{ + UINT8 i; + fixed_t pdist = 1700*mobj->scale, work, actualwork; + player_t *player = NULL; + statenum_t stat = (mobj->state - states); + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + if (!players[i].mo) + continue; + if (players[i].bot) + continue; + if (!players[i].mo->health) + continue; + actualwork = work = FixedHypot(mobj->x - players[i].mo->x, mobj->y - players[i].mo->y); + if (player) + { + if (players[i].skin == 0 || players[i].skin == 5) + work = (2*work)/3; + if (work >= pdist) + continue; + } + pdist = actualwork; + player = &players[i]; + } + + if (stat == S_ROSY_JUMP || stat == S_ROSY_PAIN) + { + if (P_IsObjectOnGround(mobj)) + { + mobj->momx = mobj->momy = 0; + if (player && mobj->cvmem < (-2*TICRATE)) + stat = S_ROSY_UNHAPPY; + else + stat = S_ROSY_WALK; + P_SetMobjState(mobj, stat); + } + else if (P_MobjFlip(mobj)*mobj->momz < 0) + mobj->frame = mobj->state->frame + mobj->state->var1; + } + + if (!player) + { + if ((stat < S_ROSY_IDLE1 || stat > S_ROSY_IDLE4) && stat != S_ROSY_JUMP) + { + mobj->momx = mobj->momy = 0; + P_SetMobjState(mobj, S_ROSY_IDLE1); + } + } + else + { + boolean dojump = false, targonground, love, makeheart = false; + if (mobj->target != player->mo) + P_SetTarget(&mobj->target, player->mo); + // Tatsuru: Don't try to hug them if they're above or below you! + targonground = (P_IsObjectOnGround(mobj->target) && (player->panim == PA_IDLE || player->panim == PA_WALK || player->panim == PA_RUN) && player->mo->z == mobj->z); + love = (player->skin == 0 || player->skin == 5); + + switch (stat) + { + case S_ROSY_IDLE1: + case S_ROSY_IDLE2: + case S_ROSY_IDLE3: + case S_ROSY_IDLE4: + dojump = true; + break; + case S_ROSY_JUMP: + case S_ROSY_PAIN: + // handled above + break; + case S_ROSY_WALK: + { + fixed_t x = mobj->x, y = mobj->y, z = mobj->z; + angle_t angletoplayer = R_PointToAngle2(x, y, mobj->target->x, mobj->target->y); + boolean allowed = P_TryMove(mobj, mobj->target->x, mobj->target->y, false); + + P_UnsetThingPosition(mobj); + mobj->x = x; + mobj->y = y; + mobj->z = z; + P_SetThingPosition(mobj); + + if (allowed) + { + fixed_t mom, max; + P_Thrust(mobj, angletoplayer, (3*FRACUNIT) >> 1); + mom = FixedHypot(mobj->momx, mobj->momy); + max = pdist; + if ((--mobj->extravalue1) <= 0) + { + if (++mobj->frame > mobj->state->frame + mobj->state->var1) + mobj->frame = mobj->state->frame; + if (mom > 12*mobj->scale) + mobj->extravalue1 = 2; + else if (mom > 6*mobj->scale) + mobj->extravalue1 = 3; + else + mobj->extravalue1 = 4; + } + if (max < (mobj->radius + mobj->target->radius)) + { + mobj->momx = mobj->target->player->cmomx; + mobj->momy = mobj->target->player->cmomy; + if ((mobj->cvmem > TICRATE && !player->exiting) || !targonground) + P_SetMobjState(mobj, (stat = S_ROSY_STND)); + else + { + mobj->target->momx = mobj->momx; + mobj->target->momy = mobj->momy; + P_SetMobjState(mobj, (stat = S_ROSY_HUG)); + S_StartSound(mobj, sfx_cdpcm6); + mobj->angle = angletoplayer; + } + } + else + { + max /= 3; + if (max > 30*mobj->scale) + max = 30*mobj->scale; + if (mom > max && max > mobj->scale) + { + max = FixedDiv(max, mom); + mobj->momx = FixedMul(mobj->momx, max); + mobj->momy = FixedMul(mobj->momy, max); + } + if (abs(mobj->momx) > mobj->scale || abs(mobj->momy) > mobj->scale) + mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy); + } + } + else + dojump = true; + } + break; + case S_ROSY_HUG: + if (targonground) + { + player->pflags |= PF_STASIS; + if (mobj->cvmem < 5*TICRATE) + mobj->cvmem++; + if (love && !(leveltime & 7)) + makeheart = true; + } + else + { + if (mobj->cvmem < (love ? 5*TICRATE : 0)) + { + P_SetMobjState(mobj, (stat = S_ROSY_PAIN)); + S_StartSound(mobj, sfx_cdpcm7); + } + else + P_SetMobjState(mobj, (stat = S_ROSY_JUMP)); + var1 = var2 = 0; + A_DoNPCPain(mobj); + mobj->cvmem -= TICRATE; + } + break; + case S_ROSY_STND: + if ((pdist > (mobj->radius + mobj->target->radius + 3*(mobj->scale + mobj->target->scale)))) + P_SetMobjState(mobj, (stat = S_ROSY_WALK)); + else if (!targonground) + ; + else + { + if (love && !(leveltime & 15)) + makeheart = true; + if (player->exiting || --mobj->cvmem < TICRATE) + { + P_SetMobjState(mobj, (stat = S_ROSY_HUG)); + S_StartSound(mobj, sfx_cdpcm6); + mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); + mobj->target->momx = mobj->momx; + mobj->target->momy = mobj->momy; + } + } + break; + case S_ROSY_UNHAPPY: + default: + break; + } + + if (stat == S_ROSY_HUG) + { + if (player->panim != PA_IDLE) + P_SetPlayerMobjState(mobj->target, S_PLAY_STND); + player->pflags |= PF_STASIS; + } + + if (dojump) + { + P_SetMobjState(mobj, S_ROSY_JUMP); + mobj->z += P_MobjFlip(mobj); + mobj->momx = mobj->momy = 0; + P_SetObjectMomZ(mobj, 6 << FRACBITS, false); + S_StartSound(mobj, sfx_cdfm02); + } + + if (makeheart) + { + mobj_t *cdlhrt = P_SpawnMobjFromMobj(mobj, 0, 0, mobj->height, MT_CDLHRT); + cdlhrt->destscale = (5*mobj->scale) >> 4; + P_SetScale(cdlhrt, cdlhrt->destscale); + cdlhrt->fuse = (5*TICRATE) >> 1; + cdlhrt->momz = mobj->scale; + P_SetTarget(&cdlhrt->target, mobj); + cdlhrt->extravalue1 = mobj->x; + cdlhrt->extravalue2 = mobj->y; + } + } +} + +static void P_MobjSceneryThink(mobj_t *mobj) +{ +#ifdef HAVE_BLUA + if (LUAh_MobjThinker(mobj)) + return; + if (P_MobjWasRemoved(mobj)) + return; +#endif + + if ((mobj->flags2 & MF2_SHIELD) && !P_AddShield(mobj)) + return; + + switch (mobj->type) + { + case MT_BOSSJUNK: + mobj->flags2 ^= MF2_DONTDRAW; + break; + case MT_MACEPOINT: + case MT_CHAINMACEPOINT: + case MT_SPRINGBALLPOINT: + case MT_CHAINPOINT: + case MT_FIREBARPOINT: + case MT_CUSTOMMACEPOINT: + case MT_HIDDEN_SLING: + P_MaceSceneryThink(mobj); + break; + case MT_HOOP: + if (mobj->fuse > 1) + P_MoveHoop(mobj); + else if (mobj->fuse == 1) + mobj->movecount = 1; + + if (mobj->movecount) + { + mobj->fuse++; + + if (mobj->fuse > 32) + { + // Don't kill the hoop center. For the sake of respawning. + //if (mobj->target) + // P_RemoveMobj(mobj->target); + + P_RemoveMobj(mobj); + } + } + else + mobj->fuse--; + return; + case MT_NIGHTSPARKLE: + if (mobj->tics != -1) + { + mobj->tics--; + + // you can cycle through multiple states in a tic + if (!mobj->tics) + if (!P_SetMobjState(mobj, mobj->state->nextstate)) + return; // freed itself + } + + P_UnsetThingPosition(mobj); + mobj->x += mobj->momx; + mobj->y += mobj->momy; + mobj->z += mobj->momz; + P_SetThingPosition(mobj); + return; + case MT_NIGHTSLOOPHELPER: + if (--mobj->tics <= 0) + P_RemoveMobj(mobj); + + // Don't touch my fuse! + return; + case MT_OVERLAY: + if (!mobj->target) + { + P_RemoveMobj(mobj); + return; + } + else + P_AddOverlay(mobj); + break; + case MT_PITY_ORB: + case MT_WHIRLWIND_ORB: + case MT_ARMAGEDDON_ORB: + if (!(mobj->flags2 & MF2_SHIELD)) + return; + break; + case MT_ATTRACT_ORB: + if (!(mobj->flags2 & MF2_SHIELD)) + return; + if (/*(mobj->target) -- the following is implicit by P_AddShield + && (mobj->target->player) + && */ (mobj->target->player->homing) && (mobj->target->player->pflags & PF_SHIELDABILITY)) + { + P_SetMobjState(mobj, mobj->info->painstate); + mobj->tics++; + } + break; + case MT_ELEMENTAL_ORB: + if (!(mobj->flags2 & MF2_SHIELD)) + return; + if (mobj->tracer + /* && mobj->target -- the following is implicit by P_AddShield + && mobj->target->player + && (mobj->target->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL */ + && mobj->target->player->pflags & PF_SHIELDABILITY + && ((statenum_t)(mobj->tracer->state - states) < mobj->info->raisestate + || (mobj->tracer->state->nextstate < mobj->info->raisestate && mobj->tracer->tics == 1))) + { + P_SetMobjState(mobj, mobj->info->painstate); + mobj->tics++; + P_SetMobjState(mobj->tracer, mobj->info->raisestate); + mobj->tracer->tics++; + } + break; + case MT_FORCE_ORB: + if (!(mobj->flags2 & MF2_SHIELD)) + return; + if (/* + && mobj->target -- the following is implicit by P_AddShield + && mobj->target->player + && (mobj->target->player->powers[pw_shield] & SH_FORCE) + && */ (mobj->target->player->pflags & PF_SHIELDABILITY)) + { + mobj_t *whoosh = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_GHOST); // done here so the offset is correct + P_SetMobjState(whoosh, mobj->info->raisestate); + whoosh->destscale = whoosh->scale << 1; + whoosh->scalespeed = FixedMul(whoosh->scalespeed, whoosh->scale); + whoosh->height = 38*whoosh->scale; + whoosh->fuse = 10; + whoosh->flags |= MF_NOCLIPHEIGHT; + whoosh->momz = mobj->target->momz; // Stay reasonably centered for a few frames + mobj->target->player->pflags &= ~PF_SHIELDABILITY; // prevent eternal whoosh + } + /* FALLTHRU */ + case MT_FLAMEAURA_ORB: + if (!(mobj->flags2 & MF2_SHIELD)) + return; + if ((statenum_t)(mobj->state - states) < mobj->info->painstate) + mobj->angle = mobj->target->angle; // implicitly okay because of P_AddShield + if (mobj->tracer + /* && mobj->target -- the following is implicit by P_AddShield + && mobj->target->player + && (mobj->target->player->powers[pw_shield] & SH_NOSTACK) == SH_FLAMEAURA */ + && mobj->target->player->pflags & PF_SHIELDABILITY + && ((statenum_t)(mobj->tracer->state - states) < mobj->info->raisestate + || (mobj->tracer->state->nextstate < mobj->info->raisestate && mobj->tracer->tics == 1))) + { + P_SetMobjState(mobj, mobj->info->painstate); + mobj->tics++; + P_SetMobjState(mobj->tracer, mobj->info->raisestate); + mobj->tracer->tics++; + } + break; + case MT_BUBBLEWRAP_ORB: + if (!(mobj->flags2 & MF2_SHIELD)) + return; + if (mobj->tracer + /* && mobj->target -- the following is implicit by P_AddShield + && mobj->target->player + && (mobj->target->player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP */ + ) + { + if (mobj->target->player->pflags & PF_SHIELDABILITY + && ((statenum_t)(mobj->state - states) < mobj->info->painstate + || (mobj->state->nextstate < mobj->info->painstate && mobj->tics == 1))) + { + P_SetMobjState(mobj, mobj->info->painstate); + mobj->tics++; + P_SetMobjState(mobj->tracer, mobj->info->raisestate); + mobj->tracer->tics++; + } + else if (mobj->target->eflags & MFE_JUSTHITFLOOR + && (statenum_t)(mobj->state - states) == mobj->info->painstate) + { + P_SetMobjState(mobj, mobj->info->painstate + 1); + mobj->tics++; + P_SetMobjState(mobj->tracer, mobj->info->raisestate + 1); + mobj->tracer->tics++; + } + } + break; + case MT_THUNDERCOIN_ORB: + if (!(mobj->flags2 & MF2_SHIELD)) + return; + if (mobj->tracer + /* && mobj->target -- the following is implicit by P_AddShield + && mobj->target->player + && (mobj->target->player->powers[pw_shield] & SH_NOSTACK) == SH_THUNDERCOIN */ + && (mobj->target->player->pflags & PF_SHIELDABILITY)) + { + P_SetMobjState(mobj, mobj->info->painstate); + mobj->tics++; + P_SetMobjState(mobj->tracer, mobj->info->raisestate); + mobj->tracer->tics++; + mobj->target->player->pflags &= ~PF_SHIELDABILITY; // prevent eternal spark + } + break; + case MT_WATERDROP: + P_SceneryCheckWater(mobj); + if ((mobj->z <= mobj->floorz || mobj->z <= mobj->watertop) + && mobj->health > 0) + { + mobj->health = 0; + P_SetMobjState(mobj, mobj->info->deathstate); + S_StartSound(mobj, mobj->info->deathsound + P_RandomKey(mobj->info->mass)); + return; + } + break; + case MT_BUBBLES: + P_SceneryCheckWater(mobj); + break; + case MT_SMALLBUBBLE: + case MT_MEDIUMBUBBLE: + case MT_EXTRALARGEBUBBLE: // start bubble dissipate + P_SceneryCheckWater(mobj); + if (P_MobjWasRemoved(mobj)) // bubble was removed by not being in water + return; + if (!(mobj->eflags & MFE_UNDERWATER) + || (!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z + mobj->height >= mobj->ceilingz) + || (mobj->eflags & MFE_VERTICALFLIP && mobj->z <= mobj->floorz) + || (P_CheckDeathPitCollide(mobj)) + || --mobj->fuse <= 0) // Bubbles eventually dissipate if they can't reach the surface. + { + // no playing sound: no point; the object is being removed + P_RemoveMobj(mobj); + return; + } + break; + case MT_LOCKON: + if (!mobj->target) + { + P_RemoveMobj(mobj); + return; + } + + mobj->flags2 &= ~MF2_DONTDRAW; + + mobj->x = mobj->target->x; + mobj->y = mobj->target->y; + + mobj->eflags |= (mobj->target->eflags & MFE_VERTICALFLIP); + + mobj->destscale = mobj->target->destscale; + P_SetScale(mobj, mobj->target->scale); + + if (!(mobj->eflags & MFE_VERTICALFLIP)) + mobj->z = mobj->target->z + mobj->target->height + FixedMul((16 + abs((signed)(leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->target->scale); + else + mobj->z = mobj->target->z - FixedMul((16 + abs((signed)(leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->target->scale) - mobj->height; + break; + case MT_LOCKONINF: + if (!(mobj->flags2 & MF2_STRONGBOX)) + { + mobj->threshold = mobj->z; + mobj->flags2 |= MF2_STRONGBOX; + } + if (!(mobj->eflags & MFE_VERTICALFLIP)) + mobj->z = mobj->threshold + FixedMul((16 + abs((signed)(leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->scale); + else + mobj->z = mobj->threshold - FixedMul((16 + abs((signed)(leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->scale); + break; + case MT_DROWNNUMBERS: + if (!P_DrownNumbersSceneryThink(mobj)) + return; + break; + case MT_FLAMEJET: + P_FlameJetSceneryThink(mobj); + break; + case MT_VERTICALFLAMEJET: + P_VerticalFlameJetSceneryThink(mobj); + break; + case MT_FLICKY_01_CENTER: + case MT_FLICKY_02_CENTER: + case MT_FLICKY_03_CENTER: + case MT_FLICKY_04_CENTER: + case MT_FLICKY_05_CENTER: + case MT_FLICKY_06_CENTER: + case MT_FLICKY_07_CENTER: + case MT_FLICKY_08_CENTER: + case MT_FLICKY_09_CENTER: + case MT_FLICKY_10_CENTER: + case MT_FLICKY_11_CENTER: + case MT_FLICKY_12_CENTER: + case MT_FLICKY_13_CENTER: + case MT_FLICKY_14_CENTER: + case MT_FLICKY_15_CENTER: + case MT_FLICKY_16_CENTER: + case MT_SECRETFLICKY_01_CENTER: + case MT_SECRETFLICKY_02_CENTER: + if (mobj->tracer && (mobj->flags & MF_NOCLIPTHING) + && (mobj->flags & MF_GRENADEBOUNCE)) + // for now: only do this bounce routine if flicky is in-place. \todo allow in all movements + { + if (!(mobj->tracer->flags2 & MF2_OBJECTFLIP) && mobj->tracer->z <= mobj->tracer->floorz) + mobj->tracer->momz = 7*FRACUNIT; + else if ((mobj->tracer->flags2 & MF2_OBJECTFLIP) && mobj->tracer->z >= mobj->tracer->ceilingz - mobj->tracer->height) + mobj->tracer->momz = -7*FRACUNIT; + } + break; + case MT_SEED: + if (P_MobjFlip(mobj)*mobj->momz < mobj->info->speed) + mobj->momz = P_MobjFlip(mobj)*mobj->info->speed; + break; + case MT_ROCKCRUMBLE1: + case MT_ROCKCRUMBLE2: + case MT_ROCKCRUMBLE3: + case MT_ROCKCRUMBLE4: + case MT_ROCKCRUMBLE5: + case MT_ROCKCRUMBLE6: + case MT_ROCKCRUMBLE7: + case MT_ROCKCRUMBLE8: + case MT_ROCKCRUMBLE9: + case MT_ROCKCRUMBLE10: + case MT_ROCKCRUMBLE11: + case MT_ROCKCRUMBLE12: + case MT_ROCKCRUMBLE13: + case MT_ROCKCRUMBLE14: + case MT_ROCKCRUMBLE15: + case MT_ROCKCRUMBLE16: + case MT_WOODDEBRIS: + case MT_BRICKDEBRIS: + case MT_BROKENROBOT: + if (mobj->z <= P_FloorzAtPos(mobj->x, mobj->y, mobj->z, mobj->height) + && mobj->state != &states[mobj->info->deathstate]) + { + P_SetMobjState(mobj, mobj->info->deathstate); + return; + } + break; + case MT_PARTICLEGEN: + if (!P_ParticleGenSceneryThink(mobj)) + return; + break; + case MT_FSGNA: + if (mobj->movedir) + mobj->angle += mobj->movedir; + break; + case MT_ROSY: + P_RosySceneryThink(mobj); + break; + case MT_CDLHRT: + { + if (mobj->cvmem < 24) + mobj->cvmem++; + mobj->movedir += ANG10; + P_UnsetThingPosition(mobj); + mobj->x = mobj->extravalue1 + P_ReturnThrustX(mobj, mobj->movedir, mobj->cvmem*mobj->scale); + mobj->y = mobj->extravalue2 + P_ReturnThrustY(mobj, mobj->movedir, mobj->cvmem*mobj->scale); + P_SetThingPosition(mobj); + if ((--mobj->fuse) < 6) + { + if (!mobj->fuse) + { + P_RemoveMobj(mobj); + return; + } + mobj->frame = (mobj->frame & ~FF_TRANSMASK) | ((10 - (mobj->fuse*2)) << (FF_TRANSSHIFT)); + } + } + break; + case MT_VWREF: + case MT_VWREB: + { + INT32 strength; + ++mobj->movedir; + mobj->frame &= ~FF_TRANSMASK; + strength = min(mobj->fuse, (INT32)mobj->movedir)*3; + if (strength < 10) + mobj->frame |= ((10 - strength) << (FF_TRANSSHIFT)); + } + /* FALLTHRU */ + default: + if (mobj->fuse) + { // Scenery object fuse! Very basic! + mobj->fuse--; + if (!mobj->fuse) + { +#ifdef HAVE_BLUA + if (!LUAh_MobjFuse(mobj)) +#endif + P_RemoveMobj(mobj); + return; + } + } + break; + } + + P_SceneryThinker(mobj); +} + // // P_MobjThinker // @@ -7171,7 +8046,7 @@ void P_MobjThinker(mobj_t *mobj) tmfloorthing = tmhitthing = NULL; - // 970 allows ANY mobj to trigger a linedef exec + // Sector special (2,8) allows ANY mobj to trigger a linedef exec if (mobj->subsector && GETSECSPECIAL(mobj->subsector->sector->special, 2) == 8) { sector_t *sec2; @@ -7181,42 +8056,8 @@ void P_MobjThinker(mobj_t *mobj) P_LinedefExecute(sec2->tag, mobj, sec2); } - // Slowly scale up/down to reach your destscale. if (mobj->scale != mobj->destscale) - { - fixed_t oldheight = mobj->height; - UINT8 correctionType = 0; // Don't correct Z position, just gain height - - if ((mobj->flags & MF_NOCLIPHEIGHT || (mobj->z > mobj->floorz && mobj->z + mobj->height < mobj->ceilingz)) - && mobj->type != MT_EGGMOBILE_FIRE) - correctionType = 1; // Correct Z position by centering - else if (mobj->eflags & MFE_VERTICALFLIP) - correctionType = 2; // Correct Z position by moving down - - if (abs(mobj->scale - mobj->destscale) < mobj->scalespeed) - P_SetScale(mobj, mobj->destscale); - else if (mobj->scale < mobj->destscale) - P_SetScale(mobj, mobj->scale + mobj->scalespeed); - else if (mobj->scale > mobj->destscale) - P_SetScale(mobj, mobj->scale - mobj->scalespeed); - - if (correctionType == 1) - mobj->z -= (mobj->height - oldheight)/2; - else if (correctionType == 2) - mobj->z -= mobj->height - oldheight; - - if (mobj->scale == mobj->destscale) - /// \todo Lua hook for "reached destscale"? - switch(mobj->type) - { - case MT_EGGMOBILE_FIRE: - mobj->destscale = FRACUNIT; - mobj->scalespeed = FRACUNIT>>4; - break; - default: - break; - } - } + P_MobjScaleThink(mobj); // Slowly scale up/down to reach your destscale. if ((mobj->type == MT_GHOST || mobj->type == MT_THOK) && mobj->fuse > 0) // Not guaranteed to be MF_SCENERY or not MF_SCENERY! { @@ -7237,806 +8078,7 @@ void P_MobjThinker(mobj_t *mobj) // Special thinker for scenery objects if (mobj->flags & MF_SCENERY) { -#ifdef HAVE_BLUA - if (LUAh_MobjThinker(mobj)) - return; - if (P_MobjWasRemoved(mobj)) - return; -#endif - - if (mobj->flags2 & MF2_SHIELD) - if (!P_AddShield(mobj)) - return; - - switch (mobj->type) - { - case MT_BOSSJUNK: - mobj->flags2 ^= MF2_DONTDRAW; - break; - case MT_MACEPOINT: - case MT_CHAINMACEPOINT: - case MT_SPRINGBALLPOINT: - case MT_CHAINPOINT: - case MT_FIREBARPOINT: - case MT_CUSTOMMACEPOINT: - case MT_HIDDEN_SLING: - { - angle_t oldmovedir = mobj->movedir; - - // Always update movedir to prevent desyncing (in the traditional sense, not the netplay sense). - mobj->movedir = (mobj->movedir + mobj->lastlook) & FINEMASK; - - // If too far away and not deliberately spitting in the face of optimisation, don't think! - if (!(mobj->flags2 & MF2_BOSSNOTRAP)) - { - UINT8 i; - // Quick! Look through players! Don't move unless a player is relatively close by. - // The below is selected based on CEZ2's first room. I promise you it is a coincidence that it looks like the weed number. - for (i = 0; i < MAXPLAYERS; ++i) - if (playeringame[i] && players[i].mo - && P_AproxDistance(P_AproxDistance(mobj->x - players[i].mo->x, mobj->y - players[i].mo->y), mobj->z - players[i].mo->z) < (4200<flags2 & MF2_BEYONDTHEGRAVE)) - { - mobj_t *ref = mobj; - - // stop/hide all your babies - while ((ref = ref->hnext)) - { - ref->eflags = (((ref->flags & MF_NOTHINK) ? 0 : 1) - | ((ref->flags & MF_NOCLIPTHING) ? 0 : 2) - | ((ref->flags2 & MF2_DONTDRAW) ? 0 : 4)); // oh my god this is nasty. - ref->flags |= MF_NOTHINK|MF_NOCLIPTHING; - ref->flags2 |= MF2_DONTDRAW; - ref->momx = ref->momy = ref->momz = 0; - } - - mobj->flags2 |= MF2_BEYONDTHEGRAVE; - } - - break; // don't make bubble! - } - else if (mobj->flags2 & MF2_BEYONDTHEGRAVE) - { - mobj_t *ref = mobj; - - // start/show all your babies - while ((ref = ref->hnext)) - { - if (ref->eflags & 1) - ref->flags &= ~MF_NOTHINK; - if (ref->eflags & 2) - ref->flags &= ~MF_NOCLIPTHING; - if (ref->eflags & 4) - ref->flags2 &= ~MF2_DONTDRAW; - ref->eflags = 0; // le sign - } - - mobj->flags2 &= ~MF2_BEYONDTHEGRAVE; - } - } - - // Okay, time to MOVE - P_MaceRotate(mobj, mobj->movedir, oldmovedir); - } - break; - case MT_HOOP: - if (mobj->fuse > 1) - P_MoveHoop(mobj); - else if (mobj->fuse == 1) - mobj->movecount = 1; - - if (mobj->movecount) - { - mobj->fuse++; - - if (mobj->fuse > 32) - { - // Don't kill the hoop center. For the sake of respawning. - //if (mobj->target) - // P_RemoveMobj(mobj->target); - - P_RemoveMobj(mobj); - } - } - else - mobj->fuse--; - return; - case MT_NIGHTSPARKLE: - if (mobj->tics != -1) - { - mobj->tics--; - - // you can cycle through multiple states in a tic - if (!mobj->tics) - if (!P_SetMobjState(mobj, mobj->state->nextstate)) - return; // freed itself - } - - P_UnsetThingPosition(mobj); - mobj->x += mobj->momx; - mobj->y += mobj->momy; - mobj->z += mobj->momz; - P_SetThingPosition(mobj); - return; - case MT_NIGHTSLOOPHELPER: - if (--mobj->tics <= 0) - P_RemoveMobj(mobj); - - // Don't touch my fuse! - return; - case MT_OVERLAY: - if (!mobj->target) - { - P_RemoveMobj(mobj); - return; - } - else - P_AddOverlay(mobj); - break; - case MT_PITY_ORB: - case MT_WHIRLWIND_ORB: - case MT_ARMAGEDDON_ORB: - if (!(mobj->flags2 & MF2_SHIELD)) - return; - break; - case MT_ATTRACT_ORB: - if (!(mobj->flags2 & MF2_SHIELD)) - return; - if (/*(mobj->target) -- the following is implicit by P_AddShield - && (mobj->target->player) - && */ (mobj->target->player->homing) && (mobj->target->player->pflags & PF_SHIELDABILITY)) - { - P_SetMobjState(mobj, mobj->info->painstate); - mobj->tics++; - } - break; - case MT_ELEMENTAL_ORB: - if (!(mobj->flags2 & MF2_SHIELD)) - return; - if (mobj->tracer - /* && mobj->target -- the following is implicit by P_AddShield - && mobj->target->player - && (mobj->target->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL */ - && mobj->target->player->pflags & PF_SHIELDABILITY - && ((statenum_t)(mobj->tracer->state-states) < mobj->info->raisestate - || (mobj->tracer->state->nextstate < mobj->info->raisestate && mobj->tracer->tics == 1))) - { - P_SetMobjState(mobj, mobj->info->painstate); - mobj->tics++; - P_SetMobjState(mobj->tracer, mobj->info->raisestate); - mobj->tracer->tics++; - } - break; - case MT_FORCE_ORB: - if (!(mobj->flags2 & MF2_SHIELD)) - return; - if (/* - && mobj->target -- the following is implicit by P_AddShield - && mobj->target->player - && (mobj->target->player->powers[pw_shield] & SH_FORCE) - && */ (mobj->target->player->pflags & PF_SHIELDABILITY)) - { - mobj_t *whoosh = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_GHOST); // done here so the offset is correct - P_SetMobjState(whoosh, mobj->info->raisestate); - whoosh->destscale = whoosh->scale<<1; - whoosh->scalespeed = FixedMul(whoosh->scalespeed, whoosh->scale); - whoosh->height = 38*whoosh->scale; - whoosh->fuse = 10; - whoosh->flags |= MF_NOCLIPHEIGHT; - whoosh->momz = mobj->target->momz; // Stay reasonably centered for a few frames - mobj->target->player->pflags &= ~PF_SHIELDABILITY; // prevent eternal whoosh - } - /* FALLTHRU */ - case MT_FLAMEAURA_ORB: - if (!(mobj->flags2 & MF2_SHIELD)) - return; - if ((statenum_t)(mobj->state-states) < mobj->info->painstate) - mobj->angle = mobj->target->angle; // implicitly okay because of P_AddShield - if (mobj->tracer - /* && mobj->target -- the following is implicit by P_AddShield - && mobj->target->player - && (mobj->target->player->powers[pw_shield] & SH_NOSTACK) == SH_FLAMEAURA */ - && mobj->target->player->pflags & PF_SHIELDABILITY - && ((statenum_t)(mobj->tracer->state-states) < mobj->info->raisestate - || (mobj->tracer->state->nextstate < mobj->info->raisestate && mobj->tracer->tics == 1))) - { - P_SetMobjState(mobj, mobj->info->painstate); - mobj->tics++; - P_SetMobjState(mobj->tracer, mobj->info->raisestate); - mobj->tracer->tics++; - } - break; - case MT_BUBBLEWRAP_ORB: - if (!(mobj->flags2 & MF2_SHIELD)) - return; - if (mobj->tracer - /* && mobj->target -- the following is implicit by P_AddShield - && mobj->target->player - && (mobj->target->player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP */ - ) - { - if (mobj->target->player->pflags & PF_SHIELDABILITY - && ((statenum_t)(mobj->state-states) < mobj->info->painstate - || (mobj->state->nextstate < mobj->info->painstate && mobj->tics == 1))) - { - P_SetMobjState(mobj, mobj->info->painstate); - mobj->tics++; - P_SetMobjState(mobj->tracer, mobj->info->raisestate); - mobj->tracer->tics++; - } - else if (mobj->target->eflags & MFE_JUSTHITFLOOR - && (statenum_t)(mobj->state-states) == mobj->info->painstate) - { - P_SetMobjState(mobj, mobj->info->painstate+1); - mobj->tics++; - P_SetMobjState(mobj->tracer, mobj->info->raisestate+1); - mobj->tracer->tics++; - } - } - break; - case MT_THUNDERCOIN_ORB: - if (!(mobj->flags2 & MF2_SHIELD)) - return; - if (mobj->tracer - /* && mobj->target -- the following is implicit by P_AddShield - && mobj->target->player - && (mobj->target->player->powers[pw_shield] & SH_NOSTACK) == SH_THUNDERCOIN */ - && (mobj->target->player->pflags & PF_SHIELDABILITY)) - { - P_SetMobjState(mobj, mobj->info->painstate); - mobj->tics++; - P_SetMobjState(mobj->tracer, mobj->info->raisestate); - mobj->tracer->tics++; - mobj->target->player->pflags &= ~PF_SHIELDABILITY; // prevent eternal spark - } - break; - case MT_WATERDROP: - P_SceneryCheckWater(mobj); - if ((mobj->z <= mobj->floorz || mobj->z <= mobj->watertop) - && mobj->health > 0) - { - mobj->health = 0; - P_SetMobjState(mobj, mobj->info->deathstate); - S_StartSound(mobj, mobj->info->deathsound+P_RandomKey(mobj->info->mass)); - return; - } - break; - case MT_BUBBLES: - P_SceneryCheckWater(mobj); - break; - case MT_SMALLBUBBLE: - case MT_MEDIUMBUBBLE: - case MT_EXTRALARGEBUBBLE: // start bubble dissipate - P_SceneryCheckWater(mobj); - if (P_MobjWasRemoved(mobj)) // bubble was removed by not being in water - return; - if (!(mobj->eflags & MFE_UNDERWATER) - || (!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z + mobj->height >= mobj->ceilingz) - || (mobj->eflags & MFE_VERTICALFLIP && mobj->z <= mobj->floorz) - || (P_CheckDeathPitCollide(mobj)) - || --mobj->fuse <= 0) // Bubbles eventually dissipate if they can't reach the surface. - { - // no playing sound: no point; the object is being removed - P_RemoveMobj(mobj); - return; - } - break; - case MT_LOCKON: - if (!mobj->target) - { - P_RemoveMobj(mobj); - return; - } - - mobj->flags2 &= ~MF2_DONTDRAW; - - mobj->x = mobj->target->x; - mobj->y = mobj->target->y; - - mobj->eflags |= (mobj->target->eflags & MFE_VERTICALFLIP); - - mobj->destscale = mobj->target->destscale; - P_SetScale(mobj, mobj->target->scale); - - if (!(mobj->eflags & MFE_VERTICALFLIP)) - mobj->z = mobj->target->z + mobj->target->height + FixedMul((16 + abs((signed)(leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->target->scale); - else - mobj->z = mobj->target->z - FixedMul((16 + abs((signed)(leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->target->scale) - mobj->height; - break; - case MT_LOCKONINF: - if (!(mobj->flags2 & MF2_STRONGBOX)) - { - mobj->threshold = mobj->z; - mobj->flags2 |= MF2_STRONGBOX; - } - if (!(mobj->eflags & MFE_VERTICALFLIP)) - mobj->z = mobj->threshold + FixedMul((16 + abs((signed)(leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->scale); - else - mobj->z = mobj->threshold - FixedMul((16 + abs((signed)(leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->scale); - break; - case MT_DROWNNUMBERS: - if (!mobj->target) - { - P_RemoveMobj(mobj); - return; - } - if (!mobj->target->player || !(mobj->target->player->powers[pw_underwater] || mobj->target->player->powers[pw_spacetime])) - { - P_RemoveMobj(mobj); - return; - } - mobj->x = mobj->target->x; - mobj->y = mobj->target->y; - - mobj->destscale = mobj->target->destscale; - P_SetScale(mobj, mobj->target->scale); - - if (mobj->target->eflags & MFE_VERTICALFLIP) - { - mobj->z = mobj->target->z - FixedMul(16*FRACUNIT, mobj->target->scale) - mobj->height; - if (mobj->target->player->pflags & PF_FLIPCAM) - mobj->eflags |= MFE_VERTICALFLIP; - } - else - mobj->z = mobj->target->z + (mobj->target->height) + FixedMul(8*FRACUNIT, mobj->target->scale); // Adjust height for height changes - - if (mobj->threshold <= 35) - mobj->flags2 |= MF2_DONTDRAW; - else - mobj->flags2 &= ~MF2_DONTDRAW; - if (mobj->threshold <= 30) - mobj->threshold = 40; - mobj->threshold--; - break; - case MT_FLAMEJET: - if ((mobj->flags2 & MF2_FIRING) && (leveltime & 3) == 0) - { - mobj_t *flame; - fixed_t strength; - - // Wave the flames back and forth. Reactiontime determines which direction it's going. - if (mobj->fuse <= -16) - mobj->reactiontime = 1; - else if (mobj->fuse >= 16) - mobj->reactiontime = 0; - - if (mobj->reactiontime) - mobj->fuse += 2; - else - mobj->fuse -= 2; - - flame = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_FLAMEJETFLAME); - P_SetMobjState(flame, S_FLAMEJETFLAME4); - - flame->angle = mobj->angle; - - if (mobj->flags2 & MF2_AMBUSH) // Wave up and down instead of side-to-side - flame->momz = mobj->fuse << (FRACBITS-2); - else - flame->angle += FixedAngle(mobj->fuse*FRACUNIT); - - strength = 20*FRACUNIT; - strength -= ((20*FRACUNIT)/16)*mobj->movedir; - - P_InstaThrust(flame, flame->angle, strength); - S_StartSound(flame, sfx_fire); - } - break; - case MT_VERTICALFLAMEJET: - if ((mobj->flags2 & MF2_FIRING) && (leveltime & 3) == 0) - { - mobj_t *flame; - fixed_t strength; - - // Wave the flames back and forth. Reactiontime determines which direction it's going. - if (mobj->fuse <= -16) - mobj->reactiontime = 1; - else if (mobj->fuse >= 16) - mobj->reactiontime = 0; - - if (mobj->reactiontime) - mobj->fuse++; - else - mobj->fuse--; - - flame = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_FLAMEJETFLAME); - - strength = 20*FRACUNIT; - strength -= ((20*FRACUNIT)/16)*mobj->movedir; - - // If deaf'd, the object spawns on the ceiling. - if (mobj->flags2 & MF2_AMBUSH) - { - mobj->z = mobj->ceilingz-mobj->height; - flame->momz = -strength; - } - else - { - flame->momz = strength; - P_SetMobjState(flame, S_FLAMEJETFLAME7); - } - P_InstaThrust(flame, mobj->angle, FixedDiv(mobj->fuse*FRACUNIT,3*FRACUNIT)); - S_StartSound(flame, sfx_fire); - } - break; - case MT_FLICKY_01_CENTER: - case MT_FLICKY_02_CENTER: - case MT_FLICKY_03_CENTER: - case MT_FLICKY_04_CENTER: - case MT_FLICKY_05_CENTER: - case MT_FLICKY_06_CENTER: - case MT_FLICKY_07_CENTER: - case MT_FLICKY_08_CENTER: - case MT_FLICKY_09_CENTER: - case MT_FLICKY_10_CENTER: - case MT_FLICKY_11_CENTER: - case MT_FLICKY_12_CENTER: - case MT_FLICKY_13_CENTER: - case MT_FLICKY_14_CENTER: - case MT_FLICKY_15_CENTER: - case MT_FLICKY_16_CENTER: - case MT_SECRETFLICKY_01_CENTER: - case MT_SECRETFLICKY_02_CENTER: - if (mobj->tracer && (mobj->flags & MF_NOCLIPTHING) - && (mobj->flags & MF_GRENADEBOUNCE)) - // for now: only do this bounce routine if flicky is in-place. \todo allow in all movements - { - if (!(mobj->tracer->flags2 & MF2_OBJECTFLIP) && mobj->tracer->z <= mobj->tracer->floorz) - mobj->tracer->momz = 7*FRACUNIT; - else if ((mobj->tracer->flags2 & MF2_OBJECTFLIP) && mobj->tracer->z >= mobj->tracer->ceilingz - mobj->tracer->height) - mobj->tracer->momz = -7*FRACUNIT; - } - break; - case MT_SEED: - if (P_MobjFlip(mobj)*mobj->momz < mobj->info->speed) - mobj->momz = P_MobjFlip(mobj)*mobj->info->speed; - break; - case MT_ROCKCRUMBLE1: - case MT_ROCKCRUMBLE2: - case MT_ROCKCRUMBLE3: - case MT_ROCKCRUMBLE4: - case MT_ROCKCRUMBLE5: - case MT_ROCKCRUMBLE6: - case MT_ROCKCRUMBLE7: - case MT_ROCKCRUMBLE8: - case MT_ROCKCRUMBLE9: - case MT_ROCKCRUMBLE10: - case MT_ROCKCRUMBLE11: - case MT_ROCKCRUMBLE12: - case MT_ROCKCRUMBLE13: - case MT_ROCKCRUMBLE14: - case MT_ROCKCRUMBLE15: - case MT_ROCKCRUMBLE16: - case MT_WOODDEBRIS: - case MT_BRICKDEBRIS: - case MT_BROKENROBOT: - if (mobj->z <= P_FloorzAtPos(mobj->x, mobj->y, mobj->z, mobj->height) - && mobj->state != &states[mobj->info->deathstate]) - { - P_SetMobjState(mobj, mobj->info->deathstate); - return; - } - break; - case MT_PARTICLEGEN: - if (!mobj->lastlook) - return; - - if (!mobj->threshold) - return; - - if (--mobj->fuse <= 0) - { - INT32 i = 0; - mobj_t *spawn; - fixed_t bottomheight, topheight; - INT32 type = mobj->threshold, line = mobj->cvmem; - - mobj->fuse = (tic_t)mobj->reactiontime; - - bottomheight = lines[line].frontsector->floorheight; - topheight = lines[line].frontsector->ceilingheight - mobjinfo[(mobjtype_t)type].height; - - if (mobj->waterbottom != bottomheight || mobj->watertop != topheight) - { - if (mobj->movefactor && (topheight > bottomheight)) - mobj->health = (tic_t)(FixedDiv((topheight - bottomheight), abs(mobj->movefactor)) >> FRACBITS); - else - mobj->health = 0; - - mobj->z = ((mobj->flags2 & MF2_OBJECTFLIP) ? topheight : bottomheight); - } - - if (!mobj->health) - return; - - for (i = 0; i < mobj->lastlook; i++) - { - spawn = P_SpawnMobj( - mobj->x + FixedMul(FixedMul(mobj->friction, mobj->scale), FINECOSINE(mobj->angle>>ANGLETOFINESHIFT)), - mobj->y + FixedMul(FixedMul(mobj->friction, mobj->scale), FINESINE(mobj->angle>>ANGLETOFINESHIFT)), - mobj->z, - (mobjtype_t)mobj->threshold); - P_SetScale(spawn, mobj->scale); - spawn->momz = FixedMul(mobj->movefactor, spawn->scale); - spawn->destscale = spawn->scale/100; - spawn->scalespeed = spawn->scale/mobj->health; - spawn->tics = (tic_t)mobj->health; - spawn->flags2 |= (mobj->flags2 & MF2_OBJECTFLIP); - spawn->angle += P_RandomKey(36)*ANG10; // irrelevant for default objects but might make sense for some custom ones - - mobj->angle += mobj->movedir; - } - - mobj->angle += (angle_t)mobj->movecount; - } - break; - case MT_FSGNA: - if (mobj->movedir) - mobj->angle += mobj->movedir; - break; - case MT_ROSY: - { - UINT8 i; - fixed_t pdist = 1700*mobj->scale, work, actualwork; - player_t *player = NULL; - statenum_t stat = (mobj->state-states); - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; - if (!players[i].mo) - continue; - if (players[i].bot) - continue; - if (!players[i].mo->health) - continue; - actualwork = work = FixedHypot(mobj->x-players[i].mo->x, mobj->y-players[i].mo->y); - if (player) - { - if (players[i].skin == 0 || players[i].skin == 5) - work = (2*work)/3; - if (work >= pdist) - continue; - } - pdist = actualwork; - player = &players[i]; - } - - if (stat == S_ROSY_JUMP || stat == S_ROSY_PAIN) - { - if (P_IsObjectOnGround(mobj)) - { - mobj->momx = mobj->momy = 0; - if (player && mobj->cvmem < (-2*TICRATE)) - stat = S_ROSY_UNHAPPY; - else - stat = S_ROSY_WALK; - P_SetMobjState(mobj, stat); - } - else if (P_MobjFlip(mobj)*mobj->momz < 0) - mobj->frame = mobj->state->frame+mobj->state->var1; - } - - if (!player) - { - if ((stat < S_ROSY_IDLE1 || stat > S_ROSY_IDLE4) && stat != S_ROSY_JUMP) - { - mobj->momx = mobj->momy = 0; - P_SetMobjState(mobj, S_ROSY_IDLE1); - } - } - else - { - boolean dojump = false, targonground, love, makeheart = false; - if (mobj->target != player->mo) - P_SetTarget(&mobj->target, player->mo); - // Tatsuru: Don't try to hug them if they're above or below you! - targonground = (P_IsObjectOnGround(mobj->target) && (player->panim == PA_IDLE || player->panim == PA_WALK || player->panim == PA_RUN) && player->mo->z == mobj->z); - love = (player->skin == 0 || player->skin == 5); - - switch (stat) - { - case S_ROSY_IDLE1: - case S_ROSY_IDLE2: - case S_ROSY_IDLE3: - case S_ROSY_IDLE4: - dojump = true; - break; - case S_ROSY_JUMP: - case S_ROSY_PAIN: - // handled above - break; - case S_ROSY_WALK: - { - fixed_t x = mobj->x, y = mobj->y, z = mobj->z; - angle_t angletoplayer = R_PointToAngle2(x, y, mobj->target->x, mobj->target->y); - boolean allowed = P_TryMove(mobj, mobj->target->x, mobj->target->y, false); - - P_UnsetThingPosition(mobj); - mobj->x = x; - mobj->y = y; - mobj->z = z; - P_SetThingPosition(mobj); - - if (allowed) - { - fixed_t mom, max; - P_Thrust(mobj, angletoplayer, (3*FRACUNIT)>>1); - mom = FixedHypot(mobj->momx, mobj->momy); - max = pdist; - if ((--mobj->extravalue1) <= 0) - { - if (++mobj->frame > mobj->state->frame+mobj->state->var1) - mobj->frame = mobj->state->frame; - if (mom > 12*mobj->scale) - mobj->extravalue1 = 2; - else if (mom > 6*mobj->scale) - mobj->extravalue1 = 3; - else - mobj->extravalue1 = 4; - } - if (max < (mobj->radius + mobj->target->radius)) - { - mobj->momx = mobj->target->player->cmomx; - mobj->momy = mobj->target->player->cmomy; - if ((mobj->cvmem > TICRATE && !player->exiting) || !targonground) - P_SetMobjState(mobj, (stat = S_ROSY_STND)); - else - { - mobj->target->momx = mobj->momx; - mobj->target->momy = mobj->momy; - P_SetMobjState(mobj, (stat = S_ROSY_HUG)); - S_StartSound(mobj, sfx_cdpcm6); - mobj->angle = angletoplayer; - } - } - else - { - max /= 3; - if (max > 30*mobj->scale) - max = 30*mobj->scale; - if (mom > max && max > mobj->scale) - { - max = FixedDiv(max, mom); - mobj->momx = FixedMul(mobj->momx, max); - mobj->momy = FixedMul(mobj->momy, max); - } - if (abs(mobj->momx) > mobj->scale || abs(mobj->momy) > mobj->scale) - mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy); - } - } - else - dojump = true; - } - break; - case S_ROSY_HUG: - if (targonground) - { - player->pflags |= PF_STASIS; - if (mobj->cvmem < 5*TICRATE) - mobj->cvmem++; - if (love && !(leveltime & 7)) - makeheart = true; - } - else - { - if (mobj->cvmem < (love ? 5*TICRATE : 0)) - { - P_SetMobjState(mobj, (stat = S_ROSY_PAIN)); - S_StartSound(mobj, sfx_cdpcm7); - } - else - P_SetMobjState(mobj, (stat = S_ROSY_JUMP)); - var1 = var2 = 0; - A_DoNPCPain(mobj); - mobj->cvmem -= TICRATE; - } - break; - case S_ROSY_STND: - if ((pdist > (mobj->radius + mobj->target->radius + 3*(mobj->scale + mobj->target->scale)))) - P_SetMobjState(mobj, (stat = S_ROSY_WALK)); - else if (!targonground) - ; - else - { - if (love && !(leveltime & 15)) - makeheart = true; - if (player->exiting || --mobj->cvmem < TICRATE) - { - P_SetMobjState(mobj, (stat = S_ROSY_HUG)); - S_StartSound(mobj, sfx_cdpcm6); - mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); - mobj->target->momx = mobj->momx; - mobj->target->momy = mobj->momy; - } - } - break; - case S_ROSY_UNHAPPY: - default: - break; - } - - if (stat == S_ROSY_HUG) - { - if (player->panim != PA_IDLE) - P_SetPlayerMobjState(mobj->target, S_PLAY_STND); - player->pflags |= PF_STASIS; - } - - if (dojump) - { - P_SetMobjState(mobj, S_ROSY_JUMP); - mobj->z += P_MobjFlip(mobj); - mobj->momx = mobj->momy = 0; - P_SetObjectMomZ(mobj, 6<height, MT_CDLHRT); - cdlhrt->destscale = (5*mobj->scale)>>4; - P_SetScale(cdlhrt, cdlhrt->destscale); - cdlhrt->fuse = (5*TICRATE)>>1; - cdlhrt->momz = mobj->scale; - P_SetTarget(&cdlhrt->target, mobj); - cdlhrt->extravalue1 = mobj->x; - cdlhrt->extravalue2 = mobj->y; - } - } - } - break; - case MT_CDLHRT: - { - if (mobj->cvmem < 24) - mobj->cvmem++; - mobj->movedir += ANG10; - P_UnsetThingPosition(mobj); - mobj->x = mobj->extravalue1 + P_ReturnThrustX(mobj, mobj->movedir, mobj->cvmem*mobj->scale); - mobj->y = mobj->extravalue2 + P_ReturnThrustY(mobj, mobj->movedir, mobj->cvmem*mobj->scale); - P_SetThingPosition(mobj); - if ((--mobj->fuse) < 6) - { - if (!mobj->fuse) - { - P_RemoveMobj(mobj); - return; - } - mobj->frame = (mobj->frame & ~FF_TRANSMASK)|((10-(mobj->fuse*2))<<(FF_TRANSSHIFT)); - } - } - break; - case MT_VWREF: - case MT_VWREB: - { - INT32 strength; - ++mobj->movedir; - mobj->frame &= ~FF_TRANSMASK; - strength = min(mobj->fuse, (INT32)mobj->movedir)*3; - if (strength < 10) - mobj->frame |= ((10-strength)<<(FF_TRANSSHIFT)); - } - /* FALLTHRU */ - default: - if (mobj->fuse) - { // Scenery object fuse! Very basic! - mobj->fuse--; - if (!mobj->fuse) - { -#ifdef HAVE_BLUA - if (!LUAh_MobjFuse(mobj)) -#endif - P_RemoveMobj(mobj); - return; - } - } - break; - } - - P_SceneryThinker(mobj); + P_MobjSceneryThink(mobj); return; } From b49672e3f91da252ca1cd882e0fb1dc75f1b5ccc Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Tue, 24 Dec 2019 17:44:06 -0500 Subject: [PATCH 186/195] Change this condition a bit --- src/p_inter.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/p_inter.c b/src/p_inter.c index 5ec1161ea..52b84059f 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -3439,13 +3439,13 @@ void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source) } } - if (inflictor->type == MT_LHRT) - return; - if (source->player->ctfteam == player->ctfteam) return; } + if (inflictor->type == MT_LHRT) + return; + if (player->powers[pw_shield] || player->bot) //If One-Hit Shield { P_RemoveShield(player); From 8d8e0ca22c79df5cfee65622e78ca1645ed0cddd Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Tue, 24 Dec 2019 17:45:57 -0500 Subject: [PATCH 187/195] Clean up comment --- src/p_inter.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/p_inter.c b/src/p_inter.c index 52b84059f..064551c8c 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -3426,8 +3426,6 @@ void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source) if (player->powers[pw_invulnerability] || player->powers[pw_flashing] || player->powers[pw_super]) return; - // Don't allow players to hurt one another, - // unless cv_friendlyfire is on. if (!cv_friendlyfire.value) { if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) From 5d89e915c6099ec20034ef37212c2dde034b122d Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Wed, 25 Dec 2019 00:14:53 +0100 Subject: [PATCH 188/195] Continue cutting up P_MobjThinker into multiple functions --- src/p_mobj.c | 3500 ++++++++++++++++++++++++++------------------------ 1 file changed, 1793 insertions(+), 1707 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index ab435afce..84592dcaa 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8018,6 +8018,1791 @@ static void P_MobjSceneryThink(mobj_t *mobj) P_SceneryThinker(mobj); } +static boolean P_MobjPushableThink(mobj_t *mobj) +{ + P_MobjCheckWater(mobj); + P_PushableThinker(mobj); + + // Extinguish fire objects in water. (Yes, it's extraordinarily rare to have a pushable flame object, but Brak uses such a case.) + if (mobj->flags & MF_FIRE && mobj->type != MT_PUMA && mobj->type != MT_FIREBALL + && (mobj->eflags & (MFE_UNDERWATER | MFE_TOUCHWATER))) + { + P_KillMobj(mobj, NULL, NULL, 0); + return false; + } + + return true; +} + +static boolean P_MobjBossThink(mobj_t *mobj) +{ +#ifdef HAVE_BLUA + if (LUAh_BossThinker(mobj)) + { + if (P_MobjWasRemoved(mobj)) + return false; + } + else if (P_MobjWasRemoved(mobj)) + return false; + else +#endif + switch (mobj->type) + { + case MT_EGGMOBILE: + if (mobj->health < mobj->info->damage + 1 && leveltime & 2) + { + fixed_t rad = mobj->radius >> FRACBITS; + fixed_t hei = mobj->height >> FRACBITS; + mobj_t *particle = P_SpawnMobjFromMobj(mobj, + P_RandomRange(rad, -rad) << FRACBITS, + P_RandomRange(rad, -rad) << FRACBITS, + P_RandomRange(hei / 2, hei) << FRACBITS, + MT_SMOKE); + P_SetObjectMomZ(particle, 2 << FRACBITS, false); + particle->momz += mobj->momz; + } + if (mobj->flags2 & MF2_SKULLFLY) +#if 1 + P_SpawnGhostMobj(mobj); +#else // all the way back from final demo... MT_THOK isn't even the same size anymore! + { + mobj_t *spawnmobj; + spawnmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->info->painchance); + P_SetTarget(&spawnmobj->target, mobj); + spawnmobj->color = SKINCOLOR_GREY; + } +#endif + P_Boss1Thinker(mobj); + break; + case MT_EGGMOBILE2: + if (mobj->health < mobj->info->damage + 1 && leveltime & 2) + { + fixed_t rad = mobj->radius >> FRACBITS; + fixed_t hei = mobj->height >> FRACBITS; + mobj_t *particle = P_SpawnMobjFromMobj(mobj, + P_RandomRange(rad, -rad) << FRACBITS, + P_RandomRange(rad, -rad) << FRACBITS, + P_RandomRange(hei/2, hei) << FRACBITS, + MT_SMOKE); + P_SetObjectMomZ(particle, 2 << FRACBITS, false); + particle->momz += mobj->momz; + } + P_Boss2Thinker(mobj); + break; + case MT_EGGMOBILE3: + if (mobj->health < mobj->info->damage + 1 && leveltime & 2) + { + fixed_t rad = mobj->radius >> FRACBITS; + fixed_t hei = mobj->height >> FRACBITS; + mobj_t *particle = P_SpawnMobjFromMobj(mobj, + P_RandomRange(rad, -rad) << FRACBITS, + P_RandomRange(rad, -rad) << FRACBITS, + P_RandomRange(hei/2, hei) << FRACBITS, + MT_SMOKE); + P_SetObjectMomZ(particle, 2 << FRACBITS, false); + particle->momz += mobj->momz; + } + P_Boss3Thinker(mobj); + break; + case MT_EGGMOBILE4: + if (mobj->health < mobj->info->damage + 1 && leveltime & 2) + { + fixed_t rad = mobj->radius >> FRACBITS; + fixed_t hei = mobj->height >> FRACBITS; + mobj_t* particle = P_SpawnMobjFromMobj(mobj, + P_RandomRange(rad, -rad) << FRACBITS, + P_RandomRange(rad, -rad) << FRACBITS, + P_RandomRange(hei/2, hei) << FRACBITS, + MT_SMOKE); + P_SetObjectMomZ(particle, 2 << FRACBITS, false); + particle->momz += mobj->momz; + } + P_Boss4Thinker(mobj); + break; + case MT_FANG: + P_Boss5Thinker(mobj); + break; + case MT_BLACKEGGMAN: + P_Boss7Thinker(mobj); + break; + case MT_METALSONIC_BATTLE: + P_Boss9Thinker(mobj); + break; + default: // Generic SOC-made boss + if (mobj->flags2 & MF2_SKULLFLY) + P_SpawnGhostMobj(mobj); + P_GenericBossThinker(mobj); + break; + } + if (mobj->flags2 & MF2_BOSSFLEE) + { + if (mobj->extravalue1) + { + if (!(--mobj->extravalue1)) + { + if (mobj->target) + { + mobj->momz = FixedMul(FixedDiv(mobj->target->z - mobj->z, P_AproxDistance(mobj->x - mobj->target->x, mobj->y - mobj->target->y)), mobj->scale << 1); + mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); + } + else + mobj->momz = 8*mobj->scale; + } + else + mobj->angle += mobj->movedir; + } + else if (mobj->target) + P_InstaThrust(mobj, mobj->angle, FixedMul(12*FRACUNIT, mobj->scale)); + } + if (mobj->type == MT_CYBRAKDEMON && !mobj->health) + { + if (!(mobj->tics & 1)) + { + var1 = 2; + var2 = 0; + A_BossScream(mobj); + } + if (P_CheckDeathPitCollide(mobj)) + { + P_RemoveMobj(mobj); + return false; + } + if (mobj->momz && mobj->z + mobj->momz <= mobj->floorz) + { + S_StartSound(mobj, sfx_befall); + if (mobj->state != states + S_CYBRAKDEMON_DIE8) + P_SetMobjState(mobj, S_CYBRAKDEMON_DIE8); + } + } + return true; +} + +static boolean P_MobjDeadThink(mobj_t *mobj) +{ + switch (mobj->type) + { + case MT_BLUESPHERE: + if ((mobj->tics >> 2) + 1 > 0 && (mobj->tics >> 2) + 1 <= tr_trans60) // tr_trans50 through tr_trans90, shifting once every second frame + mobj->frame = (NUMTRANSMAPS - ((mobj->tics >> 2) + 1)) << FF_TRANSSHIFT; + else // tr_trans60 otherwise + mobj->frame = tr_trans60 << FF_TRANSSHIFT; + break; + case MT_EGGCAPSULE: + if (mobj->z <= mobj->floorz) + { + P_RemoveMobj(mobj); + return false; + } + break; + case MT_FAKEMOBILE: + if (mobj->scale == mobj->destscale) + { + if (!mobj->fuse) + { + S_StartSound(mobj, sfx_s3k77); + mobj->flags2 |= MF2_DONTDRAW; + mobj->fuse = TICRATE; + } + return false; + } + if (!mobj->reactiontime) + { + if (P_RandomChance(FRACUNIT/2)) + mobj->movefactor = FRACUNIT; + else + mobj->movefactor = -FRACUNIT; + if (P_RandomChance(FRACUNIT/2)) + mobj->movedir = ANG20; + else + mobj->movedir = -ANG20; + mobj->reactiontime = 5; + } + mobj->momz += mobj->movefactor; + mobj->angle += mobj->movedir; + P_InstaThrust(mobj, mobj->angle, -mobj->info->speed); + mobj->reactiontime--; + break; + case MT_EGGSHIELD: + mobj->flags2 ^= MF2_DONTDRAW; + break; + case MT_EGGTRAP: // Egg Capsule animal release + if (mobj->fuse > 0)// && mobj->fuse < TICRATE-(TICRATE/7)) + { + INT32 i; + fixed_t x, y, z; + fixed_t ns; + mobj_t* mo2; + mobj_t* flicky; + + z = mobj->subsector->sector->floorheight + FRACUNIT + (P_RandomKey(64) << FRACBITS); + for (i = 0; i < 3; i++) + { + const angle_t fa = P_RandomKey(FINEANGLES) & FINEMASK; + ns = 64*FRACUNIT; + x = mobj->x + FixedMul(FINESINE(fa), ns); + y = mobj->y + FixedMul(FINECOSINE(fa), ns); + + mo2 = P_SpawnMobj(x, y, z, MT_EXPLODE); + P_SetMobjStateNF(mo2, S_XPLD_EGGTRAP); // so the flickies don't lose their target if they spawn + ns = 4*FRACUNIT; + mo2->momx = FixedMul(FINESINE(fa), ns); + mo2->momy = FixedMul(FINECOSINE(fa), ns); + mo2->angle = fa << ANGLETOFINESHIFT; + + if (!i && !(mobj->fuse & 2)) + S_StartSound(mo2, mobj->info->deathsound); + + flicky = P_InternalFlickySpawn(mo2, 0, 8*FRACUNIT, false, -1); + if (!flicky) + break; + + P_SetTarget(&flicky->target, mo2); + flicky->momx = mo2->momx; + flicky->momy = mo2->momy; + } + + mobj->fuse--; + } + break; + case MT_PLAYER: + /// \todo Have the player's dead body completely finish its animation even if they've already respawned. + if (!mobj->fuse) + { // Go away. + /// \todo Actually go ahead and remove mobj completely, and fix any bugs and crashes doing this creates. Chasecam should stop moving, and F12 should never return to it. + mobj->momz = 0; + if (mobj->player) + mobj->flags2 |= MF2_DONTDRAW; + else // safe to remove, nobody's going to complain! + { + P_RemoveMobj(mobj); + return false; + } + } + else // Apply gravity to fall downwards. + { + if (mobj->player && !(mobj->fuse % 8) && (mobj->player->charflags & SF_MACHINE)) + { + fixed_t r = mobj->radius >> FRACBITS; + mobj_t *explosion = P_SpawnMobj( + mobj->x + (P_RandomRange(r, -r) << FRACBITS), + mobj->y + (P_RandomRange(r, -r) << FRACBITS), + mobj->z + (P_RandomKey(mobj->height >> FRACBITS) << FRACBITS), + MT_SONIC3KBOSSEXPLODE); + S_StartSound(explosion, sfx_s3kb4); + } + if (mobj->movedir == DMG_DROWNED) + P_SetObjectMomZ(mobj, -FRACUNIT/2, true); // slower fall from drowning + else + P_SetObjectMomZ(mobj, -2*FRACUNIT/3, true); + } + break; + case MT_METALSONIC_RACE: + { + if (!(mobj->fuse % 8)) + { + fixed_t r = mobj->radius >> FRACBITS; + mobj_t *explosion = P_SpawnMobj( + mobj->x + (P_RandomRange(r, -r) << FRACBITS), + mobj->y + (P_RandomRange(r, -r) << FRACBITS), + mobj->z + (P_RandomKey(mobj->height >> FRACBITS) << FRACBITS), + MT_SONIC3KBOSSEXPLODE); + S_StartSound(explosion, sfx_s3kb4); + } + P_SetObjectMomZ(mobj, -2*FRACUNIT/3, true); + } + break; + default: + break; + } + return true; +} + +// Angle-to-tracer to trigger a linedef exec +// See Linedef Exec 457 (Track mobj angle to point) +static void P_TracerAngleThink(mobj_t *mobj) +{ + if (!mobj->tracer) + return; + + if (!mobj->extravalue2) + return; + + // mobj->lastlook - Don't disable behavior after first failure + // mobj->extravalue1 - Angle tolerance + // mobj->extravalue2 - Exec tag upon failure + // mobj->cvval - Allowable failure delay + // mobj->cvmem - Failure timer + + angle_t ang = mobj->angle - R_PointToAngle2(mobj->x, mobj->y, mobj->tracer->x, mobj->tracer->y); + + // \todo account for distance between mobj and tracer + // Because closer mobjs can be facing beyond the angle tolerance + // yet tracer is still in the camera view + + // failure state: mobj is not facing tracer + // Reasaonable defaults: ANGLE_67h, ANGLE_292h + if (ang >= (angle_t)mobj->extravalue1 && ang <= ANGLE_MAX - (angle_t)mobj->extravalue1) + { + if (mobj->cvmem) + mobj->cvmem--; + else + { + INT32 exectag = mobj->extravalue2; // remember this before we erase the values + + if (mobj->lastlook) + mobj->cvmem = mobj->cusval; // reset timer for next failure + else + { + // disable after first failure + mobj->eflags &= ~MFE_TRACERANGLE; + mobj->lastlook = mobj->extravalue1 = mobj->extravalue2 = mobj->cvmem = mobj->cusval = 0; + } + + P_LinedefExecute(exectag, mobj, NULL); + } + } + else + mobj->cvmem = mobj->cusval; // reset failure timer +} + +static void P_ArrowThink(mobj_t *mobj) +{ + if (mobj->flags & MF_MISSILE) + { + // Calculate the angle of movement. + /* + momz + / | + / | + / | + 0------dist(momx,momy) + */ + + fixed_t dist = P_AproxDistance(mobj->momx, mobj->momy); + angle_t angle = R_PointToAngle2(0, 0, dist, mobj->momz); + + if (angle > ANG20 && angle <= ANGLE_180) + mobj->frame = 2; + else if (angle < ANG340 && angle > ANGLE_180) + mobj->frame = 0; + else + mobj->frame = 1; + + if (!(mobj->extravalue1) && (mobj->momz < 0)) + { + mobj->extravalue1 = 1; + S_StartSound(mobj, mobj->info->activesound); + } + if (leveltime & 1) + { + mobj_t *dust = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_PARTICLE); + dust->tics = 18; + dust->scalespeed = 4096; + dust->destscale = FRACUNIT/32; + } + } + else + mobj->flags2 ^= MF2_DONTDRAW; +} + +static void P_BumbleboreThink(mobj_t *mobj) +{ + statenum_t st = mobj->state - states; + if (st == S_BUMBLEBORE_FLY1 || st == S_BUMBLEBORE_FLY2) + { + if (!mobj->target) + P_SetMobjState(mobj, mobj->info->spawnstate); + else if (P_MobjFlip(mobj)*((mobj->z + (mobj->height >> 1)) - (mobj->target->z + (mobj->target->height >> 1))) > 0 + && R_PointToDist2(mobj->x, mobj->y, mobj->target->x, mobj->target->y) <= 32*FRACUNIT) + { + mobj->momx >>= 1; + mobj->momy >>= 1; + if (++mobj->movefactor == 4) + { + S_StartSound(mobj, mobj->info->seesound); + mobj->momx = mobj->momy = mobj->momz = 0; + mobj->flags = (mobj->flags|MF_PAIN) & ~MF_NOGRAVITY; + P_SetMobjState(mobj, mobj->info->meleestate); + } + } + else + mobj->movefactor = 0; + } + else if (st == S_BUMBLEBORE_RAISE || st == S_BUMBLEBORE_FALL2) // no _FALL1 because it's an 0-tic + { + if (P_IsObjectOnGround(mobj)) + { + S_StopSound(mobj); + S_StartSound(mobj, mobj->info->attacksound); + mobj->flags = (mobj->flags | MF_NOGRAVITY) & ~MF_PAIN; + mobj->momx = mobj->momy = mobj->momz = 0; + P_SetMobjState(mobj, mobj->info->painstate); + } + else + { + mobj->angle += ANGLE_22h; + mobj->frame = mobj->state->frame + ((mobj->tics & 2) >> 1); + } + } + else if (st == S_BUMBLEBORE_STUCK2 && mobj->tics < TICRATE) + mobj->frame = mobj->state->frame + ((mobj->tics & 2) >> 1); +} + +static boolean P_HangsterThink(mobj_t *mobj) +{ + statenum_t st = mobj->state - states; + //ghost image trail when flying down + if (st == S_HANGSTER_SWOOP1 || st == S_HANGSTER_SWOOP2) + { + P_SpawnGhostMobj(mobj); + //curve when in line with target, otherwise curve to avoid crashing into floor + if ((mobj->z - mobj->floorz <= 80*FRACUNIT) || (mobj->target && (mobj->z - mobj->target->z <= 80*FRACUNIT))) + P_SetMobjState(mobj, (st = S_HANGSTER_ARC1)); + } + + //swoop arc movement stuff + if (st == S_HANGSTER_ARC1) + { + A_FaceTarget(mobj); + P_Thrust(mobj, mobj->angle, 1*FRACUNIT); + } + else if (st == S_HANGSTER_ARC2) + P_Thrust(mobj, mobj->angle, 2*FRACUNIT); + else if (st == S_HANGSTER_ARC3) + P_Thrust(mobj, mobj->angle, 4*FRACUNIT); + //if movement has stopped while flying (like hitting a wall), fly up immediately + else if (st == S_HANGSTER_FLY1 && !mobj->momx && !mobj->momy) + { + mobj->extravalue1 = 0; + P_SetMobjState(mobj, S_HANGSTER_ARCUP1); + } + //after swooping back up, check for ceiling + else if ((st == S_HANGSTER_RETURN1 || st == S_HANGSTER_RETURN2) && mobj->momz == 0 && mobj->ceilingz == (mobj->z + mobj->height)) + P_SetMobjState(mobj, (st = S_HANGSTER_RETURN3)); + + //should you roost on a ceiling with F_SKY1 as its flat, disappear forever + if (st == S_HANGSTER_RETURN3 && mobj->momz == 0 && mobj->ceilingz == (mobj->z + mobj->height) + && mobj->subsector->sector->ceilingpic == skyflatnum + && mobj->subsector->sector->ceilingheight == mobj->ceilingz) + { + P_RemoveMobj(mobj); + return false; + } + + return true; +} + +static boolean P_JetFume1Think(mobj_t *mobj) +{ + fixed_t jetx, jety; + + if (!mobj->target // if you have no target + || (!(mobj->target->flags & MF_BOSS) && mobj->target->health <= 0)) // or your target isn't a boss and it's popped now + { // then remove yourself as well! + P_RemoveMobj(mobj); + return false; + } + + jetx = mobj->target->x + P_ReturnThrustX(mobj->target, mobj->target->angle, FixedMul(-64*FRACUNIT, mobj->target->scale)); + jety = mobj->target->y + P_ReturnThrustY(mobj->target, mobj->target->angle, FixedMul(-64*FRACUNIT, mobj->target->scale)); + + if (mobj->fuse == 56) // First one + { + P_UnsetThingPosition(mobj); + mobj->x = jetx; + mobj->y = jety; + if (mobj->target->eflags & MFE_VERTICALFLIP) + mobj->z = mobj->target->z + mobj->target->height - mobj->height - FixedMul(38*FRACUNIT, mobj->target->scale); + else + mobj->z = mobj->target->z + FixedMul(38*FRACUNIT, mobj->target->scale); + mobj->floorz = mobj->z; + mobj->ceilingz = mobj->z + mobj->height; + P_SetThingPosition(mobj); + } + else if (mobj->fuse == 57) + { + P_UnsetThingPosition(mobj); + mobj->x = jetx + P_ReturnThrustX(mobj->target, mobj->target->angle - ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); + mobj->y = jety + P_ReturnThrustY(mobj->target, mobj->target->angle - ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); + if (mobj->target->eflags & MFE_VERTICALFLIP) + mobj->z = mobj->target->z + mobj->target->height - mobj->height - FixedMul(12*FRACUNIT, mobj->target->scale); + else + mobj->z = mobj->target->z + FixedMul(12*FRACUNIT, mobj->target->scale); + mobj->floorz = mobj->z; + mobj->ceilingz = mobj->z + mobj->height; + P_SetThingPosition(mobj); + } + else if (mobj->fuse == 58) + { + P_UnsetThingPosition(mobj); + mobj->x = jetx + P_ReturnThrustX(mobj->target, mobj->target->angle + ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); + mobj->y = jety + P_ReturnThrustY(mobj->target, mobj->target->angle + ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); + if (mobj->target->eflags & MFE_VERTICALFLIP) + mobj->z = mobj->target->z + mobj->target->height - mobj->height - FixedMul(12*FRACUNIT, mobj->target->scale); + else + mobj->z = mobj->target->z + FixedMul(12*FRACUNIT, mobj->target->scale); + mobj->floorz = mobj->z; + mobj->ceilingz = mobj->z + mobj->height; + P_SetThingPosition(mobj); + } + else if (mobj->fuse == 59) + { + boolean dashmod = ((mobj->target->flags & MF_PAIN) && (mobj->target->health <= mobj->target->info->damage)); + jetx = mobj->target->x + P_ReturnThrustX(mobj->target, mobj->target->angle, -mobj->target->radius); + jety = mobj->target->y + P_ReturnThrustY(mobj->target, mobj->target->angle, -mobj->target->radius); + P_UnsetThingPosition(mobj); + mobj->x = jetx; + mobj->y = jety; + mobj->destscale = mobj->target->scale; + if (!(dashmod && mobj->target->state == states + S_METALSONIC_BOUNCE)) + { + mobj->destscale = (mobj->destscale + FixedDiv(R_PointToDist2(0, 0, mobj->target->momx, mobj->target->momy), 36*mobj->target->scale))/3; + } + if (mobj->target->eflags & MFE_VERTICALFLIP) + mobj->z = mobj->target->z + mobj->target->height/2 + mobj->height/2; + else + mobj->z = mobj->target->z + mobj->target->height/2 - mobj->height/2; + mobj->floorz = mobj->z; + mobj->ceilingz = mobj->z + mobj->height; + P_SetThingPosition(mobj); + if (dashmod) + { + mobj->color = SKINCOLOR_SUNSET; + if (mobj->target->movecount == 3 && !mobj->target->reactiontime && (mobj->target->movedir == 0 || mobj->target->movedir == 2)) + P_SpawnGhostMobj(mobj); + } + else + mobj->color = SKINCOLOR_ICY; + } + mobj->fuse++; + return true; +} + +static boolean P_EggRobo1Think(mobj_t *mobj) +{ +#define SPECTATORRADIUS (96*mobj->scale) + if (!(mobj->flags2 & MF2_STRONGBOX)) + { + mobj->cusval = mobj->x; // eat my SOCs, p_mobj.h warning, we have lua now + mobj->cvmem = mobj->y; // ditto + mobj->movedir = mobj->angle; + mobj->threshold = P_MobjFlip(mobj)*10*mobj->scale; + if (mobj->threshold < 0) + mobj->threshold += (mobj->ceilingz - mobj->height); + else + mobj->threshold += mobj->floorz; + var1 = 4; + A_BossJetFume(mobj); + mobj->flags2 |= MF2_STRONGBOX; + } + + if (mobj->state == &states[mobj->info->deathstate]) // todo: make map actually set health to 0 for these + { + if (mobj->movecount) + { + if (!(--mobj->movecount)) + S_StartSound(mobj, mobj->info->deathsound); + } + else + { + mobj->momz += P_MobjFlip(mobj)*mobj->scale; + if (mobj->momz > 0) + { + if (mobj->z + mobj->momz > mobj->ceilingz + (1000 << FRACBITS)) + { + P_RemoveMobj(mobj); + return false; + } + } + else if (mobj->z + mobj->height + mobj->momz < mobj->floorz - (1000 << FRACBITS)) + { + P_RemoveMobj(mobj); + return false; + } + } + } + else + { + fixed_t basex = mobj->cusval, basey = mobj->cvmem; + + if (mobj->spawnpoint && mobj->spawnpoint->options & (MTF_AMBUSH|MTF_OBJECTSPECIAL)) + { + angle_t sideang = mobj->movedir + ((mobj->spawnpoint->options & MTF_AMBUSH) ? ANGLE_90 : -ANGLE_90); + fixed_t oscillate = FixedMul(FINESINE(((leveltime * ANG1) >> (ANGLETOFINESHIFT + 2)) & FINEMASK), 250*mobj->scale); + basex += P_ReturnThrustX(mobj, sideang, oscillate); + basey += P_ReturnThrustY(mobj, sideang, oscillate); + } + + mobj->z = mobj->threshold + FixedMul(FINESINE(((leveltime + mobj->movecount)*ANG2 >> (ANGLETOFINESHIFT - 2)) & FINEMASK), 8*mobj->scale); + if (mobj->state != &states[mobj->info->meleestate]) + { + boolean didmove = false; + + if (mobj->state == &states[mobj->info->spawnstate]) + { + UINT8 i; + fixed_t dist = INT32_MAX; + + for (i = 0; i < MAXPLAYERS; i++) + { + fixed_t compdist; + if (!playeringame[i]) + continue; + if (players[i].spectator) + continue; + if (!players[i].mo) + continue; + if (!players[i].mo->health) + continue; + if (P_PlayerInPain(&players[i])) + continue; + if (players[i].mo->z > mobj->z + mobj->height + 8*mobj->scale) + continue; + if (players[i].mo->z + players[i].mo->height < mobj->z - 8*mobj->scale) + continue; + compdist = P_AproxDistance( + players[i].mo->x + players[i].mo->momx - basex, + players[i].mo->y + players[i].mo->momy - basey); + if (compdist >= dist) + continue; + dist = compdist; + P_SetTarget(&mobj->target, players[i].mo); + } + + if (dist < (SPECTATORRADIUS << 1)) + { + didmove = true; + mobj->frame = 3 + ((leveltime & 2) >> 1); + mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); + + if (P_AproxDistance( + mobj->x - basex, + mobj->y - basey) + < mobj->scale) + S_StartSound(mobj, mobj->info->seesound); + + P_TeleportMove(mobj, + (15*(mobj->x >> 4)) + (basex >> 4) + P_ReturnThrustX(mobj, mobj->angle, SPECTATORRADIUS >> 4), + (15*(mobj->y >> 4)) + (basey >> 4) + P_ReturnThrustY(mobj, mobj->angle, SPECTATORRADIUS >> 4), + mobj->z); + } + else + { + angle_t diff = (mobj->movedir - mobj->angle); + if (diff > ANGLE_180) + diff = InvAngle(InvAngle(diff)/8); + else + diff /= 8; + mobj->angle += diff; + + dist = FINECOSINE(((leveltime + mobj->movecount)*ANG2 >> (ANGLETOFINESHIFT - 2)) & FINEMASK); + + if (abs(dist) < FRACUNIT/2) + mobj->frame = 0; + else + mobj->frame = (dist > 0) ? 1 : 2; + } + } + + if (!didmove) + { + if (P_AproxDistance(mobj->x - basex, mobj->y - basey) < mobj->scale) + P_TeleportMove(mobj, basex, basey, mobj->z); + else + P_TeleportMove(mobj, + (15*(mobj->x >> 4)) + (basex >> 4), + (15*(mobj->y >> 4)) + (basey >> 4), + mobj->z); + } + } + } + return true; +#undef SPECTATORRADIUS +} + +static void P_NiGHTSDroneThink(mobj_t *mobj) +{ + { + // variable setup + mobj_t *goalpost = NULL; + mobj_t *sparkle = NULL; + mobj_t *droneman = NULL; + + boolean flip = mobj->flags2 & MF2_OBJECTFLIP; + boolean topaligned = (mobj->flags & MF_SLIDEME) && !(mobj->flags & MF_GRENADEBOUNCE); + boolean middlealigned = (mobj->flags & MF_GRENADEBOUNCE) && !(mobj->flags & MF_SLIDEME); + boolean bottomoffsetted = !(mobj->flags & MF_SLIDEME) && !(mobj->flags & MF_GRENADEBOUNCE); + boolean flipchanged = false; + + fixed_t dronemanoffset, goaloffset, sparkleoffset, droneboxmandiff, dronemangoaldiff; + + if (mobj->target && mobj->target->type == MT_NIGHTSDRONE_GOAL) + { + goalpost = mobj->target; + if (goalpost->target && goalpost->target->type == MT_NIGHTSDRONE_SPARKLING) + sparkle = goalpost->target; + if (goalpost->tracer && goalpost->tracer->type == MT_NIGHTSDRONE_MAN) + droneman = goalpost->tracer; + } + + if (!goalpost || !sparkle || !droneman) + return; + + // did NIGHTSDRONE position, scale, flip, or flags change? all elements need to be synced + droneboxmandiff = max(mobj->height - droneman->height, 0); + dronemangoaldiff = max(droneman->height - goalpost->height, 0); + + if (!(goalpost->flags2 & MF2_OBJECTFLIP) && (mobj->flags2 & MF2_OBJECTFLIP)) + { + goalpost->eflags |= MFE_VERTICALFLIP; + goalpost->flags2 |= MF2_OBJECTFLIP; + sparkle->eflags |= MFE_VERTICALFLIP; + sparkle->flags2 |= MF2_OBJECTFLIP; + droneman->eflags |= MFE_VERTICALFLIP; + droneman->flags2 |= MF2_OBJECTFLIP; + flipchanged = true; + } + else if ((goalpost->flags2 & MF2_OBJECTFLIP) && !(mobj->flags2 & MF2_OBJECTFLIP)) + { + goalpost->eflags &= ~MFE_VERTICALFLIP; + goalpost->flags2 &= ~MF2_OBJECTFLIP; + sparkle->eflags &= ~MFE_VERTICALFLIP; + sparkle->flags2 &= ~MF2_OBJECTFLIP; + droneman->eflags &= ~MFE_VERTICALFLIP; + droneman->flags2 &= ~MF2_OBJECTFLIP; + flipchanged = true; + } + + if (goalpost->destscale != mobj->destscale + || goalpost->movefactor != mobj->z + || goalpost->friction != mobj->height + || flipchanged + || goalpost->threshold != (INT32)(mobj->flags & (MF_SLIDEME|MF_GRENADEBOUNCE))) + { + goalpost->destscale = sparkle->destscale = droneman->destscale = mobj->destscale; + + // straight copy-pasta from P_SpawnMapThing, case MT_NIGHTSDRONE + if (!flip) + { + if (topaligned) // Align droneman to top of hitbox + { + dronemanoffset = droneboxmandiff; + goaloffset = dronemangoaldiff/2 + dronemanoffset; + } + else if (middlealigned) // Align droneman to center of hitbox + { + dronemanoffset = droneboxmandiff/2; + goaloffset = dronemangoaldiff/2 + dronemanoffset; + } + else if (bottomoffsetted) + { + dronemanoffset = 24*FRACUNIT; + goaloffset = dronemangoaldiff + dronemanoffset; + } + else + { + dronemanoffset = 0; + goaloffset = dronemangoaldiff/2 + dronemanoffset; + } + + sparkleoffset = goaloffset - FixedMul(15*FRACUNIT, mobj->scale); + } + else + { + if (topaligned) // Align droneman to top of hitbox + { + dronemanoffset = 0; + goaloffset = dronemangoaldiff/2 + dronemanoffset; + } + else if (middlealigned) // Align droneman to center of hitbox + { + dronemanoffset = droneboxmandiff/2; + goaloffset = dronemangoaldiff/2 + dronemanoffset; + } + else if (bottomoffsetted) + { + dronemanoffset = droneboxmandiff - FixedMul(24*FRACUNIT, mobj->scale); + goaloffset = dronemangoaldiff + dronemanoffset; + } + else + { + dronemanoffset = droneboxmandiff; + goaloffset = dronemangoaldiff/2 + dronemanoffset; + } + + sparkleoffset = goaloffset + FixedMul(15*FRACUNIT, mobj->scale); + } + + P_TeleportMove(goalpost, mobj->x, mobj->y, mobj->z + goaloffset); + P_TeleportMove(sparkle, mobj->x, mobj->y, mobj->z + sparkleoffset); + if (goalpost->movefactor != mobj->z || goalpost->friction != mobj->height) + { + P_TeleportMove(droneman, mobj->x, mobj->y, mobj->z + dronemanoffset); + goalpost->movefactor = mobj->z; + goalpost->friction = mobj->height; + } + goalpost->threshold = mobj->flags & (MF_SLIDEME|MF_GRENADEBOUNCE); + } + else + { + if (goalpost->x != mobj->x || goalpost->y != mobj->y) + { + P_TeleportMove(goalpost, mobj->x, mobj->y, goalpost->z); + P_TeleportMove(sparkle, mobj->x, mobj->y, sparkle->z); + } + + if (droneman->x != mobj->x || droneman->y != mobj->y) + P_TeleportMove(droneman, mobj->x, mobj->y, + droneman->z >= mobj->floorz && droneman->z <= mobj->ceilingz ? droneman->z : mobj->z); + } + + // now toggle states! + // GOAL mode? + if (sparkle->state >= &states[S_NIGHTSDRONE_SPARKLING1] && sparkle->state <= &states[S_NIGHTSDRONE_SPARKLING16]) + { + INT32 i; + boolean bonustime = false; + + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && players[i].bonustime && players[i].powers[pw_carry] == CR_NIGHTSMODE) + { + bonustime = true; + break; + } + + if (!bonustime) + { + CONS_Debug(DBG_NIGHTSBASIC, "Removing goal post\n"); + if (goalpost && goalpost->state != &states[S_INVISIBLE]) + P_SetMobjState(goalpost, S_INVISIBLE); + if (sparkle && sparkle->state != &states[S_INVISIBLE]) + P_SetMobjState(sparkle, S_INVISIBLE); + } + } + // Invisible/bouncing mode. + else + { + INT32 i; + boolean bonustime = false; + fixed_t zcomp; + + // Bouncy bouncy! + if (!flip) + { + if (topaligned) + zcomp = droneboxmandiff + mobj->z; + else if (middlealigned) + zcomp = (droneboxmandiff/2) + mobj->z; + else if (bottomoffsetted) + zcomp = mobj->z + FixedMul(24*FRACUNIT, mobj->scale); + else + zcomp = mobj->z; + } + else + { + if (topaligned) + zcomp = mobj->z; + else if (middlealigned) + zcomp = (droneboxmandiff/2) + mobj->z; + else if (bottomoffsetted) + zcomp = mobj->z + droneboxmandiff - FixedMul(24*FRACUNIT, mobj->scale); + else + zcomp = mobj->z + droneboxmandiff; + } + + droneman->angle += ANG10; + if (!flip && droneman->z <= zcomp) + droneman->momz = FixedMul(5*FRACUNIT, droneman->scale); + else if (flip && droneman->z >= zcomp) + droneman->momz = FixedMul(-5*FRACUNIT, droneman->scale); + + // state switching logic + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && players[i].bonustime && players[i].powers[pw_carry] == CR_NIGHTSMODE) + { + bonustime = true; + break; + } + + if (bonustime) + { + CONS_Debug(DBG_NIGHTSBASIC, "Adding goal post\n"); + if (!(droneman->flags2 & MF2_DONTDRAW)) + droneman->flags2 |= MF2_DONTDRAW; + if (goalpost->state == &states[S_INVISIBLE]) + P_SetMobjState(goalpost, mobjinfo[goalpost->type].meleestate); + if (sparkle->state == &states[S_INVISIBLE]) + P_SetMobjState(sparkle, mobjinfo[sparkle->type].meleestate); + } + else if (!G_IsSpecialStage(gamemap)) + { + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && players[i].powers[pw_carry] != CR_NIGHTSMODE) + { + bonustime = true; // variable reuse + break; + } + + if (bonustime) + { + // show droneman if at least one player is non-nights + if (goalpost->state != &states[S_INVISIBLE]) + P_SetMobjState(goalpost, S_INVISIBLE); + if (sparkle->state != &states[S_INVISIBLE]) + P_SetMobjState(sparkle, S_INVISIBLE); + if (droneman->state != &states[mobjinfo[droneman->type].meleestate]) + P_SetMobjState(droneman, mobjinfo[droneman->type].meleestate); + if (droneman->flags2 & MF2_DONTDRAW) + droneman->flags2 &= ~MF2_DONTDRAW; + } + else + { + // else, hide it + if (!(droneman->flags2 & MF2_DONTDRAW)) + droneman->flags2 |= MF2_DONTDRAW; + } + } + } + } +} + +static boolean P_TurretThink(mobj_t *mobj) +{ + P_MobjCheckWater(mobj); + P_CheckPosition(mobj, mobj->x, mobj->y); + if (P_MobjWasRemoved(mobj)) + return false; + mobj->floorz = tmfloorz; + mobj->ceilingz = tmceilingz; + mobj->floorrover = tmfloorrover; + mobj->ceilingrover = tmceilingrover; + + if ((mobj->eflags & MFE_UNDERWATER) && mobj->health > 0) + { + P_SetMobjState(mobj, mobj->info->deathstate); + mobj->health = 0; + mobj->flags2 &= ~MF2_FIRING; + } + else if (mobj->health > 0 && mobj->z + mobj->height > mobj->ceilingz) // Crushed + { + INT32 i, j; + fixed_t ns; + fixed_t x, y, z; + mobj_t* mo2; + + z = mobj->subsector->sector->floorheight + FixedMul(64*FRACUNIT, mobj->scale); + for (j = 0; j < 2; j++) + { + for (i = 0; i < 32; i++) + { + const angle_t fa = (i*FINEANGLES/16) & FINEMASK; + ns = FixedMul(64*FRACUNIT, mobj->scale); + x = mobj->x + FixedMul(FINESINE(fa), ns); + y = mobj->y + FixedMul(FINECOSINE(fa), ns); + + mo2 = P_SpawnMobj(x, y, z, MT_EXPLODE); + ns = FixedMul(16*FRACUNIT, mobj->scale); + mo2->momx = FixedMul(FINESINE(fa), ns); + mo2->momy = FixedMul(FINECOSINE(fa), ns); + } + z -= FixedMul(32*FRACUNIT, mobj->scale); + } + P_SetMobjState(mobj, mobj->info->deathstate); + mobj->health = 0; + mobj->flags2 &= ~MF2_FIRING; + } + return true; +} + +static void P_SaloonDoorThink(mobj_t *mobj) +{ + fixed_t x = mobj->tracer->x; + fixed_t y = mobj->tracer->y; + fixed_t z = mobj->tracer->z; + angle_t oang = FixedAngle(mobj->extravalue1); + angle_t fa = (oang >> ANGLETOFINESHIFT) & FINEMASK; + fixed_t c0 = -96*FINECOSINE(fa); + fixed_t s0 = -96*FINESINE(fa); + angle_t fma; + fixed_t c, s; + angle_t angdiff; + + // Adjust angular speed + fixed_t da = AngleFixed(mobj->angle - oang); + if (da > 180*FRACUNIT) + da -= 360*FRACUNIT; + mobj->extravalue2 = 8*(mobj->extravalue2 - da/32)/9; + + // Update angle + mobj->angle += FixedAngle(mobj->extravalue2); + + angdiff = mobj->angle - FixedAngle(mobj->extravalue1); + if (angdiff > (ANGLE_90 - ANG2) && angdiff < ANGLE_180) + { + mobj->angle = FixedAngle(mobj->extravalue1) + (ANGLE_90 - ANG2); + mobj->extravalue2 /= 2; + } + else if (angdiff < (ANGLE_270 + ANG2) && angdiff >= ANGLE_180) + { + mobj->angle = FixedAngle(mobj->extravalue1) + (ANGLE_270 + ANG2); + mobj->extravalue2 /= 2; + } + + // Update position + fma = (mobj->angle >> ANGLETOFINESHIFT) & FINEMASK; + c = 48*FINECOSINE(fma); + s = 48*FINESINE(fma); + P_TeleportMove(mobj, x + c0 + c, y + s0 + s, z); +} + +static void P_PyreFlyThink(mobj_t *mobj) +{ + fixed_t hdist; + + mobj->extravalue1 = (mobj->extravalue1 + 3) % 360; + mobj->z += FINESINE(((mobj->extravalue1 * ANG1) >> ANGLETOFINESHIFT) & FINEMASK); + + if (!(mobj->flags2 & MF2_BOSSNOTRAP)) + P_LookForPlayers(mobj, true, false, 1500*FRACUNIT); + + if (!mobj->target) + return; + + if (mobj->extravalue2 == 1) + P_PyreFlyBurn(mobj, 0, 20, MT_SMOKE, 4*FRACUNIT); + else if (mobj->extravalue2 == 2) + { + INT32 fireradius = min(100 - mobj->fuse, 52); + P_PyreFlyBurn(mobj, P_RandomRange(0, fireradius) << FRACBITS, 20, MT_FLAMEPARTICLE, 4*FRACUNIT); + P_PyreFlyBurn(mobj, fireradius*FRACUNIT, 40, MT_PYREFLY_FIRE, 0); + } + + hdist = R_PointToDist2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); + + if (hdist > 1500*FRACUNIT) + { + mobj->flags2 &= ~MF2_BOSSNOTRAP; + P_SetTarget(&mobj->target, NULL); + return; + } + + if (!(mobj->flags2 & MF2_BOSSNOTRAP) && hdist <= 450*FRACUNIT) + mobj->flags2 |= MF2_BOSSNOTRAP; + + if (!(mobj->flags2 & MF2_BOSSNOTRAP)) + return; + + if (hdist < 1000*FRACUNIT) + { + //Aim for player z position. If too close to floor/ceiling, aim just above/below them. + fixed_t destz = min(max(mobj->target->z, mobj->target->floorz + 70*FRACUNIT), mobj->target->ceilingz - 80*FRACUNIT - mobj->height); + fixed_t dist = P_AproxDistance(hdist, destz - mobj->z); + P_InstaThrust(mobj, R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y), 2*FRACUNIT); + mobj->momz = FixedMul(FixedDiv(destz - mobj->z, dist), 2*FRACUNIT); + } + else + { + mobj->momx = 0; + mobj->momy = 0; + mobj->momz = 0; + } +} + +static void P_PterabyteThink(mobj_t *mobj) +{ + if (mobj->extravalue1 & 4) // Cooldown after grabbing + { + if (mobj->movefactor) + mobj->movefactor--; + else + { + P_SetTarget(&mobj->target, NULL); + mobj->extravalue1 &= 3; + } + } + + if ((mobj->extravalue1 & 3) == 0) // Hovering + { + fixed_t vdist, hdist, time; + fixed_t hspeed = 3*mobj->info->speed; + angle_t fa; + + var1 = 1; + var2 = 0; + A_CapeChase(mobj); + + if (mobj->target) + return; // Still carrying a player or in cooldown + + P_LookForPlayers(mobj, true, false, 256*FRACUNIT); + + if (!mobj->target) + return; + + if (mobj->target->player->powers[pw_flashing]) + { + P_SetTarget(&mobj->target, NULL); + return; + } + + vdist = mobj->z - mobj->target->z - mobj->target->height; + if (P_MobjFlip(mobj)*vdist <= 0) + { + P_SetTarget(&mobj->target, NULL); + return; + } + + hdist = R_PointToDist2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); + if (hdist > 450*FRACUNIT) + { + P_SetTarget(&mobj->target, NULL); + return; + } + + P_SetMobjState(mobj, S_PTERABYTE_SWOOPDOWN); + mobj->extravalue1++; + S_StartSound(mobj, mobj->info->attacksound); + time = FixedDiv(hdist, hspeed); + mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); + fa = (mobj->angle >> ANGLETOFINESHIFT) & FINEMASK; + mobj->momx = FixedMul(FINECOSINE(fa), hspeed); + mobj->momy = FixedMul(FINESINE(fa), hspeed); + mobj->momz = -2*FixedDiv(vdist, time); + mobj->extravalue2 = -FixedDiv(mobj->momz, time); //Z accel + mobj->movecount = time >> FRACBITS; + mobj->reactiontime = mobj->movecount; + } + else if ((mobj->extravalue1 & 3) == 1) // Swooping + { + mobj->reactiontime--; + mobj->momz += mobj->extravalue2; + if (mobj->reactiontime) + return; + + if (mobj->state - states == S_PTERABYTE_SWOOPDOWN) + { + P_SetMobjState(mobj, S_PTERABYTE_SWOOPUP); + mobj->reactiontime = mobj->movecount; + } + else if (mobj->state - states == S_PTERABYTE_SWOOPUP) + { + P_SetMobjState(mobj, S_PTERABYTE_FLY1); + mobj->extravalue1++; + if (mobj->target && mobj->target->tracer != mobj) + P_SetTarget(&mobj->target, NULL); // Failed to grab the target + mobj->momx = mobj->momy = mobj->momz = 0; + } + } + else // Returning + { + var1 = 2*mobj->info->speed; + var2 = 1; + A_HomingChase(mobj); + if (P_AproxDistance(mobj->x - mobj->tracer->x, mobj->y - mobj->tracer->y) <= mobj->info->speed) + { + mobj->extravalue1 -= 2; + mobj->momx = mobj->momy = mobj->momz = 0; + } + } +} + +static void P_DragonbomberThink(mobj_t *mobj) +{ +#define DRAGONTURNSPEED ANG2 + mobj->movecount = (mobj->movecount + 9) % 360; + P_SetObjectMomZ(mobj, 4*FINESINE(((mobj->movecount*ANG1) >> ANGLETOFINESHIFT) & FINEMASK), false); + if (mobj->threshold > 0) // are we dropping mines? + { + mobj->threshold--; + if (mobj->threshold == 0) // if the timer hits 0, look for a mine to drop! + { + mobj_t *segment = mobj; + while (segment->tracer != NULL && !P_MobjWasRemoved(segment->tracer) && segment->tracer->state == &states[segment->tracer->info->spawnstate]) + segment = segment->tracer; + if (segment != mobj) // found an unactivated segment? + { + mobj_t *mine = P_SpawnMobjFromMobj(segment, 0, 0, 0, segment->info->painchance); + mine->angle = segment->angle; + P_InstaThrust(mine, mobj->angle, P_AproxDistance(mobj->momx, mobj->momy) >> 1); + P_SetObjectMomZ(mine, -2*FRACUNIT, true); + S_StartSound(mine, mine->info->seesound); + P_SetMobjState(segment, segment->info->raisestate); + mobj->threshold = mobj->info->painchance; + } + } + } + if (mobj->target) // Are we chasing a player? + { + fixed_t dist = P_AproxDistance(mobj->x - mobj->target->x, mobj->y - mobj->target->y); + if (dist > 2000*mobj->scale) // Not anymore! + P_SetTarget(&mobj->target, NULL); + else + { + fixed_t vspeed = FixedMul(mobj->info->speed >> 3, mobj->scale); + fixed_t z = mobj->target->z + (mobj->height >> 1) + (mobj->flags & MFE_VERTICALFLIP ? -128*mobj->scale : 128*mobj->scale + mobj->target->height); + angle_t diff = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y) - mobj->angle; + if (diff > ANGLE_180) + mobj->angle -= DRAGONTURNSPEED; + else + mobj->angle += DRAGONTURNSPEED; + if (!mobj->threshold && dist < 512*mobj->scale) // Close enough to drop bombs + { + mobj->threshold = mobj->info->painchance; + } + mobj->momz += max(min(z - mobj->z, vspeed), -vspeed); + } + } + else // Can we find a player to chase? + { + if (mobj->tracer == NULL || mobj->tracer->state != &states[mobj->tracer->info->spawnstate] + || !P_LookForPlayers(mobj, true, false, 2000*mobj->scale)) // if not, circle around the spawnpoint + { + if (!mobj->spawnpoint) // unless we don't have one, in which case uhhh just circle around wherever we currently are I guess?? + mobj->angle += DRAGONTURNSPEED; + else + { + fixed_t vspeed = FixedMul(mobj->info->speed >> 3, mobj->scale); + fixed_t x = mobj->spawnpoint->x << FRACBITS; + fixed_t y = mobj->spawnpoint->y << FRACBITS; + fixed_t z = mobj->spawnpoint->z << FRACBITS; + angle_t diff = R_PointToAngle2(mobj->x, mobj->y, x, y) - mobj->angle; + if (diff > ANGLE_180) + mobj->angle -= DRAGONTURNSPEED; + else + mobj->angle += DRAGONTURNSPEED; + mobj->momz += max(min(z - mobj->z, vspeed), -vspeed); + } + } + } + P_InstaThrust(mobj, mobj->angle, FixedMul(mobj->info->speed, mobj->scale)); +#undef DRAGONTURNSPEED +} + +static boolean P_MobjRegularThink(mobj_t *mobj) +{ + if ((mobj->flags & MF_ENEMY) && (mobj->state->nextstate == mobj->info->spawnstate && mobj->tics == 1)) + mobj->flags2 &= ~MF2_FRET; + + if (mobj->eflags & MFE_TRACERANGLE) + P_TracerAngleThink(mobj); + + switch (mobj->type) + { + case MT_WALLSPIKEBASE: + if (!mobj->target) { + P_RemoveMobj(mobj); + return false; + } + mobj->frame = (mobj->frame & ~FF_FRAMEMASK)|(mobj->target->frame & FF_FRAMEMASK); +#if 0 + if (mobj->angle != mobj->target->angle + ANGLE_90) // reposition if not the correct angle + { + mobj_t* target = mobj->target; // shortcut + const fixed_t baseradius = target->radius - (target->scale/2); //FixedMul(FRACUNIT/2, target->scale); + P_UnsetThingPosition(mobj); + mobj->x = target->x - P_ReturnThrustX(target, target->angle, baseradius); + mobj->y = target->y - P_ReturnThrustY(target, target->angle, baseradius); + P_SetThingPosition(mobj); + mobj->angle = target->angle + ANGLE_90; + } +#endif + break; + case MT_FALLINGROCK: + // Despawn rocks here in case zmovement code can't do so (blame slopes) + if (!mobj->momx && !mobj->momy && !mobj->momz + && ((mobj->eflags & MFE_VERTICALFLIP) ? + mobj->z + mobj->height >= mobj->ceilingz + : mobj->z <= mobj->floorz)) + { + P_RemoveMobj(mobj); + return false; + } + P_MobjCheckWater(mobj); + break; + case MT_ARROW: + P_ArrowThink(mobj); + break; + case MT_EMERALDSPAWN: + if (mobj->threshold) + { + mobj->threshold--; + + if (!mobj->threshold && !mobj->target && mobj->reactiontime) + { + mobj_t *emerald = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->reactiontime); + emerald->threshold = 42; + P_SetTarget(&mobj->target, emerald); + P_SetTarget(&emerald->target, mobj); + } + } + break; + case MT_BUGGLE: + mobj->eflags |= MFE_UNDERWATER; //P_MobjCheckWater(mobj); // solely for MFE_UNDERWATER for A_FlickySpawn + { + if (mobj->tracer && mobj->tracer->player && mobj->tracer->health > 0 + && P_AproxDistance(P_AproxDistance(mobj->tracer->x - mobj->x, mobj->tracer->y - mobj->y), mobj->tracer->z - mobj->z) <= mobj->radius*16) + { + // Home in on the target. + P_HomingAttack(mobj, mobj->tracer); + + if (mobj->z < mobj->floorz) + mobj->z = mobj->floorz; + + if (leveltime % mobj->info->painchance == 0) + S_StartSound(mobj, mobj->info->activesound); + + if ((statenum_t)(mobj->state - states) != mobj->info->seestate) + P_SetMobjState(mobj, mobj->info->seestate); + } + else + { + // Try to find a player + P_LookForPlayers(mobj, true, true, mobj->radius*16); + mobj->momx >>= 1; + mobj->momy >>= 1; + mobj->momz >>= 1; + if ((statenum_t)(mobj->state - states) != mobj->info->spawnstate) + P_SetMobjState(mobj, mobj->info->spawnstate); + } + } + break; + case MT_BUMBLEBORE: + P_BumbleboreThink(mobj); + break; + case MT_BIGMINE: + mobj->extravalue1 += 3; + mobj->extravalue1 %= 360; + P_UnsetThingPosition(mobj); + mobj->z += FINESINE(mobj->extravalue1*(FINEMASK + 1)/360); + P_SetThingPosition(mobj); + break; + case MT_FLAME: + if (mobj->flags2 & MF2_BOSSNOTRAP) + { + if (!mobj->target || P_MobjWasRemoved(mobj->target)) + { + if (mobj->tracer && !P_MobjWasRemoved(mobj->tracer)) + P_RemoveMobj(mobj->tracer); + P_RemoveMobj(mobj); + return false; + } + mobj->z = mobj->target->z + mobj->target->momz; + if (!(mobj->eflags & MFE_VERTICALFLIP)) + mobj->z += mobj->target->height; + } + if (mobj->tracer && !P_MobjWasRemoved(mobj->tracer)) + { + mobj->tracer->z = mobj->z + P_MobjFlip(mobj)*20*mobj->scale; + if (mobj->eflags & MFE_VERTICALFLIP) + mobj->tracer->z += mobj->height; + } + break; + case MT_WAVINGFLAG1: + case MT_WAVINGFLAG2: + { + fixed_t base = (leveltime << (FRACBITS + 1)); + mobj_t *seg = mobj->tracer, *prev = mobj; + mobj->movedir = mobj->angle + + ((((FINESINE((FixedAngle(base << 1) >> ANGLETOFINESHIFT) & FINEMASK) + + FINESINE((FixedAngle(base << 4) >> ANGLETOFINESHIFT) & FINEMASK)) >> 1) + + FINESINE((FixedAngle(base*9) >> ANGLETOFINESHIFT) & FINEMASK) + + FINECOSINE(((FixedAngle(base*9)) >> ANGLETOFINESHIFT) & FINEMASK)) << 12); //*2^12 + while (seg) + { + seg->movedir = seg->angle; + seg->angle = prev->movedir; + P_UnsetThingPosition(seg); + seg->x = prev->x + P_ReturnThrustX(prev, prev->angle, prev->radius); + seg->y = prev->y + P_ReturnThrustY(prev, prev->angle, prev->radius); + seg->z = prev->z + prev->height - (seg->scale >> 1); + P_SetThingPosition(seg); + prev = seg; + seg = seg->tracer; + } + } + break; + case MT_SPINCUSHION: + if (mobj->target && mobj->state - states >= S_SPINCUSHION_AIM1 && mobj->state - states <= S_SPINCUSHION_AIM5) + mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); + break; + case MT_CRUSHCLAW: + if (mobj->state - states == S_CRUSHCLAW_STAY && mobj->target) + { + mobj_t *chain = mobj->target->target; + SINT8 sign = ((mobj->tics & 1) ? mobj->tics : -(SINT8)(mobj->tics)); + while (chain) + { + chain->z = chain->watertop + sign*mobj->scale; + sign = -sign; + chain = chain->target; + } + } + break; + case MT_SMASHINGSPIKEBALL: + mobj->momx = mobj->momy = 0; + if (mobj->state - states == S_SMASHSPIKE_FALL && P_IsObjectOnGround(mobj)) + { + P_SetMobjState(mobj, S_SMASHSPIKE_STOMP1); + S_StartSound(mobj, sfx_spsmsh); + } + else if (mobj->state - states == S_SMASHSPIKE_RISE2 && P_MobjFlip(mobj)*(mobj->z - mobj->movecount) >= 0) + { + mobj->momz = 0; + P_SetMobjState(mobj, S_SMASHSPIKE_FLOAT); + } + break; + case MT_HANGSTER: + if (!P_HangsterThink(mobj)) + return false; + break; + case MT_LHRT: + mobj->momx = FixedMul(mobj->momx, mobj->extravalue2); + mobj->momy = FixedMul(mobj->momy, mobj->extravalue2); + break; + case MT_EGGCAPSULE: + if (!mobj->reactiontime) + { + // Target nearest player on your mare. + // (You can make it float up/down by adding MF_FLOAT, + // but beware level design pitfalls.) + fixed_t shortest = 1024*FRACUNIT; + INT32 i; + P_SetTarget(&mobj->target, NULL); + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && players[i].mo + && players[i].mare == mobj->threshold && players[i].spheres > 0) + { + fixed_t dist = P_AproxDistance(players[i].mo->x - mobj->x, players[i].mo->y - mobj->y); + if (dist < shortest) + { + P_SetTarget(&mobj->target, players[i].mo); + shortest = dist; + } + } + } + break; + case MT_EGGMOBILE2_POGO: + if (!mobj->target + || !mobj->target->health + || mobj->target->state == &states[mobj->target->info->spawnstate] + || mobj->target->state == &states[mobj->target->info->raisestate]) + { + P_RemoveMobj(mobj); + return false; + } + P_TeleportMove(mobj, mobj->target->x, mobj->target->y, mobj->target->z - mobj->height); + break; + case MT_HAMMER: + if (mobj->z <= mobj->floorz) + { + P_RemoveMobj(mobj); + return false; + } + break; + case MT_KOOPA: + P_KoopaThinker(mobj); + break; + case MT_FIREBALL: + if (P_AproxDistance(mobj->momx, mobj->momy) <= 16*FRACUNIT) // Once fireballs lose enough speed, kill them + { + P_KillMobj(mobj, NULL, NULL, 0); + return false; + } + break; + case MT_REDRING: + if (((mobj->z < mobj->floorz) || (mobj->z + mobj->height > mobj->ceilingz)) + && mobj->flags & MF_MISSILE) + { + P_ExplodeMissile(mobj); + return false; + } + break; + case MT_BOSSFLYPOINT: + return false; + case MT_NIGHTSCORE: + mobj->color = (UINT8)(leveltime % SKINCOLOR_WHITE); + break; + case MT_JETFUME1: + if (!P_JetFume1Think(mobj)) + return false; + break; + case MT_JETFLAME: + { + if (!mobj->target // if you have no target + || (!(mobj->target->flags & MF_BOSS) && mobj->target->health <= 0)) // or your target isn't a boss and it's popped now + { // then remove yourself as well! + P_RemoveMobj(mobj); + return false; + } + + P_UnsetThingPosition(mobj); + mobj->x = mobj->target->x; + mobj->y = mobj->target->y; + mobj->z = mobj->target->z - 50*mobj->target->scale; + mobj->floorz = mobj->z; + mobj->ceilingz = mobj->z + mobj->height; + P_SetThingPosition(mobj); + } + break; + case MT_EGGROBO1: + if (!P_EggRobo1Think(mobj)) + return false; + break; + case MT_EGGROBO1JET: + { + if (!mobj->target || P_MobjWasRemoved(mobj->target) // if you have no target + || (mobj->target->health <= 0)) // or your target isn't a boss and it's popped now + { // then remove yourself as well! + P_RemoveMobj(mobj); + return false; + } + + mobj->flags2 ^= MF2_DONTDRAW; + + P_UnsetThingPosition(mobj); + mobj->x = mobj->target->x + P_ReturnThrustX(mobj, mobj->target->angle + ANGLE_90, mobj->movefactor*mobj->target->scale) - P_ReturnThrustX(mobj, mobj->target->angle, 19*mobj->target->scale); + mobj->y = mobj->target->y + P_ReturnThrustY(mobj, mobj->target->angle + ANGLE_90, mobj->movefactor*mobj->target->scale) - P_ReturnThrustY(mobj, mobj->target->angle, 19*mobj->target->scale); + mobj->z = mobj->target->z; + if (mobj->target->eflags & MFE_VERTICALFLIP) + mobj->z += (mobj->target->height - mobj->height); + mobj->floorz = mobj->z; + mobj->ceilingz = mobj->z + mobj->height; + P_SetThingPosition(mobj); + } + break; + case MT_NIGHTSDRONE: + P_NiGHTSDroneThink(mobj); + break; + case MT_PLAYER: + if (mobj->player) + P_PlayerMobjThinker(mobj); + return false; + case MT_SKIM: + // check mobj against possible water content, before movement code + P_MobjCheckWater(mobj); + + // Keep Skim at water surface + if (mobj->z <= mobj->watertop) + { + mobj->flags |= MF_NOGRAVITY; + if (mobj->z < mobj->watertop) + { + if (mobj->watertop - mobj->z <= FixedMul(mobj->info->speed*FRACUNIT, mobj->scale)) + mobj->z = mobj->watertop; + else + mobj->momz = FixedMul(mobj->info->speed*FRACUNIT, mobj->scale); + } + } + else + { + mobj->flags &= ~MF_NOGRAVITY; + if (mobj->z > mobj->watertop && mobj->z - mobj->watertop < FixedMul(MAXSTEPMOVE, mobj->scale)) + mobj->z = mobj->watertop; + } + break; + case MT_RING: + case MT_REDTEAMRING: + case MT_BLUETEAMRING: + P_KillRingsInLava(mobj); + if (P_MobjWasRemoved(mobj)) + return false; + /* FALLTHRU */ + case MT_COIN: + case MT_BLUESPHERE: + case MT_BOMBSPHERE: + case MT_NIGHTSCHIP: + case MT_NIGHTSSTAR: + // No need to check water. Who cares? + P_RingThinker(mobj); + if (mobj->flags2 & MF2_NIGHTSPULL) + P_NightsItemChase(mobj); + else + A_AttractChase(mobj); + return false; + // Flung items + case MT_FLINGRING: + P_KillRingsInLava(mobj); + if (P_MobjWasRemoved(mobj)) + return false; + /* FALLTHRU */ + case MT_FLINGCOIN: + case MT_FLINGBLUESPHERE: + case MT_FLINGNIGHTSCHIP: + if (mobj->flags2 & MF2_NIGHTSPULL) + P_NightsItemChase(mobj); + else + A_AttractChase(mobj); + break; + case MT_EMBLEM: + if (mobj->flags2 & MF2_NIGHTSPULL) + P_NightsItemChase(mobj); + break; + case MT_SHELL: + if (mobj->threshold && mobj->threshold != TICRATE) + mobj->threshold--; + + if (mobj->threshold >= TICRATE) + { + mobj->angle += ((mobj->movedir == 1) ? ANGLE_22h : ANGLE_337h); + P_InstaThrust(mobj, R_PointToAngle2(0, 0, mobj->momx, mobj->momy), (mobj->info->speed*mobj->scale)); + } + break; + case MT_TURRET: + if (!P_TurretThink(mobj)) + return false; + break; + case MT_BLUEFLAG: + case MT_REDFLAG: + { + sector_t* sec2; + sec2 = P_ThingOnSpecial3DFloor(mobj); + if ((sec2 && GETSECSPECIAL(sec2->special, 4) == 2) || (GETSECSPECIAL(mobj->subsector->sector->special, 4) == 2)) + mobj->fuse = 1; // Return to base. + break; + } + case MT_CANNONBALL: +#ifdef FLOORSPLATS + R_AddFloorSplat(mobj->tracer->subsector, mobj->tracer, "TARGET", mobj->tracer->x, + mobj->tracer->y, mobj->tracer->floorz, SPLATDRAWMODE_SHADE); +#endif + break; + case MT_SPINDUST: // Spindash dust + mobj->momx = FixedMul(mobj->momx, (3*FRACUNIT)/4); // originally 50000 + mobj->momy = FixedMul(mobj->momy, (3*FRACUNIT)/4); // same + //mobj->momz = mobj->momz+P_MobjFlip(mobj)/3; // no meaningful change in value to be frank + if (mobj->state >= &states[S_SPINDUST_BUBBLE1] && mobj->state <= &states[S_SPINDUST_BUBBLE4]) // bubble dust! + { + P_MobjCheckWater(mobj); + if (mobj->watertop != mobj->subsector->sector->floorheight - 1000*FRACUNIT + && mobj->z + mobj->height >= mobj->watertop - 5*FRACUNIT) + mobj->flags2 |= MF2_DONTDRAW; + } + break; + case MT_TRAINDUSTSPAWNER: + if (leveltime % 5 == 0) { + mobj_t* traindust = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_PARTICLE); + traindust->flags = MF_SCENERY; + P_SetMobjState(traindust, S_TRAINDUST); + traindust->frame = P_RandomRange(0, 8)|FF_TRANS90; + traindust->angle = mobj->angle; + traindust->tics = TICRATE*4; + traindust->destscale = FRACUNIT*64; + traindust->scalespeed = FRACUNIT/24; + P_SetScale(traindust, FRACUNIT*6); + } + break; + case MT_TRAINSTEAMSPAWNER: + if (leveltime % 5 == 0) { + mobj_t *steam = P_SpawnMobj(mobj->x + FRACUNIT*P_SignedRandom()/2, mobj->y + FRACUNIT*P_SignedRandom()/2, mobj->z, MT_PARTICLE); + P_SetMobjState(steam, S_TRAINSTEAM); + steam->frame = P_RandomRange(0, 1)|FF_TRANS90; + steam->tics = TICRATE*8; + steam->destscale = FRACUNIT*64; + steam->scalespeed = FRACUNIT/8; + P_SetScale(steam, FRACUNIT*16); + steam->momx = P_SignedRandom()*32; + steam->momy = -64*FRACUNIT; + steam->momz = 2*FRACUNIT; + } + break; + case MT_CANARIVORE_GAS: + { + fixed_t momz; + + if (mobj->flags2 & MF2_AMBUSH) + { + mobj->momx = FixedMul(mobj->momx, 50*FRACUNIT/51); + mobj->momy = FixedMul(mobj->momy, 50*FRACUNIT/51); + break; + } + + if (mobj->eflags & MFE_VERTICALFLIP) + { + if ((mobj->z + mobj->height + mobj->momz) <= mobj->ceilingz) + break; + } + else + { + if ((mobj->z + mobj->momz) >= mobj->floorz) + break; + } + + momz = abs(mobj->momz); + if (R_PointToDist2(0, 0, mobj->momx, mobj->momy) < momz) + P_InstaThrust(mobj, R_PointToAngle2(0, 0, mobj->momx, mobj->momy), momz); + mobj->flags2 |= MF2_AMBUSH; + break; + } + case MT_SALOONDOOR: + P_SaloonDoorThink(mobj); + break; + case MT_MINECARTSPAWNER: + P_HandleMinecartSegments(mobj); + if (!mobj->fuse || mobj->fuse > TICRATE) + break; + if (mobj->fuse == 2) + { + mobj->fuse = 0; + break; + } + mobj->flags2 ^= MF2_DONTDRAW; + break; + case MT_LAVAFALLROCK: + if (P_IsObjectOnGround(mobj)) + P_RemoveMobj(mobj); + break; + case MT_PYREFLY: + P_PyreFlyThink(mobj); + break; + case MT_PTERABYTE: + P_PterabyteThink(mobj); + break; + case MT_DRAGONBOMBER: + P_DragonbomberThink(mobj); + break; + case MT_MINUS: +#ifdef ROTSPRITE + { + if (P_IsObjectOnGround(mobj)) + mobj->rollangle = 0; + else + mobj->rollangle = R_PointToAngle2(0, 0, mobj->momz, (mobj->scale << 1) - min(abs(mobj->momz), mobj->scale << 1)); + } +#endif + break; + case MT_SPINFIRE: + if (mobj->flags & MF_NOGRAVITY) + { + if (mobj->eflags & MFE_VERTICALFLIP) + mobj->z = mobj->ceilingz - mobj->height; + else + mobj->z = mobj->floorz; + } + else if ((!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z <= mobj->floorz) + || ((mobj->eflags & MFE_VERTICALFLIP) && mobj->z + mobj->height >= mobj->ceilingz)) + { + mobj->flags |= MF_NOGRAVITY; + mobj->momx = 8; // this is a hack which is used to ensure it still behaves as a missile and can damage others + mobj->momy = mobj->momz = 0; + mobj->z = ((mobj->eflags & MFE_VERTICALFLIP) ? mobj->ceilingz - mobj->height : mobj->floorz); + } + /* FALLTHRU */ + default: + // check mobj against possible water content, before movement code + P_MobjCheckWater(mobj); + + // Extinguish fire objects in water + if (mobj->flags & MF_FIRE && mobj->type != MT_PUMA && mobj->type != MT_FIREBALL + && (mobj->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER))) + { + P_KillMobj(mobj, NULL, NULL, 0); + return false; + } + break; + } + return true; +} + // // P_MobjThinker // @@ -8101,1722 +9886,23 @@ void P_MobjThinker(mobj_t *mobj) // separate thinker if (mobj->flags & MF_PUSHABLE || (mobj->info->flags & MF_PUSHABLE && mobj->fuse)) { - P_MobjCheckWater(mobj); - P_PushableThinker(mobj); - - // Extinguish fire objects in water. (Yes, it's extraordinarily rare to have a pushable flame object, but Brak uses such a case.) - if (mobj->flags & MF_FIRE && mobj->type != MT_PUMA && mobj->type != MT_FIREBALL - && (mobj->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER))) - { - P_KillMobj(mobj, NULL, NULL, 0); + if (!P_MobjPushableThink(mobj)) return; - } } else if (mobj->flags & MF_BOSS) { -#ifdef HAVE_BLUA - if (LUAh_BossThinker(mobj)) - { - if (P_MobjWasRemoved(mobj)) - return; - } - else if (P_MobjWasRemoved(mobj)) + if (!P_MobjBossThink(mobj)) return; - else -#endif - switch (mobj->type) - { - case MT_EGGMOBILE: - if (mobj->health < mobj->info->damage+1 && leveltime & 2) - { - fixed_t rad = mobj->radius>>FRACBITS; - fixed_t hei = mobj->height>>FRACBITS; - mobj_t *particle = P_SpawnMobjFromMobj(mobj, - P_RandomRange(rad, -rad)<momz += mobj->momz; - } - if (mobj->flags2 & MF2_SKULLFLY) -#if 1 - P_SpawnGhostMobj(mobj); -#else // all the way back from final demo... MT_THOK isn't even the same size anymore! - { - mobj_t *spawnmobj; - spawnmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->info->painchance); - P_SetTarget(&spawnmobj->target, mobj); - spawnmobj->color = SKINCOLOR_GREY; - } -#endif - P_Boss1Thinker(mobj); - break; - case MT_EGGMOBILE2: - if (mobj->health < mobj->info->damage+1 && leveltime & 2) - { - fixed_t rad = mobj->radius>>FRACBITS; - fixed_t hei = mobj->height>>FRACBITS; - mobj_t *particle = P_SpawnMobjFromMobj(mobj, - P_RandomRange(rad, -rad)<momz += mobj->momz; - } - P_Boss2Thinker(mobj); - break; - case MT_EGGMOBILE3: - if (mobj->health < mobj->info->damage+1 && leveltime & 2) - { - fixed_t rad = mobj->radius>>FRACBITS; - fixed_t hei = mobj->height>>FRACBITS; - mobj_t *particle = P_SpawnMobjFromMobj(mobj, - P_RandomRange(rad, -rad)<momz += mobj->momz; - } - P_Boss3Thinker(mobj); - break; - case MT_EGGMOBILE4: - if (mobj->health < mobj->info->damage+1 && leveltime & 2) - { - fixed_t rad = mobj->radius>>FRACBITS; - fixed_t hei = mobj->height>>FRACBITS; - mobj_t *particle = P_SpawnMobjFromMobj(mobj, - P_RandomRange(rad, -rad)<momz += mobj->momz; - } - P_Boss4Thinker(mobj); - break; - case MT_FANG: - P_Boss5Thinker(mobj); - break; - case MT_BLACKEGGMAN: - P_Boss7Thinker(mobj); - break; - case MT_METALSONIC_BATTLE: - P_Boss9Thinker(mobj); - break; - default: // Generic SOC-made boss - if (mobj->flags2 & MF2_SKULLFLY) - P_SpawnGhostMobj(mobj); - P_GenericBossThinker(mobj); - break; - } - if (mobj->flags2 & MF2_BOSSFLEE) - { - if (mobj->extravalue1) - { - if (!(--mobj->extravalue1)) - { - if (mobj->target) - { - mobj->momz = FixedMul(FixedDiv(mobj->target->z - mobj->z, P_AproxDistance(mobj->x-mobj->target->x,mobj->y-mobj->target->y)), mobj->scale<<1); - mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); - } - else - mobj->momz = 8*mobj->scale; - } - else - mobj->angle += mobj->movedir; - } - else if (mobj->target) - P_InstaThrust(mobj, mobj->angle, FixedMul(12*FRACUNIT, mobj->scale)); - } - if (mobj->type == MT_CYBRAKDEMON && !mobj->health) - { - if (!(mobj->tics & 1)) - { - var1 = 2; - var2 = 0; - A_BossScream(mobj); - } - if (P_CheckDeathPitCollide(mobj)) - { - P_RemoveMobj(mobj); - return; - } - if (mobj->momz && mobj->z+mobj->momz <= mobj->floorz) - { - S_StartSound(mobj, sfx_befall); - if (mobj->state != states+S_CYBRAKDEMON_DIE8) - P_SetMobjState(mobj, S_CYBRAKDEMON_DIE8); - } - } } else if (mobj->health <= 0) // Dead things think differently than the living. - switch (mobj->type) - { - case MT_BLUESPHERE: - if ((mobj->tics>>2)+1 > 0 && (mobj->tics>>2)+1 <= tr_trans60) // tr_trans50 through tr_trans90, shifting once every second frame - mobj->frame = (NUMTRANSMAPS-((mobj->tics>>2)+1))<frame = tr_trans60<z <= mobj->floorz) - { - P_RemoveMobj(mobj); - return; - } - break; - case MT_FAKEMOBILE: - if (mobj->scale == mobj->destscale) - { - if (!mobj->fuse) - { - S_StartSound(mobj, sfx_s3k77); - mobj->flags2 |= MF2_DONTDRAW; - mobj->fuse = TICRATE; - } - return; - } - if (!mobj->reactiontime) - { - if (P_RandomChance(FRACUNIT/2)) - mobj->movefactor = FRACUNIT; - else - mobj->movefactor = -FRACUNIT; - if (P_RandomChance(FRACUNIT/2)) - mobj->movedir = ANG20; - else - mobj->movedir = -ANG20; - mobj->reactiontime = 5; - } - mobj->momz += mobj->movefactor; - mobj->angle += mobj->movedir; - P_InstaThrust(mobj, mobj->angle, -mobj->info->speed); - mobj->reactiontime--; - break; - case MT_EGGSHIELD: - mobj->flags2 ^= MF2_DONTDRAW; - break; - case MT_EGGTRAP: // Egg Capsule animal release - if (mobj->fuse > 0)// && mobj->fuse < TICRATE-(TICRATE/7)) - { - INT32 i; - fixed_t x,y,z; - fixed_t ns; - mobj_t *mo2; - mobj_t *flicky; - - z = mobj->subsector->sector->floorheight + FRACUNIT + (P_RandomKey(64)<x + FixedMul(FINESINE(fa),ns); - y = mobj->y + FixedMul(FINECOSINE(fa),ns); - - mo2 = P_SpawnMobj(x, y, z, MT_EXPLODE); - P_SetMobjStateNF(mo2, S_XPLD_EGGTRAP); // so the flickies don't lose their target if they spawn - ns = 4 * FRACUNIT; - mo2->momx = FixedMul(FINESINE(fa),ns); - mo2->momy = FixedMul(FINECOSINE(fa),ns); - mo2->angle = fa << ANGLETOFINESHIFT; - - if (!i && !(mobj->fuse & 2)) - S_StartSound(mo2, mobj->info->deathsound); - - flicky = P_InternalFlickySpawn(mo2, 0, 8*FRACUNIT, false, -1); - if (!flicky) - break; - - P_SetTarget(&flicky->target, mo2); - flicky->momx = mo2->momx; - flicky->momy = mo2->momy; - } - - mobj->fuse--; - } - break; - case MT_PLAYER: - /// \todo Have the player's dead body completely finish its animation even if they've already respawned. - if (!mobj->fuse) - { // Go away. - /// \todo Actually go ahead and remove mobj completely, and fix any bugs and crashes doing this creates. Chasecam should stop moving, and F12 should never return to it. - mobj->momz = 0; - if (mobj->player) - mobj->flags2 |= MF2_DONTDRAW; - else // safe to remove, nobody's going to complain! - { - P_RemoveMobj(mobj); - return; - } - } - else // Apply gravity to fall downwards. - { - if (mobj->player && !(mobj->fuse % 8) && (mobj->player->charflags & SF_MACHINE)) - { - fixed_t r = mobj->radius >> FRACBITS; - mobj_t *explosion = P_SpawnMobj( - mobj->x + (P_RandomRange(r, -r) << FRACBITS), - mobj->y + (P_RandomRange(r, -r) << FRACBITS), - mobj->z + (P_RandomKey(mobj->height >> FRACBITS) << FRACBITS), - MT_SONIC3KBOSSEXPLODE); - S_StartSound(explosion, sfx_s3kb4); - } - if (mobj->movedir == DMG_DROWNED) - P_SetObjectMomZ(mobj, -FRACUNIT / 2, true); // slower fall from drowning - else - P_SetObjectMomZ(mobj, -2 * FRACUNIT / 3, true); - } - break; - case MT_METALSONIC_RACE: - { - if (!(mobj->fuse % 8)) - { - fixed_t r = mobj->radius >> FRACBITS; - mobj_t *explosion = P_SpawnMobj( - mobj->x + (P_RandomRange(r, -r) << FRACBITS), - mobj->y + (P_RandomRange(r, -r) << FRACBITS), - mobj->z + (P_RandomKey(mobj->height >> FRACBITS) << FRACBITS), - MT_SONIC3KBOSSEXPLODE); - S_StartSound(explosion, sfx_s3kb4); - } - P_SetObjectMomZ(mobj, -2 * FRACUNIT / 3, true); - } - default: - break; - } + { + if (!P_MobjDeadThink(mobj)) + return; + } else { - if ((mobj->flags & MF_ENEMY) && (mobj->state->nextstate == mobj->info->spawnstate && mobj->tics == 1)) - mobj->flags2 &= ~MF2_FRET; - - // Angle-to-tracer to trigger a linedef exec - // See Linedef Exec 457 (Track mobj angle to point) - if ((mobj->eflags & MFE_TRACERANGLE) && mobj->tracer && mobj->extravalue2) - { - // mobj->lastlook - Don't disable behavior after first failure - // mobj->extravalue1 - Angle tolerance - // mobj->extravalue2 - Exec tag upon failure - // mobj->cvval - Allowable failure delay - // mobj->cvmem - Failure timer - - angle_t ang = mobj->angle - R_PointToAngle2(mobj->x, mobj->y, mobj->tracer->x, mobj->tracer->y); - - // \todo account for distance between mobj and tracer - // Because closer mobjs can be facing beyond the angle tolerance - // yet tracer is still in the camera view - - // failure state: mobj is not facing tracer - // Reasaonable defaults: ANGLE_67h, ANGLE_292h - if (ang >= (angle_t)mobj->extravalue1 && ang <= ANGLE_MAX - (angle_t)mobj->extravalue1) - { - if (mobj->cvmem) - mobj->cvmem--; - else - { - INT32 exectag = mobj->extravalue2; // remember this before we erase the values - - if (mobj->lastlook) - mobj->cvmem = mobj->cusval; // reset timer for next failure - else - { - // disable after first failure - mobj->eflags &= ~MFE_TRACERANGLE; - mobj->lastlook = mobj->extravalue1 = mobj->extravalue2 = mobj->cvmem = mobj->cusval = 0; - } - - P_LinedefExecute(exectag, mobj, NULL); - } - } - else - mobj->cvmem = mobj->cusval; // reset failure timer - } - - switch (mobj->type) - { - case MT_WALLSPIKEBASE: - if (!mobj->target) { - P_RemoveMobj(mobj); - return; - } - mobj->frame = (mobj->frame & ~FF_FRAMEMASK)|(mobj->target->frame & FF_FRAMEMASK); -#if 0 - if (mobj->angle != mobj->target->angle + ANGLE_90) // reposition if not the correct angle - { - mobj_t *target = mobj->target; // shortcut - const fixed_t baseradius = target->radius - (target->scale/2); //FixedMul(FRACUNIT/2, target->scale); - P_UnsetThingPosition(mobj); - mobj->x = target->x - P_ReturnThrustX(target, target->angle, baseradius); - mobj->y = target->y - P_ReturnThrustY(target, target->angle, baseradius); - P_SetThingPosition(mobj); - mobj->angle = target->angle + ANGLE_90; - } -#endif - break; - case MT_FALLINGROCK: - // Despawn rocks here in case zmovement code can't do so (blame slopes) - if (!mobj->momx && !mobj->momy && !mobj->momz - && ((mobj->eflags & MFE_VERTICALFLIP) ? - mobj->z + mobj->height >= mobj->ceilingz - : mobj->z <= mobj->floorz)) - { - P_RemoveMobj(mobj); - return; - } - P_MobjCheckWater(mobj); - break; - case MT_ARROW: - if (mobj->flags & MF_MISSILE) - { - // Calculate the angle of movement. - /* - momz - / | - / | - / | - 0------dist(momx,momy) - */ - - fixed_t dist = P_AproxDistance(mobj->momx, mobj->momy); - angle_t angle = R_PointToAngle2(0, 0, dist, mobj->momz); - - if (angle > ANG20 && angle <= ANGLE_180) - mobj->frame = 2; - else if (angle < ANG340 && angle > ANGLE_180) - mobj->frame = 0; - else - mobj->frame = 1; - - if (!(mobj->extravalue1) && (mobj->momz < 0)) - { - mobj->extravalue1 = 1; - S_StartSound(mobj, mobj->info->activesound); - } - if (leveltime & 1) - { - mobj_t *dust = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_PARTICLE); - dust->tics = 18; - dust->scalespeed = 4096; - dust->destscale = FRACUNIT/32; - } - } - else - mobj->flags2 ^= MF2_DONTDRAW; - break; - case MT_EMERALDSPAWN: - if (mobj->threshold) - { - mobj->threshold--; - - if (!mobj->threshold && !mobj->target && mobj->reactiontime) - { - mobj_t *emerald = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->reactiontime); - emerald->threshold = 42; - P_SetTarget(&mobj->target, emerald); - P_SetTarget(&emerald->target, mobj); - } - } - break; - case MT_BUGGLE: - mobj->eflags |= MFE_UNDERWATER; //P_MobjCheckWater(mobj); // solely for MFE_UNDERWATER for A_FlickySpawn - { - if (mobj->tracer && mobj->tracer->player && mobj->tracer->health > 0 - && P_AproxDistance(P_AproxDistance(mobj->tracer->x - mobj->x, mobj->tracer->y - mobj->y), mobj->tracer->z - mobj->z) <= mobj->radius * 16) - { - // Home in on the target. - P_HomingAttack(mobj, mobj->tracer); - - if (mobj->z < mobj->floorz) - mobj->z = mobj->floorz; - - if (leveltime % mobj->info->painchance == 0) - S_StartSound(mobj, mobj->info->activesound); - - if ((statenum_t)(mobj->state-states) != mobj->info->seestate) - P_SetMobjState(mobj, mobj->info->seestate); - } - else - { - // Try to find a player - P_LookForPlayers(mobj, true, true, mobj->radius * 16); - mobj->momx >>= 1; - mobj->momy >>= 1; - mobj->momz >>= 1; - if ((statenum_t)(mobj->state-states) != mobj->info->spawnstate) - P_SetMobjState(mobj, mobj->info->spawnstate); - } - } - break; - case MT_BUMBLEBORE: - { - statenum_t st = mobj->state-states; - if (st == S_BUMBLEBORE_FLY1 || st == S_BUMBLEBORE_FLY2) - { - if (!mobj->target) - P_SetMobjState(mobj, mobj->info->spawnstate); - else if (P_MobjFlip(mobj)*((mobj->z + (mobj->height>>1)) - (mobj->target->z + (mobj->target->height>>1))) > 0 - && R_PointToDist2(mobj->x, mobj->y, mobj->target->x, mobj->target->y) <= 32*FRACUNIT) - { - mobj->momx >>= 1; - mobj->momy >>= 1; - if (++mobj->movefactor == 4) - { - S_StartSound(mobj, mobj->info->seesound); - mobj->momx = mobj->momy = mobj->momz = 0; - mobj->flags = (mobj->flags|MF_PAIN) & ~MF_NOGRAVITY; - P_SetMobjState(mobj, mobj->info->meleestate); - } - } - else - mobj->movefactor = 0; - } - else if (st == S_BUMBLEBORE_RAISE || st == S_BUMBLEBORE_FALL2) // no _FALL1 because it's an 0-tic - { - if (P_IsObjectOnGround(mobj)) - { - S_StopSound(mobj); - S_StartSound(mobj, mobj->info->attacksound); - mobj->flags = (mobj->flags|MF_NOGRAVITY) & ~MF_PAIN; - mobj->momx = mobj->momy = mobj->momz = 0; - P_SetMobjState(mobj, mobj->info->painstate); - } - else - { - mobj->angle += ANGLE_22h; - mobj->frame = mobj->state->frame + ((mobj->tics & 2)>>1); - } - } - else if (st == S_BUMBLEBORE_STUCK2 && mobj->tics < TICRATE) - mobj->frame = mobj->state->frame + ((mobj->tics & 2)>>1); - } - break; - case MT_BIGMINE: - mobj->extravalue1 += 3; - mobj->extravalue1 %= 360; - P_UnsetThingPosition(mobj); - mobj->z += FINESINE(mobj->extravalue1*(FINEMASK+1)/360); - P_SetThingPosition(mobj); - break; - case MT_FLAME: - if (mobj->flags2 & MF2_BOSSNOTRAP) - { - if (!mobj->target || P_MobjWasRemoved(mobj->target)) - { - if (mobj->tracer && !P_MobjWasRemoved(mobj->tracer)) - P_RemoveMobj(mobj->tracer); - P_RemoveMobj(mobj); - return; - } - mobj->z = mobj->target->z + mobj->target->momz; - if (!(mobj->eflags & MFE_VERTICALFLIP)) - mobj->z += mobj->target->height; - } - if (mobj->tracer && !P_MobjWasRemoved(mobj->tracer)) - { - mobj->tracer->z = mobj->z + P_MobjFlip(mobj)*20*mobj->scale; - if (mobj->eflags & MFE_VERTICALFLIP) - mobj->tracer->z += mobj->height; - } - break; - case MT_WAVINGFLAG1: - case MT_WAVINGFLAG2: - { - fixed_t base = (leveltime<<(FRACBITS+1)); - mobj_t *seg = mobj->tracer, *prev = mobj; - mobj->movedir = mobj->angle - + ((((FINESINE((FixedAngle(base<<1)>>ANGLETOFINESHIFT) & FINEMASK) - + FINESINE((FixedAngle(base<<4)>>ANGLETOFINESHIFT) & FINEMASK))>>1) - + FINESINE((FixedAngle(base*9)>>ANGLETOFINESHIFT) & FINEMASK) - + FINECOSINE(((FixedAngle(base*9))>>ANGLETOFINESHIFT) & FINEMASK))<<12); //*2^12 - while (seg) - { - seg->movedir = seg->angle; - seg->angle = prev->movedir; - P_UnsetThingPosition(seg); - seg->x = prev->x + P_ReturnThrustX(prev, prev->angle, prev->radius); - seg->y = prev->y + P_ReturnThrustY(prev, prev->angle, prev->radius); - seg->z = prev->z + prev->height - (seg->scale>>1); - P_SetThingPosition(seg); - prev = seg; - seg = seg->tracer; - } - } - break; - case MT_SPINCUSHION: - if (mobj->target && mobj->state-states >= S_SPINCUSHION_AIM1 && mobj->state-states <= S_SPINCUSHION_AIM5) - mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); - break; - case MT_CRUSHCLAW: - if (mobj->state-states == S_CRUSHCLAW_STAY && mobj->target) - { - mobj_t *chain = mobj->target->target; - SINT8 sign = ((mobj->tics & 1) ? mobj->tics : -(SINT8)(mobj->tics)); - while (chain) - { - chain->z = chain->watertop + sign*mobj->scale; - sign = -sign; - chain = chain->target; - } - } - break; - case MT_SMASHINGSPIKEBALL: - mobj->momx = mobj->momy = 0; - if (mobj->state-states == S_SMASHSPIKE_FALL && P_IsObjectOnGround(mobj)) - { - P_SetMobjState(mobj, S_SMASHSPIKE_STOMP1); - S_StartSound(mobj, sfx_spsmsh); - } - else if (mobj->state-states == S_SMASHSPIKE_RISE2 && P_MobjFlip(mobj)*(mobj->z - mobj->movecount) >= 0) - { - mobj->momz = 0; - P_SetMobjState(mobj, S_SMASHSPIKE_FLOAT); - } - break; - case MT_HANGSTER: - { - statenum_t st = mobj->state-states; - //ghost image trail when flying down - if (st == S_HANGSTER_SWOOP1 || st == S_HANGSTER_SWOOP2) - { - P_SpawnGhostMobj(mobj); - //curve when in line with target, otherwise curve to avoid crashing into floor - if ((mobj->z - mobj->floorz <= 80*FRACUNIT) || (mobj->target && (mobj->z - mobj->target->z <= 80*FRACUNIT))) - P_SetMobjState(mobj, (st = S_HANGSTER_ARC1)); - } - - //swoop arc movement stuff - if (st == S_HANGSTER_ARC1) - { - A_FaceTarget(mobj); - P_Thrust(mobj, mobj->angle, 1*FRACUNIT); - } - else if (st == S_HANGSTER_ARC2) - P_Thrust(mobj, mobj->angle, 2*FRACUNIT); - else if (st == S_HANGSTER_ARC3) - P_Thrust(mobj, mobj->angle, 4*FRACUNIT); - //if movement has stopped while flying (like hitting a wall), fly up immediately - else if (st == S_HANGSTER_FLY1 && !mobj->momx && !mobj->momy) - { - mobj->extravalue1 = 0; - P_SetMobjState(mobj, S_HANGSTER_ARCUP1); - } - //after swooping back up, check for ceiling - else if ((st == S_HANGSTER_RETURN1 || st == S_HANGSTER_RETURN2) && mobj->momz == 0 && mobj->ceilingz == (mobj->z + mobj->height)) - P_SetMobjState(mobj, (st = S_HANGSTER_RETURN3)); - - //should you roost on a ceiling with F_SKY1 as its flat, disappear forever - if (st == S_HANGSTER_RETURN3 && mobj->momz == 0 && mobj->ceilingz == (mobj->z + mobj->height) - && mobj->subsector->sector->ceilingpic == skyflatnum - && mobj->subsector->sector->ceilingheight == mobj->ceilingz) - { - P_RemoveMobj(mobj); - return; - } - } - break; - case MT_LHRT: - mobj->momx = FixedMul(mobj->momx, mobj->extravalue2); - mobj->momy = FixedMul(mobj->momy, mobj->extravalue2); - break; - case MT_EGGCAPSULE: - if (!mobj->reactiontime) - { - // Target nearest player on your mare. - // (You can make it float up/down by adding MF_FLOAT, - // but beware level design pitfalls.) - fixed_t shortest = 1024*FRACUNIT; - INT32 i; - P_SetTarget(&mobj->target, NULL); - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].mo - && players[i].mare == mobj->threshold && players[i].spheres > 0) - { - fixed_t dist = P_AproxDistance(players[i].mo->x - mobj->x, players[i].mo->y - mobj->y); - if (dist < shortest) - { - P_SetTarget(&mobj->target, players[i].mo); - shortest = dist; - } - } - } - break; - case MT_EGGMOBILE2_POGO: - if (!mobj->target - || !mobj->target->health - || mobj->target->state == &states[mobj->target->info->spawnstate] - || mobj->target->state == &states[mobj->target->info->raisestate]) - { - P_RemoveMobj(mobj); - return; - } - P_TeleportMove(mobj, mobj->target->x, mobj->target->y, mobj->target->z - mobj->height); - break; - case MT_HAMMER: - if (mobj->z <= mobj->floorz) - { - P_RemoveMobj(mobj); - return; - } - break; - case MT_KOOPA: - P_KoopaThinker(mobj); - break; - case MT_FIREBALL: - if (P_AproxDistance(mobj->momx, mobj->momy) <= 16*FRACUNIT) // Once fireballs lose enough speed, kill them - { - P_KillMobj(mobj, NULL, NULL, 0); - return; - } - break; - case MT_REDRING: - if (((mobj->z < mobj->floorz) || (mobj->z + mobj->height > mobj->ceilingz)) - && mobj->flags & MF_MISSILE) - { - P_ExplodeMissile(mobj); - return; - } - break; - case MT_BOSSFLYPOINT: - return; - case MT_NIGHTSCORE: - mobj->color = (UINT8)(leveltime % SKINCOLOR_WHITE); - break; - case MT_JETFUME1: - { - fixed_t jetx, jety; - - if (!mobj->target // if you have no target - || (!(mobj->target->flags & MF_BOSS) && mobj->target->health <= 0)) // or your target isn't a boss and it's popped now - { // then remove yourself as well! - P_RemoveMobj(mobj); - return; - } - - jetx = mobj->target->x + P_ReturnThrustX(mobj->target, mobj->target->angle, FixedMul(-64*FRACUNIT, mobj->target->scale)); - jety = mobj->target->y + P_ReturnThrustY(mobj->target, mobj->target->angle, FixedMul(-64*FRACUNIT, mobj->target->scale)); - - if (mobj->fuse == 56) // First one - { - P_UnsetThingPosition(mobj); - mobj->x = jetx; - mobj->y = jety; - if (mobj->target->eflags & MFE_VERTICALFLIP) - mobj->z = mobj->target->z + mobj->target->height - mobj->height - FixedMul(38*FRACUNIT, mobj->target->scale); - else - mobj->z = mobj->target->z + FixedMul(38*FRACUNIT, mobj->target->scale); - mobj->floorz = mobj->z; - mobj->ceilingz = mobj->z+mobj->height; - P_SetThingPosition(mobj); - } - else if (mobj->fuse == 57) - { - P_UnsetThingPosition(mobj); - mobj->x = jetx + P_ReturnThrustX(mobj->target, mobj->target->angle-ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); - mobj->y = jety + P_ReturnThrustY(mobj->target, mobj->target->angle-ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); - if (mobj->target->eflags & MFE_VERTICALFLIP) - mobj->z = mobj->target->z + mobj->target->height - mobj->height - FixedMul(12*FRACUNIT, mobj->target->scale); - else - mobj->z = mobj->target->z + FixedMul(12*FRACUNIT, mobj->target->scale); - mobj->floorz = mobj->z; - mobj->ceilingz = mobj->z+mobj->height; - P_SetThingPosition(mobj); - } - else if (mobj->fuse == 58) - { - P_UnsetThingPosition(mobj); - mobj->x = jetx + P_ReturnThrustX(mobj->target, mobj->target->angle+ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); - mobj->y = jety + P_ReturnThrustY(mobj->target, mobj->target->angle+ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); - if (mobj->target->eflags & MFE_VERTICALFLIP) - mobj->z = mobj->target->z + mobj->target->height - mobj->height - FixedMul(12*FRACUNIT, mobj->target->scale); - else - mobj->z = mobj->target->z + FixedMul(12*FRACUNIT, mobj->target->scale); - mobj->floorz = mobj->z; - mobj->ceilingz = mobj->z+mobj->height; - P_SetThingPosition(mobj); - } - else if (mobj->fuse == 59) - { - boolean dashmod = ((mobj->target->flags & MF_PAIN) && (mobj->target->health <= mobj->target->info->damage)); - jetx = mobj->target->x + P_ReturnThrustX(mobj->target, mobj->target->angle, -mobj->target->radius); - jety = mobj->target->y + P_ReturnThrustY(mobj->target, mobj->target->angle, -mobj->target->radius); - P_UnsetThingPosition(mobj); - mobj->x = jetx; - mobj->y = jety; - mobj->destscale = mobj->target->scale; - if (!(dashmod && mobj->target->state == states+S_METALSONIC_BOUNCE)) - { - mobj->destscale = (mobj->destscale + FixedDiv(R_PointToDist2(0, 0, mobj->target->momx, mobj->target->momy), 36*mobj->target->scale))/3; - } - if (mobj->target->eflags & MFE_VERTICALFLIP) - mobj->z = mobj->target->z + mobj->target->height/2 + mobj->height/2; - else - mobj->z = mobj->target->z + mobj->target->height/2 - mobj->height/2; - mobj->floorz = mobj->z; - mobj->ceilingz = mobj->z+mobj->height; - P_SetThingPosition(mobj); - if (dashmod) - { - mobj->color = SKINCOLOR_SUNSET; - if (mobj->target->movecount == 3 && !mobj->target->reactiontime && (mobj->target->movedir == 0 || mobj->target->movedir == 2)) - P_SpawnGhostMobj(mobj); - } - else - mobj->color = SKINCOLOR_ICY; - } - mobj->fuse++; - } - break; - case MT_JETFLAME: - { - if (!mobj->target // if you have no target - || (!(mobj->target->flags & MF_BOSS) && mobj->target->health <= 0)) // or your target isn't a boss and it's popped now - { // then remove yourself as well! - P_RemoveMobj(mobj); - return; - } - - P_UnsetThingPosition(mobj); - mobj->x = mobj->target->x; - mobj->y = mobj->target->y; - mobj->z = mobj->target->z - 50*mobj->target->scale; - mobj->floorz = mobj->z; - mobj->ceilingz = mobj->z+mobj->height; - P_SetThingPosition(mobj); - } - break; - case MT_EGGROBO1: -#define SPECTATORRADIUS (96*mobj->scale) - { - if (!(mobj->flags2 & MF2_STRONGBOX)) - { - mobj->cusval = mobj->x; // eat my SOCs, p_mobj.h warning, we have lua now - mobj->cvmem = mobj->y; // ditto - mobj->movedir = mobj->angle; - mobj->threshold = P_MobjFlip(mobj)*10*mobj->scale; - if (mobj->threshold < 0) - mobj->threshold += (mobj->ceilingz - mobj->height); - else - mobj->threshold += mobj->floorz; - var1 = 4; - A_BossJetFume(mobj); - mobj->flags2 |= MF2_STRONGBOX; - } - - if (mobj->state == &states[mobj->info->deathstate]) // todo: make map actually set health to 0 for these - { - if (mobj->movecount) - { - if (!(--mobj->movecount)) - S_StartSound(mobj, mobj->info->deathsound); - } - else - { - mobj->momz += P_MobjFlip(mobj)*mobj->scale; - if (mobj->momz > 0) - { - if (mobj->z + mobj->momz > mobj->ceilingz + (1000<z + mobj->height + mobj->momz < mobj->floorz - (1000<cusval, basey = mobj->cvmem; - - if (mobj->spawnpoint && mobj->spawnpoint->options & (MTF_AMBUSH|MTF_OBJECTSPECIAL)) - { - angle_t sideang = mobj->movedir + ((mobj->spawnpoint->options & MTF_AMBUSH) ? ANGLE_90 : -ANGLE_90); - fixed_t oscillate = FixedMul(FINESINE(((leveltime*ANG1)>>(ANGLETOFINESHIFT+2)) & FINEMASK), 250*mobj->scale); - basex += P_ReturnThrustX(mobj, sideang, oscillate); - basey += P_ReturnThrustY(mobj, sideang, oscillate); - } - - mobj->z = mobj->threshold + FixedMul(FINESINE(((leveltime + mobj->movecount)*ANG2>>(ANGLETOFINESHIFT-2)) & FINEMASK), 8*mobj->scale); - if (mobj->state != &states[mobj->info->meleestate]) - { - boolean didmove = false; - - if (mobj->state == &states[mobj->info->spawnstate]) - { - UINT8 i; - fixed_t dist = INT32_MAX; - - for (i = 0; i < MAXPLAYERS; i++) - { - fixed_t compdist; - if (!playeringame[i]) - continue; - if (players[i].spectator) - continue; - if (!players[i].mo) - continue; - if (!players[i].mo->health) - continue; - if (P_PlayerInPain(&players[i])) - continue; - if (players[i].mo->z > mobj->z + mobj->height + 8*mobj->scale) - continue; - if (players[i].mo->z + players[i].mo->height < mobj->z - 8*mobj->scale) - continue; - compdist = P_AproxDistance( - players[i].mo->x + players[i].mo->momx - basex, - players[i].mo->y + players[i].mo->momy - basey); - if (compdist >= dist) - continue; - dist = compdist; - P_SetTarget(&mobj->target, players[i].mo); - } - - if (dist < (SPECTATORRADIUS<<1)) - { - didmove = true; - mobj->frame = 3 + ((leveltime & 2)>>1); - mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); - - if (P_AproxDistance( - mobj->x - basex, - mobj->y - basey) - < mobj->scale) - S_StartSound(mobj, mobj->info->seesound); - - P_TeleportMove(mobj, - (15*(mobj->x>>4)) + (basex>>4) + P_ReturnThrustX(mobj, mobj->angle, SPECTATORRADIUS>>4), - (15*(mobj->y>>4)) + (basey>>4) + P_ReturnThrustY(mobj, mobj->angle, SPECTATORRADIUS>>4), - mobj->z); - } - else - { - angle_t diff = (mobj->movedir - mobj->angle); - if (diff > ANGLE_180) - diff = InvAngle(InvAngle(diff)/8); - else - diff /= 8; - mobj->angle += diff; - - dist = FINECOSINE(((leveltime + mobj->movecount)*ANG2>>(ANGLETOFINESHIFT-2)) & FINEMASK); - - if (abs(dist) < FRACUNIT/2) - mobj->frame = 0; - else - mobj->frame = (dist > 0) ? 1 : 2; - } - } - - if (!didmove) - { - if (P_AproxDistance(mobj->x - basex, mobj->y - basey) < mobj->scale) - P_TeleportMove(mobj, basex, basey, mobj->z); - else - P_TeleportMove(mobj, - (15*(mobj->x>>4)) + (basex>>4), - (15*(mobj->y>>4)) + (basey>>4), - mobj->z); - } - } - } - } - break; -#undef SPECTATORRADIUS - case MT_EGGROBO1JET: - { - if (!mobj->target || P_MobjWasRemoved(mobj->target) // if you have no target - || (mobj->target->health <= 0)) // or your target isn't a boss and it's popped now - { // then remove yourself as well! - P_RemoveMobj(mobj); - return; - } - - mobj->flags2 ^= MF2_DONTDRAW; - - P_UnsetThingPosition(mobj); - mobj->x = mobj->target->x + P_ReturnThrustX(mobj, mobj->target->angle+ANGLE_90, mobj->movefactor*mobj->target->scale) - P_ReturnThrustX(mobj, mobj->target->angle, 19*mobj->target->scale); - mobj->y = mobj->target->y + P_ReturnThrustY(mobj, mobj->target->angle+ANGLE_90, mobj->movefactor*mobj->target->scale) - P_ReturnThrustY(mobj, mobj->target->angle, 19*mobj->target->scale); - mobj->z = mobj->target->z; - if (mobj->target->eflags & MFE_VERTICALFLIP) - mobj->z += (mobj->target->height - mobj->height); - mobj->floorz = mobj->z; - mobj->ceilingz = mobj->z+mobj->height; - P_SetThingPosition(mobj); - } - break; - case MT_NIGHTSDRONE: - { - // variable setup - mobj_t *goalpost = NULL; - mobj_t *sparkle = NULL; - mobj_t *droneman = NULL; - - boolean flip = mobj->flags2 & MF2_OBJECTFLIP; - boolean topaligned = (mobj->flags & MF_SLIDEME) && !(mobj->flags & MF_GRENADEBOUNCE); - boolean middlealigned = (mobj->flags & MF_GRENADEBOUNCE) && !(mobj->flags & MF_SLIDEME); - boolean bottomoffsetted = !(mobj->flags & MF_SLIDEME) && !(mobj->flags & MF_GRENADEBOUNCE); - boolean flipchanged = false; - - fixed_t dronemanoffset, goaloffset, sparkleoffset, droneboxmandiff, dronemangoaldiff; - - if (mobj->target && mobj->target->type == MT_NIGHTSDRONE_GOAL) - { - goalpost = mobj->target; - if (goalpost->target && goalpost->target->type == MT_NIGHTSDRONE_SPARKLING) - sparkle = goalpost->target; - if (goalpost->tracer && goalpost->tracer->type == MT_NIGHTSDRONE_MAN) - droneman = goalpost->tracer; - } - - if (!goalpost || !sparkle || !droneman) - break; - - // did NIGHTSDRONE position, scale, flip, or flags change? all elements need to be synced - droneboxmandiff = max(mobj->height - droneman->height, 0); - dronemangoaldiff = max(droneman->height - goalpost->height, 0); - - if (!(goalpost->flags2 & MF2_OBJECTFLIP) && (mobj->flags2 & MF2_OBJECTFLIP)) - { - goalpost->eflags |= MFE_VERTICALFLIP; - goalpost->flags2 |= MF2_OBJECTFLIP; - sparkle->eflags |= MFE_VERTICALFLIP; - sparkle->flags2 |= MF2_OBJECTFLIP; - droneman->eflags |= MFE_VERTICALFLIP; - droneman->flags2 |= MF2_OBJECTFLIP; - flipchanged = true; - } - else if ((goalpost->flags2 & MF2_OBJECTFLIP) && !(mobj->flags2 & MF2_OBJECTFLIP)) - { - goalpost->eflags &= ~MFE_VERTICALFLIP; - goalpost->flags2 &= ~MF2_OBJECTFLIP; - sparkle->eflags &= ~MFE_VERTICALFLIP; - sparkle->flags2 &= ~MF2_OBJECTFLIP; - droneman->eflags &= ~MFE_VERTICALFLIP; - droneman->flags2 &= ~MF2_OBJECTFLIP; - flipchanged = true; - } - - if (goalpost->destscale != mobj->destscale - || goalpost->movefactor != mobj->z - || goalpost->friction != mobj->height - || flipchanged - || goalpost->threshold != (INT32)(mobj->flags & (MF_SLIDEME | MF_GRENADEBOUNCE))) - { - goalpost->destscale = sparkle->destscale = droneman->destscale = mobj->destscale; - - // straight copy-pasta from P_SpawnMapThing, case MT_NIGHTSDRONE - if (!flip) - { - if (topaligned) // Align droneman to top of hitbox - { - dronemanoffset = droneboxmandiff; - goaloffset = dronemangoaldiff / 2 + dronemanoffset; - } - else if (middlealigned) // Align droneman to center of hitbox - { - dronemanoffset = droneboxmandiff / 2; - goaloffset = dronemangoaldiff / 2 + dronemanoffset; - } - else if (bottomoffsetted) - { - dronemanoffset = 24*FRACUNIT; - goaloffset = dronemangoaldiff + dronemanoffset; - } - else - { - dronemanoffset = 0; - goaloffset = dronemangoaldiff / 2 + dronemanoffset; - } - - sparkleoffset = goaloffset - FixedMul(15*FRACUNIT, mobj->scale); - } - else - { - if (topaligned) // Align droneman to top of hitbox - { - dronemanoffset = 0; - goaloffset = dronemangoaldiff / 2 + dronemanoffset; - } - else if (middlealigned) // Align droneman to center of hitbox - { - dronemanoffset = droneboxmandiff / 2; - goaloffset = dronemangoaldiff / 2 + dronemanoffset; - } - else if (bottomoffsetted) - { - dronemanoffset = droneboxmandiff - FixedMul(24*FRACUNIT, mobj->scale); - goaloffset = dronemangoaldiff + dronemanoffset; - } - else - { - dronemanoffset = droneboxmandiff; - goaloffset = dronemangoaldiff / 2 + dronemanoffset; - } - - sparkleoffset = goaloffset + FixedMul(15*FRACUNIT, mobj->scale); - } - - P_TeleportMove(goalpost, mobj->x, mobj->y, mobj->z + goaloffset); - P_TeleportMove(sparkle, mobj->x, mobj->y, mobj->z + sparkleoffset); - if (goalpost->movefactor != mobj->z || goalpost->friction != mobj->height) - { - P_TeleportMove(droneman, mobj->x, mobj->y, mobj->z + dronemanoffset); - goalpost->movefactor = mobj->z; - goalpost->friction = mobj->height; - } - goalpost->threshold = mobj->flags & (MF_SLIDEME | MF_GRENADEBOUNCE); - } - else - { - if (goalpost->x != mobj->x || goalpost->y != mobj->y) - { - P_TeleportMove(goalpost, mobj->x, mobj->y, goalpost->z); - P_TeleportMove(sparkle, mobj->x, mobj->y, sparkle->z); - } - - if (droneman->x != mobj->x || droneman->y != mobj->y) - P_TeleportMove(droneman, mobj->x, mobj->y, - droneman->z >= mobj->floorz && droneman->z <= mobj->ceilingz ? droneman->z : mobj->z); - } - - // now toggle states! - // GOAL mode? - if (sparkle->state >= &states[S_NIGHTSDRONE_SPARKLING1] && sparkle->state <= &states[S_NIGHTSDRONE_SPARKLING16]) - { - INT32 i; - boolean bonustime = false; - - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].bonustime && players[i].powers[pw_carry] == CR_NIGHTSMODE) - { - bonustime = true; - break; - } - - if (!bonustime) - { - CONS_Debug(DBG_NIGHTSBASIC, "Removing goal post\n"); - if (goalpost && goalpost->state != &states[S_INVISIBLE]) - P_SetMobjState(goalpost, S_INVISIBLE); - if (sparkle && sparkle->state != &states[S_INVISIBLE]) - P_SetMobjState(sparkle, S_INVISIBLE); - } - } - // Invisible/bouncing mode. - else - { - INT32 i; - boolean bonustime = false; - fixed_t zcomp; - - // Bouncy bouncy! - if (!flip) - { - if (topaligned) - zcomp = droneboxmandiff + mobj->z; - else if (middlealigned) - zcomp = (droneboxmandiff / 2) + mobj->z; - else if (bottomoffsetted) - zcomp = mobj->z + FixedMul(24*FRACUNIT, mobj->scale); - else - zcomp = mobj->z; - } - else - { - if (topaligned) - zcomp = mobj->z; - else if (middlealigned) - zcomp = (droneboxmandiff / 2) + mobj->z; - else if (bottomoffsetted) - zcomp = mobj->z + droneboxmandiff - FixedMul(24*FRACUNIT, mobj->scale); - else - zcomp = mobj->z + droneboxmandiff; - } - - droneman->angle += ANG10; - if (!flip && droneman->z <= zcomp) - droneman->momz = FixedMul(5*FRACUNIT, droneman->scale); - else if (flip && droneman->z >= zcomp) - droneman->momz = FixedMul(-5*FRACUNIT, droneman->scale); - - // state switching logic - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].bonustime && players[i].powers[pw_carry] == CR_NIGHTSMODE) - { - bonustime = true; - break; - } - - if (bonustime) - { - CONS_Debug(DBG_NIGHTSBASIC, "Adding goal post\n"); - if (!(droneman->flags2 & MF2_DONTDRAW)) - droneman->flags2 |= MF2_DONTDRAW; - if (goalpost->state == &states[S_INVISIBLE]) - P_SetMobjState(goalpost, mobjinfo[goalpost->type].meleestate); - if (sparkle->state == &states[S_INVISIBLE]) - P_SetMobjState(sparkle, mobjinfo[sparkle->type].meleestate); - } - else if (!G_IsSpecialStage(gamemap)) - { - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].powers[pw_carry] != CR_NIGHTSMODE) - { - bonustime = true; // variable reuse - break; - } - - if (bonustime) - { - // show droneman if at least one player is non-nights - if (goalpost->state != &states[S_INVISIBLE]) - P_SetMobjState(goalpost, S_INVISIBLE); - if (sparkle->state != &states[S_INVISIBLE]) - P_SetMobjState(sparkle, S_INVISIBLE); - if (droneman->state != &states[mobjinfo[droneman->type].meleestate]) - P_SetMobjState(droneman, mobjinfo[droneman->type].meleestate); - if (droneman->flags2 & MF2_DONTDRAW) - droneman->flags2 &= ~MF2_DONTDRAW; - } - else - { - // else, hide it - if (!(droneman->flags2 & MF2_DONTDRAW)) - droneman->flags2 |= MF2_DONTDRAW; - } - } - } - } - break; - case MT_PLAYER: - if (mobj->player) - P_PlayerMobjThinker(mobj); - return; - case MT_SKIM: - // check mobj against possible water content, before movement code - P_MobjCheckWater(mobj); - - // Keep Skim at water surface - if (mobj->z <= mobj->watertop) - { - mobj->flags |= MF_NOGRAVITY; - if (mobj->z < mobj->watertop) - { - if (mobj->watertop - mobj->z <= FixedMul(mobj->info->speed*FRACUNIT, mobj->scale)) - mobj->z = mobj->watertop; - else - mobj->momz = FixedMul(mobj->info->speed*FRACUNIT, mobj->scale); - } - } - else - { - mobj->flags &= ~MF_NOGRAVITY; - if (mobj->z > mobj->watertop && mobj->z - mobj->watertop < FixedMul(MAXSTEPMOVE, mobj->scale)) - mobj->z = mobj->watertop; - } - break; - case MT_RING: - case MT_REDTEAMRING: - case MT_BLUETEAMRING: - P_KillRingsInLava(mobj); - if (P_MobjWasRemoved(mobj)) - return; - /* FALLTHRU */ - case MT_COIN: - case MT_BLUESPHERE: - case MT_BOMBSPHERE: - case MT_NIGHTSCHIP: - case MT_NIGHTSSTAR: - // No need to check water. Who cares? - P_RingThinker(mobj); - if (mobj->flags2 & MF2_NIGHTSPULL) - P_NightsItemChase(mobj); - else - A_AttractChase(mobj); - return; - // Flung items - case MT_FLINGRING: - P_KillRingsInLava(mobj); - if (P_MobjWasRemoved(mobj)) - return; - /* FALLTHRU */ - case MT_FLINGCOIN: - case MT_FLINGBLUESPHERE: - case MT_FLINGNIGHTSCHIP: - if (mobj->flags2 & MF2_NIGHTSPULL) - P_NightsItemChase(mobj); - else - A_AttractChase(mobj); - break; - case MT_EMBLEM: - if (mobj->flags2 & MF2_NIGHTSPULL) - P_NightsItemChase(mobj); - break; - case MT_SHELL: - if (mobj->threshold && mobj->threshold != TICRATE) - mobj->threshold--; - - if (mobj->threshold >= TICRATE) - { - mobj->angle += ((mobj->movedir == 1) ? ANGLE_22h : ANGLE_337h); - P_InstaThrust(mobj, R_PointToAngle2(0, 0, mobj->momx, mobj->momy), (mobj->info->speed*mobj->scale)); - } - break; - case MT_TURRET: - P_MobjCheckWater(mobj); - P_CheckPosition(mobj, mobj->x, mobj->y); - if (P_MobjWasRemoved(mobj)) - return; - mobj->floorz = tmfloorz; - mobj->ceilingz = tmceilingz; - mobj->floorrover = tmfloorrover; - mobj->ceilingrover = tmceilingrover; - - if ((mobj->eflags & MFE_UNDERWATER) && mobj->health > 0) - { - P_SetMobjState(mobj, mobj->info->deathstate); - mobj->health = 0; - mobj->flags2 &= ~MF2_FIRING; - } - else if (mobj->health > 0 && mobj->z + mobj->height > mobj->ceilingz) // Crushed - { - INT32 i,j; - fixed_t ns; - fixed_t x,y,z; - mobj_t *mo2; - - z = mobj->subsector->sector->floorheight + FixedMul(64*FRACUNIT, mobj->scale); - for (j = 0; j < 2; j++) - { - for (i = 0; i < 32; i++) - { - const angle_t fa = (i*FINEANGLES/16) & FINEMASK; - ns = FixedMul(64 * FRACUNIT, mobj->scale); - x = mobj->x + FixedMul(FINESINE(fa),ns); - y = mobj->y + FixedMul(FINECOSINE(fa),ns); - - mo2 = P_SpawnMobj(x, y, z, MT_EXPLODE); - ns = FixedMul(16 * FRACUNIT, mobj->scale); - mo2->momx = FixedMul(FINESINE(fa),ns); - mo2->momy = FixedMul(FINECOSINE(fa),ns); - } - z -= FixedMul(32*FRACUNIT, mobj->scale); - } - P_SetMobjState(mobj, mobj->info->deathstate); - mobj->health = 0; - mobj->flags2 &= ~MF2_FIRING; - } - break; - case MT_BLUEFLAG: - case MT_REDFLAG: - { - sector_t *sec2; - sec2 = P_ThingOnSpecial3DFloor(mobj); - if ((sec2 && GETSECSPECIAL(sec2->special, 4) == 2) || (GETSECSPECIAL(mobj->subsector->sector->special, 4) == 2)) - mobj->fuse = 1; // Return to base. - break; - } - case MT_CANNONBALL: -#ifdef FLOORSPLATS - R_AddFloorSplat(mobj->tracer->subsector, mobj->tracer, "TARGET", mobj->tracer->x, - mobj->tracer->y, mobj->tracer->floorz, SPLATDRAWMODE_SHADE); -#endif - break; - case MT_SPINDUST: // Spindash dust - mobj->momx = FixedMul(mobj->momx, (3*FRACUNIT)/4); // originally 50000 - mobj->momy = FixedMul(mobj->momy, (3*FRACUNIT)/4); // same - //mobj->momz = mobj->momz+P_MobjFlip(mobj)/3; // no meaningful change in value to be frank - if (mobj->state >= &states[S_SPINDUST_BUBBLE1] && mobj->state <= &states[S_SPINDUST_BUBBLE4]) // bubble dust! - { - P_MobjCheckWater(mobj); - if (mobj->watertop != mobj->subsector->sector->floorheight - 1000*FRACUNIT - && mobj->z+mobj->height >= mobj->watertop - 5*FRACUNIT) - mobj->flags2 |= MF2_DONTDRAW; - } - break; - case MT_TRAINDUSTSPAWNER: - if (leveltime % 5 == 0) { - mobj_t *traindust = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_PARTICLE); - traindust->flags = MF_SCENERY; - P_SetMobjState(traindust, S_TRAINDUST); - traindust->frame = P_RandomRange(0, 8) | FF_TRANS90; - traindust->angle = mobj->angle; - traindust->tics = TICRATE * 4; - traindust->destscale = FRACUNIT * 64; - traindust->scalespeed = FRACUNIT / 24; - P_SetScale(traindust, FRACUNIT * 6); - } - break; - case MT_TRAINSTEAMSPAWNER: - if (leveltime % 5 == 0) { - mobj_t *steam = P_SpawnMobj(mobj->x + FRACUNIT*P_SignedRandom() / 2, mobj->y + FRACUNIT*P_SignedRandom() / 2, mobj->z, MT_PARTICLE); - P_SetMobjState(steam, S_TRAINSTEAM); - steam->frame = P_RandomRange(0, 1) | FF_TRANS90; - steam->tics = TICRATE * 8; - steam->destscale = FRACUNIT * 64; - steam->scalespeed = FRACUNIT / 8; - P_SetScale(steam, FRACUNIT * 16); - steam->momx = P_SignedRandom() * 32; - steam->momy = -64 * FRACUNIT; - steam->momz = 2 * FRACUNIT; - } - break; - case MT_CANARIVORE_GAS: - { - fixed_t momz; - - if (mobj->flags2 & MF2_AMBUSH) - { - mobj->momx = FixedMul(mobj->momx, 50 * FRACUNIT / 51); - mobj->momy = FixedMul(mobj->momy, 50 * FRACUNIT / 51); - break; - } - - if (mobj->eflags & MFE_VERTICALFLIP) - { - if ((mobj->z + mobj->height + mobj->momz) <= mobj->ceilingz) - break; - } - else - { - if ((mobj->z + mobj->momz) >= mobj->floorz) - break; - } - - momz = abs(mobj->momz); - if (R_PointToDist2(0, 0, mobj->momx, mobj->momy) < momz) - P_InstaThrust(mobj, R_PointToAngle2(0, 0, mobj->momx, mobj->momy), momz); - mobj->flags2 |= MF2_AMBUSH; - break; - } - case MT_SALOONDOOR: - { - fixed_t x = mobj->tracer->x; - fixed_t y = mobj->tracer->y; - fixed_t z = mobj->tracer->z; - angle_t oang = FixedAngle(mobj->extravalue1); - angle_t fa = (oang >> ANGLETOFINESHIFT) & FINEMASK; - fixed_t c0 = -96*FINECOSINE(fa); - fixed_t s0 = -96*FINESINE(fa); - angle_t fma; - fixed_t c, s; - angle_t angdiff; - - // Adjust angular speed - fixed_t da = AngleFixed(mobj->angle - oang); - if (da > 180*FRACUNIT) - da -= 360*FRACUNIT; - mobj->extravalue2 = 8*(mobj->extravalue2 - da/32)/9; - - // Update angle - mobj->angle += FixedAngle(mobj->extravalue2); - - angdiff = mobj->angle - FixedAngle(mobj->extravalue1); - if (angdiff > (ANGLE_90 - ANG2) && angdiff < ANGLE_180) - { - mobj->angle = FixedAngle(mobj->extravalue1) + (ANGLE_90 - ANG2); - mobj->extravalue2 /= 2; - } - else if (angdiff < (ANGLE_270 + ANG2) && angdiff >= ANGLE_180) - { - mobj->angle = FixedAngle(mobj->extravalue1) + (ANGLE_270 + ANG2); - mobj->extravalue2 /= 2; - } - - // Update position - fma = (mobj->angle >> ANGLETOFINESHIFT) & FINEMASK; - c = 48*FINECOSINE(fma); - s = 48*FINESINE(fma); - P_TeleportMove(mobj, x + c0 + c, y + s0 + s, z); - break; - } - case MT_MINECARTSPAWNER: - P_HandleMinecartSegments(mobj); - if (!mobj->fuse || mobj->fuse > TICRATE) - break; - if (mobj->fuse == 2) - { - mobj->fuse = 0; - break; - } - mobj->flags2 ^= MF2_DONTDRAW; - break; - case MT_LAVAFALLROCK: - if (P_IsObjectOnGround(mobj)) - P_RemoveMobj(mobj); - break; - case MT_PYREFLY: - { - fixed_t hdist; - - mobj->extravalue1 = (mobj->extravalue1 + 3) % 360; - mobj->z += FINESINE(((mobj->extravalue1*ANG1) >> ANGLETOFINESHIFT) & FINEMASK); - - if (!(mobj->flags2 & MF2_BOSSNOTRAP)) - P_LookForPlayers(mobj, true, false, 1500*FRACUNIT); - - if (!mobj->target) - break; - - if (mobj->extravalue2 == 1) - P_PyreFlyBurn(mobj, 0, 20, MT_SMOKE, 4*FRACUNIT); - else if (mobj->extravalue2 == 2) - { - INT32 fireradius = min(100 - mobj->fuse, 52); - P_PyreFlyBurn(mobj, P_RandomRange(0, fireradius)*FRACUNIT, 20, MT_FLAMEPARTICLE, 4*FRACUNIT); - P_PyreFlyBurn(mobj, fireradius*FRACUNIT, 40, MT_PYREFLY_FIRE, 0); - } - - hdist = R_PointToDist2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); - - if (hdist > 1500*FRACUNIT) - { - mobj->flags2 &= ~MF2_BOSSNOTRAP; - P_SetTarget(&mobj->target, NULL); - break; - } - - if (!(mobj->flags2 & MF2_BOSSNOTRAP) && hdist <= 450*FRACUNIT) - mobj->flags2 |= MF2_BOSSNOTRAP; - - if (!(mobj->flags2 & MF2_BOSSNOTRAP)) - break; - - if (hdist < 1000*FRACUNIT) - { - //Aim for player z position. If too close to floor/ceiling, aim just above/below them. - fixed_t destz = min(max(mobj->target->z, mobj->target->floorz + 70*FRACUNIT), mobj->target->ceilingz - 80*FRACUNIT - mobj->height); - fixed_t dist = P_AproxDistance(hdist, destz - mobj->z); - P_InstaThrust(mobj, R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y), 2*FRACUNIT); - mobj->momz = FixedMul(FixedDiv(destz - mobj->z, dist), 2*FRACUNIT); - } - else - { - mobj->momx = 0; - mobj->momy = 0; - mobj->momz = 0; - } - break; - } - case MT_PTERABYTE: - { - if (mobj->extravalue1 & 4) // Cooldown after grabbing - { - if (mobj->movefactor) - mobj->movefactor--; - else - { - P_SetTarget(&mobj->target, NULL); - mobj->extravalue1 &= 3; - } - } - - if ((mobj->extravalue1 & 3) == 0) // Hovering - { - fixed_t vdist, hdist, time; - fixed_t hspeed = 3*mobj->info->speed; - angle_t fa; - - var1 = 1; - var2 = 0; - A_CapeChase(mobj); - - if (mobj->target) - break; // Still carrying a player or in cooldown - - P_LookForPlayers(mobj, true, false, 256*FRACUNIT); - - if (!mobj->target) - break; - - if (mobj->target->player->powers[pw_flashing]) - { - P_SetTarget(&mobj->target, NULL); - break; - } - - vdist = mobj->z - mobj->target->z - mobj->target->height; - if (P_MobjFlip(mobj)*vdist <= 0) - { - P_SetTarget(&mobj->target, NULL); - break; - } - - hdist = R_PointToDist2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); - if (hdist > 450*FRACUNIT) - { - P_SetTarget(&mobj->target, NULL); - break; - } - - P_SetMobjState(mobj, S_PTERABYTE_SWOOPDOWN); - mobj->extravalue1++; - S_StartSound(mobj, mobj->info->attacksound); - time = FixedDiv(hdist, hspeed); - mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); - fa = (mobj->angle >> ANGLETOFINESHIFT) & FINEMASK; - mobj->momx = FixedMul(FINECOSINE(fa), hspeed); - mobj->momy = FixedMul(FINESINE(fa), hspeed); - mobj->momz = -2*FixedDiv(vdist, time); - mobj->extravalue2 = -FixedDiv(mobj->momz, time); //Z accel - mobj->movecount = time >> FRACBITS; - mobj->reactiontime = mobj->movecount; - } - else if ((mobj->extravalue1 & 3) == 1) // Swooping - { - mobj->reactiontime--; - mobj->momz += mobj->extravalue2; - if (mobj->reactiontime) - break; - - if (mobj->state - states == S_PTERABYTE_SWOOPDOWN) - { - P_SetMobjState(mobj, S_PTERABYTE_SWOOPUP); - mobj->reactiontime = mobj->movecount; - } - else if (mobj->state - states == S_PTERABYTE_SWOOPUP) - { - P_SetMobjState(mobj, S_PTERABYTE_FLY1); - mobj->extravalue1++; - if (mobj->target && mobj->target->tracer != mobj) - P_SetTarget(&mobj->target, NULL); // Failed to grab the target - mobj->momx = mobj->momy = mobj->momz = 0; - } - } - else // Returning - { - var1 = 2*mobj->info->speed; - var2 = 1; - A_HomingChase(mobj); - if (P_AproxDistance(mobj->x - mobj->tracer->x, mobj->y - mobj->tracer->y) <= mobj->info->speed) - { - mobj->extravalue1 -= 2; - mobj->momx = mobj->momy = mobj->momz = 0; - } - } - break; - } - case MT_DRAGONBOMBER: - { -#define DRAGONTURNSPEED ANG2 - mobj->movecount = (mobj->movecount + 9) % 360; - P_SetObjectMomZ(mobj, 4*FINESINE(((mobj->movecount*ANG1) >> ANGLETOFINESHIFT) & FINEMASK), false); - if (mobj->threshold > 0) // are we dropping mines? - { - mobj->threshold--; - if (mobj->threshold == 0) // if the timer hits 0, look for a mine to drop! - { - mobj_t *segment = mobj; - while (segment->tracer != NULL && !P_MobjWasRemoved(segment->tracer) && segment->tracer->state == &states[segment->tracer->info->spawnstate]) - { - segment = segment->tracer; - } - if (segment != mobj) // found an unactivated segment? - { - mobj_t *mine = P_SpawnMobjFromMobj(segment, 0, 0, 0, segment->info->painchance); - mine->angle = segment->angle; - P_InstaThrust(mine, mobj->angle, P_AproxDistance(mobj->momx, mobj->momy) >> 1); - P_SetObjectMomZ(mine, -2*FRACUNIT, true); - S_StartSound(mine, mine->info->seesound); - P_SetMobjState(segment, segment->info->raisestate); - mobj->threshold = mobj->info->painchance; - } - } - } - if (mobj->target != NULL) // Are we chasing a player? - { - fixed_t dist = P_AproxDistance(mobj->x - mobj->target->x, mobj->y - mobj->target->y); - if (dist > 2000 * mobj->scale) // Not anymore! - P_SetTarget(&mobj->target, NULL); - else - { - fixed_t vspeed = FixedMul(mobj->info->speed >> 3, mobj->scale); - fixed_t z = mobj->target->z + (mobj->height >> 1) + (mobj->flags & MFE_VERTICALFLIP ? -128*mobj->scale : 128*mobj->scale + mobj->target->height); - angle_t diff = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y) - mobj->angle; - if (diff > ANGLE_180) - mobj->angle -= DRAGONTURNSPEED; - else - mobj->angle += DRAGONTURNSPEED; - if (!mobj->threshold && dist < 512 * mobj->scale) // Close enough to drop bombs - { - mobj->threshold = mobj->info->painchance; - } - mobj->momz += max(min(z - mobj->z, vspeed), -vspeed); - } - } - else // Can we find a player to chase? - { - if (mobj->tracer == NULL || mobj->tracer->state != &states[mobj->tracer->info->spawnstate] - || !P_LookForPlayers(mobj, true, false, 2000*mobj->scale)) // if not, circle around the spawnpoint - { - if (!mobj->spawnpoint) // unless we don't have one, in which case uhhh just circle around wherever we currently are I guess?? - mobj->angle += DRAGONTURNSPEED; - else - { - fixed_t vspeed = FixedMul(mobj->info->speed >> 3, mobj->scale); - fixed_t x = mobj->spawnpoint->x << FRACBITS; - fixed_t y = mobj->spawnpoint->y << FRACBITS; - fixed_t z = mobj->spawnpoint->z << FRACBITS; - angle_t diff = R_PointToAngle2(mobj->x, mobj->y, x, y) - mobj->angle; - if (diff > ANGLE_180) - mobj->angle -= DRAGONTURNSPEED; - else - mobj->angle += DRAGONTURNSPEED; - mobj->momz += max(min(z - mobj->z, vspeed), -vspeed); - } - } - } - P_InstaThrust(mobj, mobj->angle, FixedMul(mobj->info->speed, mobj->scale)); -#undef DRAGONTURNSPEED - } - break; - case MT_MINUS: -#ifdef ROTSPRITE - { - if (P_IsObjectOnGround(mobj)) - mobj->rollangle = 0; - else - mobj->rollangle = R_PointToAngle2(0, 0, mobj->momz, (mobj->scale << 1) - min(abs(mobj->momz), mobj->scale << 1)); - } -#endif - break; - case MT_SPINFIRE: - if (mobj->flags & MF_NOGRAVITY) - { - if (mobj->eflags & MFE_VERTICALFLIP) - mobj->z = mobj->ceilingz - mobj->height; - else - mobj->z = mobj->floorz; - } - else if ((!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z <= mobj->floorz) - || ((mobj->eflags & MFE_VERTICALFLIP) && mobj->z+mobj->height >= mobj->ceilingz)) - { - mobj->flags |= MF_NOGRAVITY; - mobj->momx = 8; // this is a hack which is used to ensure it still behaves as a missile and can damage others - mobj->momy = mobj->momz = 0; - mobj->z = ((mobj->eflags & MFE_VERTICALFLIP) ? mobj->ceilingz-mobj->height : mobj->floorz); - } - /* FALLTHRU */ - default: - // check mobj against possible water content, before movement code - P_MobjCheckWater(mobj); - - // Extinguish fire objects in water - if (mobj->flags & MF_FIRE && mobj->type != MT_PUMA && mobj->type != MT_FIREBALL - && (mobj->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER))) - { - P_KillMobj(mobj, NULL, NULL, 0); - return; - } - break; - } + if (!P_MobjRegularThink(mobj)) + return; } if (P_MobjWasRemoved(mobj)) return; From 6032aa3cd1c2d55053971fb2738f6f4753306aa6 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Wed, 25 Dec 2019 00:18:12 +0100 Subject: [PATCH 189/195] P_MobjThinker: Separate MF2_FIRING handling into its own function --- src/p_mobj.c | 93 ++++++++++++++++++++++++++++------------------------ 1 file changed, 51 insertions(+), 42 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 84592dcaa..10ca92a2d 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9803,6 +9803,55 @@ static boolean P_MobjRegularThink(mobj_t *mobj) return true; } +static void P_FiringThink(mobj_t* mobj) +{ + if (!mobj->target) + return; + + if (mobj->health <= 0) + return; + + if (mobj->state->action.acp1 == (actionf_p1)A_Boss1Laser) + { + if (mobj->state->tics > 1) + { + var1 = mobj->state->var1; + var2 = mobj->state->var2 & 65535; + mobj->state->action.acp1(mobj); + } + } + else if (leveltime & 1) // Fire mode + { + mobj_t *missile; + + if (mobj->target->player && mobj->target->player->powers[pw_carry] == CR_NIGHTSMODE) + { + fixed_t oldval = mobjinfo[mobj->extravalue1].speed; + + mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x + mobj->target->momx, mobj->target->y + mobj->target->momy); + mobjinfo[mobj->extravalue1].speed = FixedMul(60*FRACUNIT, mobj->scale); + missile = P_SpawnMissile(mobj, mobj->target, mobj->extravalue1); + mobjinfo[mobj->extravalue1].speed = oldval; + } + else + { + mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); + missile = P_SpawnMissile(mobj, mobj->target, mobj->extravalue1); + } + + if (missile) + { + if (mobj->flags2 & MF2_SUPERFIRE) + missile->flags2 |= MF2_SUPERFIRE; + + if (mobj->info->attacksound) + S_StartSound(missile, mobj->info->attacksound); + } + } + else + mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); +} + // // P_MobjThinker // @@ -9907,48 +9956,8 @@ void P_MobjThinker(mobj_t *mobj) if (P_MobjWasRemoved(mobj)) return; - if (mobj->flags2 & MF2_FIRING && mobj->target && mobj->health > 0) - { - if (mobj->state->action.acp1 == (actionf_p1)A_Boss1Laser) - { - if (mobj->state->tics > 1) - { - var1 = mobj->state->var1; - var2 = mobj->state->var2 & 65535; - mobj->state->action.acp1(mobj); - } - } - else if (leveltime & 1) // Fire mode - { - mobj_t *missile; - - if (mobj->target->player && mobj->target->player->powers[pw_carry] == CR_NIGHTSMODE) - { - fixed_t oldval = mobjinfo[mobj->extravalue1].speed; - - mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x+mobj->target->momx, mobj->target->y+mobj->target->momy); - mobjinfo[mobj->extravalue1].speed = FixedMul(60*FRACUNIT, mobj->scale); - missile = P_SpawnMissile(mobj, mobj->target, mobj->extravalue1); - mobjinfo[mobj->extravalue1].speed = oldval; - } - else - { - mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); - missile = P_SpawnMissile(mobj, mobj->target, mobj->extravalue1); - } - - if (missile) - { - if (mobj->flags2 & MF2_SUPERFIRE) - missile->flags2 |= MF2_SUPERFIRE; - - if (mobj->info->attacksound) - S_StartSound(missile, mobj->info->attacksound); - } - } - else - mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); - } + if (mobj->flags2 & MF2_FIRING) + P_FiringThink(mobj); if (mobj->flags & MF_AMBIENT) { From 64df10f7bee74f221fd2a70978948911613a9822 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Wed, 25 Dec 2019 00:36:24 +0100 Subject: [PATCH 190/195] P_MobjThinker: Separate fuse handling into its own function --- src/p_mobj.c | 437 ++++++++++++++++++++++++++------------------------- 1 file changed, 226 insertions(+), 211 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 10ca92a2d..292545328 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9803,7 +9803,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) return true; } -static void P_FiringThink(mobj_t* mobj) +static void P_FiringThink(mobj_t *mobj) { if (!mobj->target) return; @@ -9852,6 +9852,229 @@ static void P_FiringThink(mobj_t* mobj) mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); } +static void P_MonitorFuseThink(mobj_t *mobj) +{ + mobj_t *newmobj; + + // Special case for ALL monitors. + // If a box's speed is nonzero, it's allowed to respawn as a WRM/SRM. + if (mobj->info->speed != 0 && (mobj->flags2 & (MF2_AMBUSH|MF2_STRONGBOX))) + { + mobjtype_t spawnchance[64]; + INT32 numchoices = 0, i = 0; + + // This define should make it a lot easier to organize and change monitor weights +#define SETMONITORCHANCES(type, strongboxamt, weakboxamt) \ +for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) spawnchance[numchoices++] = type + + // Type SRM WRM + SETMONITORCHANCES(MT_SNEAKERS_BOX, 0, 10); // Super Sneakers + SETMONITORCHANCES(MT_INVULN_BOX, 2, 0); // Invincibility + SETMONITORCHANCES(MT_WHIRLWIND_BOX, 3, 8); // Whirlwind Shield + SETMONITORCHANCES(MT_ELEMENTAL_BOX, 3, 8); // Elemental Shield + SETMONITORCHANCES(MT_ATTRACT_BOX, 2, 0); // Attraction Shield + SETMONITORCHANCES(MT_FORCE_BOX, 3, 3); // Force Shield + SETMONITORCHANCES(MT_ARMAGEDDON_BOX, 2, 0); // Armageddon Shield + SETMONITORCHANCES(MT_MIXUP_BOX, 0, 1); // Teleporters + SETMONITORCHANCES(MT_RECYCLER_BOX, 0, 1); // Recycler + SETMONITORCHANCES(MT_1UP_BOX, 1, 1); // 1-Up + // ======================================= + // Total 16 32 + +#undef SETMONITORCHANCES + + i = P_RandomKey(numchoices); // Gotta love those random numbers! + newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, spawnchance[i]); + } + else + newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->type); + + // Transfer flags2 (ambush, strongbox, objectflip) + newmobj->flags2 = mobj->flags2; + P_RemoveMobj(mobj); // make sure they disappear +} + +static void P_FlagFuseThink(mobj_t *mobj) +{ + subsector_t *ss; + fixed_t x, y, z; + mobj_t* flagmo; + + if (!mobj->spawnpoint) + return; + + x = mobj->spawnpoint->x << FRACBITS; + y = mobj->spawnpoint->y << FRACBITS; + ss = R_PointInSubsector(x, y); + if (mobj->spawnpoint->options & MTF_OBJECTFLIP) + { + z = ss->sector->ceilingheight - mobjinfo[mobj->type].height; + if (mobj->spawnpoint->options >> ZSHIFT) + z -= (mobj->spawnpoint->options >> ZSHIFT) << FRACBITS; + } + else + { + z = ss->sector->floorheight; + if (mobj->spawnpoint->options >> ZSHIFT) + z += (mobj->spawnpoint->options >> ZSHIFT) << FRACBITS; + } + flagmo = P_SpawnMobj(x, y, z, mobj->type); + flagmo->spawnpoint = mobj->spawnpoint; + if (mobj->spawnpoint->options & MTF_OBJECTFLIP) + { + flagmo->eflags |= MFE_VERTICALFLIP; + flagmo->flags2 |= MF2_OBJECTFLIP; + } + + if (mobj->type == MT_REDFLAG) + { + if (!(mobj->flags2 & MF2_JUSTATTACKED)) + CONS_Printf(M_GetText("The %c%s%c has returned to base.\n"), 0x85, M_GetText("Red flag"), 0x80); + + // Assumedly in splitscreen players will be on opposing teams + if (players[consoleplayer].ctfteam == 1 || splitscreen) + S_StartSound(NULL, sfx_hoop1); + else if (players[consoleplayer].ctfteam == 2) + S_StartSound(NULL, sfx_hoop3); + + redflag = flagmo; + } + else // MT_BLUEFLAG + { + if (!(mobj->flags2 & MF2_JUSTATTACKED)) + CONS_Printf(M_GetText("The %c%s%c has returned to base.\n"), 0x84, M_GetText("Blue flag"), 0x80); + + // Assumedly in splitscreen players will be on opposing teams + if (players[consoleplayer].ctfteam == 2 || splitscreen) + S_StartSound(NULL, sfx_hoop1); + else if (players[consoleplayer].ctfteam == 1) + S_StartSound(NULL, sfx_hoop3); + + blueflag = flagmo; + } +} + +static boolean P_FuseThink(mobj_t *mobj) +{ + if (mobj->type == MT_SNAPPER_HEAD || mobj->type == MT_SNAPPER_LEG || mobj->type == MT_MINECARTSEG) + mobj->flags2 ^= MF2_DONTDRAW; + + mobj->fuse--; + + if (mobj->fuse) + return true; + +#ifdef HAVE_BLUA + if (LUAh_MobjFuse(mobj) || P_MobjWasRemoved(mobj)) + ; + else +#endif + if (mobj->info->flags & MF_MONITOR) + { + P_MonitorFuseThink(mobj); + return false; + } + else switch (mobj->type) + { + // gargoyle and snowman handled in P_PushableThinker, not here + case MT_THROWNGRENADE: + case MT_CYBRAKDEMON_NAPALM_BOMB_LARGE: + P_SetMobjState(mobj, mobj->info->deathstate); + break; + case MT_LHRT: + P_KillMobj(mobj, NULL, NULL, 0); + break; + case MT_BLUEFLAG: + case MT_REDFLAG: + P_FlagFuseThink(mobj); + P_RemoveMobj(mobj); + return false; + case MT_FANG: + if (mobj->flags2 & MF2_SLIDEPUSH) + { + var1 = 0; + var2 = 0; + A_BossDeath(mobj); + return false; + } + P_SetMobjState(mobj, mobj->state->nextstate); + if (P_MobjWasRemoved(mobj)) + return false; + break; + case MT_METALSONIC_BATTLE: + break; // don't remove + case MT_SPIKE: + P_SetMobjState(mobj, mobj->state->nextstate); + mobj->fuse = mobj->info->speed; + if (mobj->spawnpoint) + mobj->fuse += mobj->spawnpoint->angle; + break; + case MT_WALLSPIKE: + P_SetMobjState(mobj, mobj->state->nextstate); + mobj->fuse = mobj->info->speed; + if (mobj->spawnpoint) + mobj->fuse += (mobj->spawnpoint->angle / 360); + break; + case MT_NIGHTSCORE: + P_RemoveMobj(mobj); + return false; + case MT_LAVAFALL: + if (mobj->state - states == S_LAVAFALL_DORMANT) + { + mobj->fuse = 30; + P_SetMobjState(mobj, S_LAVAFALL_TELL); + S_StartSound(mobj, mobj->info->seesound); + } + else if (mobj->state - states == S_LAVAFALL_TELL) + { + mobj->fuse = 40; + P_SetMobjState(mobj, S_LAVAFALL_SHOOT); + S_StopSound(mobj); + S_StartSound(mobj, mobj->info->attacksound); + } + else + { + mobj->fuse = 30; + P_SetMobjState(mobj, S_LAVAFALL_DORMANT); + S_StopSound(mobj); + } + return false; + case MT_PYREFLY: + if (mobj->health <= 0) + break; + + mobj->extravalue2 = (mobj->extravalue2 + 1) % 3; + if (mobj->extravalue2 == 0) + { + P_SetMobjState(mobj, mobj->info->spawnstate); + mobj->fuse = 100; + S_StopSound(mobj); + S_StartSound(mobj, sfx_s3k8c); + } + else if (mobj->extravalue2 == 1) + { + mobj->fuse = 50; + S_StartSound(mobj, sfx_s3ka3); + } + else + { + P_SetMobjState(mobj, mobj->info->meleestate); + mobj->fuse = 100; + S_StopSound(mobj); + S_StartSound(mobj, sfx_s3kc2l); + } + return false; + case MT_PLAYER: + break; // don't remove + default: + P_SetMobjState(mobj, mobj->info->xdeathstate); // will remove the mobj if S_NULL. + break; + // Looking for monitors? They moved to a special condition above. + } + + return !P_MobjWasRemoved(mobj); +} + // // P_MobjThinker // @@ -9967,216 +10190,8 @@ void P_MobjThinker(mobj_t *mobj) } // Check fuse - if (mobj->fuse) - { - - if (mobj->type == MT_SNAPPER_HEAD || mobj->type == MT_SNAPPER_LEG || mobj->type == MT_MINECARTSEG) - mobj->flags2 ^= MF2_DONTDRAW; - - mobj->fuse--; - if (!mobj->fuse) - { - subsector_t *ss; - fixed_t x, y, z; - mobj_t *flagmo, *newmobj; - -#ifdef HAVE_BLUA - if (LUAh_MobjFuse(mobj) || P_MobjWasRemoved(mobj)) - ; - else -#endif - if (mobj->info->flags & MF_MONITOR) - { - // Special case for ALL monitors. - // If a box's speed is nonzero, it's allowed to respawn as a WRM/SRM. - if (mobj->info->speed != 0 && (mobj->flags2 & (MF2_AMBUSH|MF2_STRONGBOX))) - { - mobjtype_t spawnchance[64]; - INT32 numchoices = 0, i = 0; - -// This define should make it a lot easier to organize and change monitor weights -#define SETMONITORCHANCES(type, strongboxamt, weakboxamt) \ -for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) spawnchance[numchoices++] = type - - // Type SRM WRM - SETMONITORCHANCES(MT_SNEAKERS_BOX, 0, 10); // Super Sneakers - SETMONITORCHANCES(MT_INVULN_BOX, 2, 0); // Invincibility - SETMONITORCHANCES(MT_WHIRLWIND_BOX, 3, 8); // Whirlwind Shield - SETMONITORCHANCES(MT_ELEMENTAL_BOX, 3, 8); // Elemental Shield - SETMONITORCHANCES(MT_ATTRACT_BOX, 2, 0); // Attraction Shield - SETMONITORCHANCES(MT_FORCE_BOX, 3, 3); // Force Shield - SETMONITORCHANCES(MT_ARMAGEDDON_BOX, 2, 0); // Armageddon Shield - SETMONITORCHANCES(MT_MIXUP_BOX, 0, 1); // Teleporters - SETMONITORCHANCES(MT_RECYCLER_BOX, 0, 1); // Recycler - SETMONITORCHANCES(MT_1UP_BOX, 1, 1); // 1-Up - // ======================================= - // Total 16 32 - -#undef SETMONITORCHANCES - - i = P_RandomKey(numchoices); // Gotta love those random numbers! - newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, spawnchance[i]); - } - else - newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->type); - - // Transfer flags2 (ambush, strongbox, objectflip) - newmobj->flags2 = mobj->flags2; - P_RemoveMobj(mobj); // make sure they disappear - return; - } - else switch (mobj->type) - { - // gargoyle and snowman handled in P_PushableThinker, not here - case MT_THROWNGRENADE: - case MT_CYBRAKDEMON_NAPALM_BOMB_LARGE: - P_SetMobjState(mobj, mobj->info->deathstate); - break; - case MT_LHRT: - P_KillMobj(mobj, NULL, NULL, 0); - break; - case MT_BLUEFLAG: - case MT_REDFLAG: - if (mobj->spawnpoint) - { - x = mobj->spawnpoint->x << FRACBITS; - y = mobj->spawnpoint->y << FRACBITS; - ss = R_PointInSubsector(x, y); - if (mobj->spawnpoint->options & MTF_OBJECTFLIP) - { - z = ss->sector->ceilingheight - mobjinfo[mobj->type].height; - if (mobj->spawnpoint->options >> ZSHIFT) - z -= (mobj->spawnpoint->options >> ZSHIFT) << FRACBITS; - } - else - { - z = ss->sector->floorheight; - if (mobj->spawnpoint->options >> ZSHIFT) - z += (mobj->spawnpoint->options >> ZSHIFT) << FRACBITS; - } - flagmo = P_SpawnMobj(x, y, z, mobj->type); - flagmo->spawnpoint = mobj->spawnpoint; - if (mobj->spawnpoint->options & MTF_OBJECTFLIP) - { - flagmo->eflags |= MFE_VERTICALFLIP; - flagmo->flags2 |= MF2_OBJECTFLIP; - } - - if (mobj->type == MT_REDFLAG) - { - if (!(mobj->flags2 & MF2_JUSTATTACKED)) - CONS_Printf(M_GetText("The %c%s%c has returned to base.\n"), 0x85, M_GetText("Red flag"), 0x80); - - // Assumedly in splitscreen players will be on opposing teams - if (players[consoleplayer].ctfteam == 1 || splitscreen) - S_StartSound(NULL, sfx_hoop1); - else if (players[consoleplayer].ctfteam == 2) - S_StartSound(NULL, sfx_hoop3); - - redflag = flagmo; - } - else // MT_BLUEFLAG - { - if (!(mobj->flags2 & MF2_JUSTATTACKED)) - CONS_Printf(M_GetText("The %c%s%c has returned to base.\n"), 0x84, M_GetText("Blue flag"), 0x80); - - // Assumedly in splitscreen players will be on opposing teams - if (players[consoleplayer].ctfteam == 2 || splitscreen) - S_StartSound(NULL, sfx_hoop1); - else if (players[consoleplayer].ctfteam == 1) - S_StartSound(NULL, sfx_hoop3); - - blueflag = flagmo; - } - } - P_RemoveMobj(mobj); - return; - case MT_FANG: - if (mobj->flags2 & MF2_SLIDEPUSH) - { - var1 = 0; - var2 = 0; - A_BossDeath(mobj); - return; - } - P_SetMobjState(mobj, mobj->state->nextstate); - if (P_MobjWasRemoved(mobj)) - return; - break; - case MT_METALSONIC_BATTLE: - break; // don't remove - case MT_SPIKE: - P_SetMobjState(mobj, mobj->state->nextstate); - mobj->fuse = mobj->info->speed; - if (mobj->spawnpoint) - mobj->fuse += mobj->spawnpoint->angle; - break; - case MT_WALLSPIKE: - P_SetMobjState(mobj, mobj->state->nextstate); - mobj->fuse = mobj->info->speed; - if (mobj->spawnpoint) - mobj->fuse += (mobj->spawnpoint->angle/360); - break; - case MT_NIGHTSCORE: - P_RemoveMobj(mobj); - return; - case MT_LAVAFALL: - if (mobj->state - states == S_LAVAFALL_DORMANT) - { - mobj->fuse = 30; - P_SetMobjState(mobj, S_LAVAFALL_TELL); - S_StartSound(mobj, mobj->info->seesound); - } - else if (mobj->state - states == S_LAVAFALL_TELL) - { - mobj->fuse = 40; - P_SetMobjState(mobj, S_LAVAFALL_SHOOT); - S_StopSound(mobj); - S_StartSound(mobj, mobj->info->attacksound); - } - else - { - mobj->fuse = 30; - P_SetMobjState(mobj, S_LAVAFALL_DORMANT); - S_StopSound(mobj); - } - return; - case MT_PYREFLY: - if (mobj->health <= 0) - break; - - mobj->extravalue2 = (mobj->extravalue2 + 1) % 3; - if (mobj->extravalue2 == 0) - { - P_SetMobjState(mobj, mobj->info->spawnstate); - mobj->fuse = 100; - S_StopSound(mobj); - S_StartSound(mobj, sfx_s3k8c); - } - else if (mobj->extravalue2 == 1) - { - mobj->fuse = 50; - S_StartSound(mobj, sfx_s3ka3); - } - else - { - P_SetMobjState(mobj, mobj->info->meleestate); - mobj->fuse = 100; - S_StopSound(mobj); - S_StartSound(mobj, sfx_s3kc2l); - } - return; - case MT_PLAYER: - break; // don't remove - default: - P_SetMobjState(mobj, mobj->info->xdeathstate); // will remove the mobj if S_NULL. - break; - // Looking for monitors? They moved to a special condition above. - } - if (P_MobjWasRemoved(mobj)) - return; - } - } + if (mobj->fuse && !P_FuseThink(mobj)) + return; I_Assert(mobj != NULL); I_Assert(!P_MobjWasRemoved(mobj)); From c4a017ddf01e6c529df0369bb28e66d9aa0cdf20 Mon Sep 17 00:00:00 2001 From: Nev3r Date: Wed, 25 Dec 2019 12:05:40 +0100 Subject: [PATCH 191/195] Move flat caching code to the map data load function. --- src/p_setup.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index f5d4c26e2..3ae17cc23 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -651,14 +651,6 @@ static void P_LoadRawSectors(UINT8 *data) sector_t *ss = sectors; size_t i; - // Allocate a big chunk of memory as big as our MAXLEVELFLATS limit. - //Fab : FIXME: allocate for whatever number of flats - 512 different flats per level should be plenty - foundflats = calloc(MAXLEVELFLATS, sizeof (*foundflats)); - if (foundflats == NULL) - I_Error("Ran out of memory while loading sectors\n"); - - numlevelflats = 0; - // For each counted sector, copy the sector raw data from our cache pointer ms, to the global table pointer ss. for (i = 0; i < numsectors; i++, ss++, ms++) { @@ -1982,6 +1974,14 @@ static void P_LoadMapData(const virtres_t* virt) lines = Z_Calloc(numlines * sizeof (*lines), PU_LEVEL, NULL); mapthings = Z_Calloc(nummapthings * sizeof (*mapthings), PU_LEVEL, NULL); + // Allocate a big chunk of memory as big as our MAXLEVELFLATS limit. + //Fab : FIXME: allocate for whatever number of flats - 512 different flats per level should be plenty + foundflats = calloc(MAXLEVELFLATS, sizeof (*foundflats)); + if (foundflats == NULL) + I_Error("Ran out of memory while loading sectors\n"); + + numlevelflats = 0; + #ifdef UDMF if (textmap) { From 5241030012cf53746192d8004f21e0118297853f Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Wed, 25 Dec 2019 21:48:59 +0000 Subject: [PATCH 192/195] Fix ShouldDamage, MobjDamage and MobjDeath hooks all messing up the pushing of variables to Lua as function args, by adding damagetype support where it was missing! The above issue occured only if you had both a generic hook and a type specific hook for a particular hook type. This way, the stack is never updated to include damagetype at the start, and all pushes of the variables get offsetted by 1 compared to what they should be, once the code *expects* damagetype to be included in it. --- src/lua_hooklib.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index ef87d0b6f..aadba6aba 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -657,14 +657,16 @@ UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 LUA_PushUserdata(gL, inflictor, META_MOBJ); LUA_PushUserdata(gL, source, META_MOBJ); lua_pushinteger(gL, damage); + lua_pushinteger(gL, damagetype); } lua_pushfstring(gL, FMT_HOOKID, hookp->id); lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 0)) { + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + if (lua_pcall(gL, 5, 1, 0)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -745,14 +747,16 @@ boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 LUA_PushUserdata(gL, inflictor, META_MOBJ); LUA_PushUserdata(gL, source, META_MOBJ); lua_pushinteger(gL, damage); + lua_pushinteger(gL, damagetype); } lua_pushfstring(gL, FMT_HOOKID, hookp->id); lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 0)) { + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + if (lua_pcall(gL, 5, 1, 0)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); @@ -823,13 +827,15 @@ boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 LUA_PushUserdata(gL, target, META_MOBJ); LUA_PushUserdata(gL, inflictor, META_MOBJ); LUA_PushUserdata(gL, source, META_MOBJ); + lua_pushinteger(gL, damagetype); } lua_pushfstring(gL, FMT_HOOKID, hookp->id); lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - if (lua_pcall(gL, 3, 1, 0)) { + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + if (lua_pcall(gL, 4, 1, 0)) { if (!hookp->error || cv_debug & DBG_LUA) CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); From 70f08007ebff21a97b10f5978d2765d002ace6d4 Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 25 Dec 2019 15:23:19 -0800 Subject: [PATCH 193/195] Correct the check for rings on thing 604 - 607 The original code used a switch case, not AND 1. :V --- src/p_mobj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 13f75b94a..1882a4e3c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -13372,7 +13372,7 @@ void P_SpawnItemPattern(mapthing_t *mthing, boolean bonustime) { INT32 numitems = (mthing->type & 1) ? 16 : 8; fixed_t size = (mthing->type & 1) ? 192*FRACUNIT : 96*FRACUNIT; - mobjtype_t itemtypes[1] = { (mthing->type & 1) ? MT_RING : MT_BLUESPHERE }; + mobjtype_t itemtypes[1] = { (mthing->type < 606) ? MT_RING : MT_BLUESPHERE }; P_SpawnItemCircle(mthing, itemtypes, 1, numitems, size, bonustime); return; } From 50379dac858f60057c474806bad160e558c34cb2 Mon Sep 17 00:00:00 2001 From: Alam Ed Arias Date: Thu, 26 Dec 2019 12:27:15 -0500 Subject: [PATCH 194/195] cleanup buildbot error --- src/p_mobj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 1882a4e3c..bd0927355 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -13005,7 +13005,7 @@ static void P_SetObjectSpecial(mobj_t *mobj) } } -mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y, fixed_t z, mobjtype_t i) +static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y, fixed_t z, mobjtype_t i) { mobj_t *mobj = NULL; boolean doangle = true; From ca5a4d90e0e3445df560a6adc7884eb22df02f3b Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Thu, 26 Dec 2019 21:59:09 +0000 Subject: [PATCH 195/195] Fix mixed declaration-and-code compiling error --- src/p_mobj.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index b3705ee44..9ecd1d32a 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8321,6 +8321,8 @@ static boolean P_MobjDeadThink(mobj_t *mobj) // See Linedef Exec 457 (Track mobj angle to point) static void P_TracerAngleThink(mobj_t *mobj) { + angle_t ang; + if (!mobj->tracer) return; @@ -8333,7 +8335,7 @@ static void P_TracerAngleThink(mobj_t *mobj) // mobj->cvval - Allowable failure delay // mobj->cvmem - Failure timer - angle_t ang = mobj->angle - R_PointToAngle2(mobj->x, mobj->y, mobj->tracer->x, mobj->tracer->y); + ang = mobj->angle - R_PointToAngle2(mobj->x, mobj->y, mobj->tracer->x, mobj->tracer->y); // \todo account for distance between mobj and tracer // Because closer mobjs can be facing beyond the angle tolerance