diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d35e774e9..87a0499b6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -276,6 +276,7 @@ set(SRB2_LUA_SOURCES lua_hudlib.c lua_infolib.c lua_maplib.c + lua_taglib.c lua_mathlib.c lua_mobjlib.c lua_playerlib.c diff --git a/src/blua/Makefile.cfg b/src/blua/Makefile.cfg index eae95ba3a..3a2962e65 100644 --- a/src/blua/Makefile.cfg +++ b/src/blua/Makefile.cfg @@ -47,6 +47,7 @@ OBJS:=$(OBJS) \ $(OBJDIR)/lua_skinlib.o \ $(OBJDIR)/lua_thinkerlib.o \ $(OBJDIR)/lua_maplib.o \ + $(OBJDIR)/lua_taglib.o \ $(OBJDIR)/lua_polyobjlib.o \ $(OBJDIR)/lua_blockmaplib.o \ $(OBJDIR)/lua_hudlib.o diff --git a/src/console.c b/src/console.c index b19b8818d..c7bfe0fe1 100644 --- a/src/console.c +++ b/src/console.c @@ -360,30 +360,48 @@ static void CON_SetupColormaps(void) for (i = 0; i < (256*15); i++, ++memorysrc) *memorysrc = (UINT8)(i & 0xFF); // remap each color to itself... -#define colset(map, a, b, c) \ - map[1] = (UINT8)a;\ - map[3] = (UINT8)b;\ - map[9] = (UINT8)c +#define colset(map, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \ + map[0x0] = (UINT8)a;\ + map[0x1] = (UINT8)b;\ + map[0x2] = (UINT8)c;\ + map[0x3] = (UINT8)d;\ + map[0x4] = (UINT8)e;\ + map[0x5] = (UINT8)f;\ + map[0x6] = (UINT8)g;\ + map[0x7] = (UINT8)h;\ + map[0x8] = (UINT8)i;\ + map[0x9] = (UINT8)j;\ + map[0xA] = (UINT8)k;\ + map[0xB] = (UINT8)l;\ + map[0xC] = (UINT8)m;\ + map[0xD] = (UINT8)n;\ + map[0xE] = (UINT8)o;\ + map[0xF] = (UINT8)p; - colset(magentamap, 177, 178, 184); - colset(yellowmap, 82, 73, 66); - colset(lgreenmap, 97, 98, 106); - colset(bluemap, 146, 147, 155); - colset(redmap, 210, 32, 39); - colset(graymap, 6, 8, 14); - colset(orangemap, 51, 52, 57); - colset(skymap, 129, 130, 133); - colset(purplemap, 160, 161, 163); - colset(aquamap, 120, 121, 123); - colset(peridotmap, 88, 188, 190); - colset(azuremap, 144, 145, 170); - colset(brownmap, 219, 221, 224); - colset(rosymap, 200, 201, 203); - colset(invertmap, 27, 26, 22); - invertmap[26] = (UINT8)3; + // Tried to keep the colors vanilla while adding some shades in between them ~SonicX8000 + + // 0x1 0x3 0x9 0xF + colset(magentamap, 177, 177, 178, 178, 178, 180, 180, 180, 182, 182, 182, 182, 184, 184, 184, 185); + colset(yellowmap, 82, 82, 73, 73, 73, 64, 64, 64, 66, 66, 66, 66, 67, 67, 67, 68); + colset(lgreenmap, 96, 96, 98, 98, 98, 101, 101, 101, 104, 104, 104, 104, 106, 106, 106, 107); + colset(bluemap, 146, 146, 147, 147, 147, 149, 149, 149, 152, 152, 152, 152, 155, 155, 155, 157); + colset(redmap, 32, 32, 33, 33, 33, 35, 35, 35, 39, 39, 39, 39, 42, 42, 42, 44); + colset(graymap, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23); + colset(orangemap, 50, 50, 52, 52, 52, 54, 54, 54, 56, 56, 56, 56, 59, 59, 59, 60); + colset(skymap, 129, 129, 130, 130, 130, 131, 131, 131, 133, 133, 133, 133, 135, 135, 135, 136); + colset(purplemap, 160, 160, 161, 161, 161, 162, 162, 162, 163, 163, 163, 163, 164, 164, 164, 165); + colset(aquamap, 120, 120, 121, 121, 121, 122, 122, 122, 123, 123, 123, 123, 124, 124, 124, 125); + colset(peridotmap, 72, 72, 188, 188, 189, 189, 189, 189, 190, 190, 190, 190, 191, 191, 191, 94); + colset(azuremap, 144, 144, 145, 145, 145, 146, 146, 146, 170, 170, 170, 170, 171, 171, 171, 172); + colset(brownmap, 219, 219, 221, 221, 221, 222, 222, 222, 224, 224, 224, 224, 227, 227, 227, 229); + colset(rosymap, 200, 200, 201, 201, 201, 202, 202, 202, 203, 203, 203, 203, 204, 204, 204, 205); #undef colset + // Yeah just straight up invert it like a normal person + for (i = 0x00; i <= 0x1F; i++) + invertmap[0x1F - i] = i; + // Init back colormap CON_SetupBackColormap(); } diff --git a/src/d_player.h b/src/d_player.h index 79f2a3b92..2e7afed88 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -52,6 +52,8 @@ typedef enum SF_NOSUPERSPRITES = 1<<16, // Don't use super sprites while super SF_NOSUPERJUMPBOOST = 1<<17, // Disable the jump boost given while super (i.e. Knuckles) SF_CANBUSTWALLS = 1<<18, // Can naturally bust walls on contact? (i.e. Knuckles) + SF_NOSHIELDABILITY = 1<<19, // Disable shield abilities + // free up to and including 1<<31 } skinflags_t; diff --git a/src/deh_tables.c b/src/deh_tables.c index b907e2206..3039bf7de 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -1522,6 +1522,13 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_SPINFIRE5", "S_SPINFIRE6", + "S_TEAM_SPINFIRE1", + "S_TEAM_SPINFIRE2", + "S_TEAM_SPINFIRE3", + "S_TEAM_SPINFIRE4", + "S_TEAM_SPINFIRE5", + "S_TEAM_SPINFIRE6", + // Spikes "S_SPIKE1", "S_SPIKE2", @@ -5015,6 +5022,7 @@ struct int_const_s const INT_CONST[] = { {"SF_NOSUPERSPRITES",SF_NOSUPERSPRITES}, {"SF_NOSUPERJUMPBOOST",SF_NOSUPERJUMPBOOST}, {"SF_CANBUSTWALLS",SF_CANBUSTWALLS}, + {"SF_NOSHIELDABILITY",SF_NOSHIELDABILITY}, // Dashmode constants {"DASHMODE_THRESHOLD",DASHMODE_THRESHOLD}, diff --git a/src/doomtype.h b/src/doomtype.h index 910063665..7dfee0720 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -381,6 +381,28 @@ Needed for some lua shenanigans. #define FIELDFROM( type, field, have, want ) \ (void *)((intptr_t)(field) - offsetof (type, have) + offsetof (type, want)) +typedef UINT8 bitarray_t; + +#define BIT_ARRAY_SIZE(n) (((n) + 7) >> 3) + +static inline int +in_bit_array (const bitarray_t * const array, const int value) +{ + return (array[value >> 3] & (1<<(value & 7))); +} + +static inline void +set_bit_array (bitarray_t * const array, const int value) +{ + array[value >> 3] |= (1<<(value & 7)); +} + +static inline void +unset_bit_array (bitarray_t * const array, const int value) +{ + array[value >> 3] &= ~(1<<(value & 7)); +} + #ifdef HAVE_SDL typedef UINT64 precise_t; #endif diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index b4fa7ec6c..43fdc89f0 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -108,7 +108,7 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm //Hurdler: 25/04/2000: now support colormap in hardware mode if (mipmap->colormap) - texel = mipmap->colormap[texel]; + texel = mipmap->colormap->data[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 ?) @@ -218,7 +218,7 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block, //Hurdler: 25/04/2000: now support colormap in hardware mode if (mipmap->colormap) - texel = mipmap->colormap[texel]; + texel = mipmap->colormap->data[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 ?) @@ -659,7 +659,10 @@ void HWR_FreeTextureColormaps(patch_t *patch) // Free image data from memory. if (next->data) Z_Free(next->data); + if (next->colormap) + Z_Free(next->colormap); next->data = NULL; + next->colormap = NULL; HWD.pfnDeleteTexture(next); // Free the old colormap mipmap from memory. @@ -667,16 +670,29 @@ void HWR_FreeTextureColormaps(patch_t *patch) } } +static boolean FreeTextureCallback(void *mem) +{ + patch_t *patch = (patch_t *)mem; + HWR_FreeTexture(patch); + return false; +} + +static boolean FreeColormapsCallback(void *mem) +{ + patch_t *patch = (patch_t *)mem; + HWR_FreeTextureColormaps(patch); + return false; +} + static void HWR_FreePatchCache(boolean freeall) { - INT32 i; + boolean (*callback)(void *mem) = FreeTextureCallback; - for (i = 0; i < numwadfiles; i++) - { - INT32 j = 0; - for (; j < wadfiles[i]->numlumps; j++) - (freeall ? HWR_FreeTexture : HWR_FreeTextureColormaps)(wadfiles[i]->patchcache[j]); - } + if (!freeall) + callback = FreeColormapsCallback; + + Z_IterateTags(PU_PATCH, PU_PATCH_ROTATED, callback); + Z_IterateTags(PU_SPRITE, PU_HUDGFX, callback); } // free all textures after each level @@ -977,8 +993,28 @@ static void HWR_LoadPatchMipmap(patch_t *patch, GLMipmap_t *grMipmap) Z_ChangeTag(grMipmap->data, PU_HWRCACHE_UNLOCKED); } +// ----------------------+ +// HWR_UpdatePatchMipmap : Updates a mipmap. +// ----------------------+ +static void HWR_UpdatePatchMipmap(patch_t *patch, GLMipmap_t *grMipmap) +{ + GLPatch_t *grPatch = patch->hardware; + HWR_MakePatch(patch, grPatch, grMipmap, true); + + // If hardware does not have the texture, then call pfnSetTexture to upload it + // If it does have the texture, then call pfnUpdateTexture to update it + if (!grMipmap->downloaded) + HWD.pfnSetTexture(grMipmap); + else + HWD.pfnUpdateTexture(grMipmap); + HWR_SetCurrentTexture(grMipmap); + + // The system-memory data can be purged now. + Z_ChangeTag(grMipmap->data, PU_HWRCACHE_UNLOCKED); +} + // -----------------+ -// HWR_GetPatch : Download a patch to the hardware cache and make it ready for use +// HWR_GetPatch : Downloads a patch to the hardware cache and make it ready for use // -----------------+ void HWR_GetPatch(patch_t *patch) { @@ -1006,14 +1042,20 @@ void HWR_GetMappedPatch(patch_t *patch, const UINT8 *colormap) return; } - // search for the mimmap + // search for the mipmap // skip the first (no colormap translated) for (grMipmap = grPatch->mipmap; grMipmap->nextcolormap; ) { grMipmap = grMipmap->nextcolormap; - if (grMipmap->colormap == colormap) + if (grMipmap->colormap && grMipmap->colormap->source == colormap) { - HWR_LoadPatchMipmap(patch, grMipmap); + if (memcmp(grMipmap->colormap->data, colormap, 256 * sizeof(UINT8))) + { + M_Memcpy(grMipmap->colormap->data, colormap, 256 * sizeof(UINT8)); + HWR_UpdatePatchMipmap(patch, grMipmap); + } + else + HWR_LoadPatchMipmap(patch, grMipmap); return; } } @@ -1029,7 +1071,10 @@ void HWR_GetMappedPatch(patch_t *patch, const UINT8 *colormap) I_Error("%s: Out of memory", "HWR_GetMappedPatch"); grMipmap->nextcolormap = newMipmap; - newMipmap->colormap = colormap; + newMipmap->colormap = Z_Calloc(sizeof(*newMipmap->colormap), PU_HWRPATCHCOLMIPMAP, NULL); + newMipmap->colormap->source = colormap; + M_Memcpy(newMipmap->colormap->data, colormap, 256 * sizeof(UINT8)); + HWR_LoadPatchMipmap(patch, newMipmap); } diff --git a/src/hardware/hw_data.h b/src/hardware/hw_data.h index 3ae4ef8bc..11e41b18a 100644 --- a/src/hardware/hw_data.h +++ b/src/hardware/hw_data.h @@ -39,6 +39,15 @@ typedef enum GLTextureFormat_e GL_TEXFMT_ALPHA_INTENSITY_88 = 0x22, } GLTextureFormat_t; +// Colormap structure for mipmaps. +struct GLColormap_s +{ + const UINT8 *source; + UINT8 data[256]; +}; +typedef struct GLColormap_s GLColormap_t; + + // data holds the address of the graphics data cached in heap memory // NULL if the texture is not in Doom heap cache. struct GLMipmap_s @@ -53,7 +62,7 @@ struct GLMipmap_s UINT32 downloaded; // The GPU has this texture. struct GLMipmap_s *nextcolormap; - const UINT8 *colormap; + struct GLColormap_s *colormap; struct GLMipmap_s *nextmipmap; // Linked list of all textures }; @@ -77,7 +86,7 @@ struct GLPatch_s { float max_s,max_t; GLMipmap_t *mipmap; -} ATTRPACK; +}; typedef struct GLPatch_s GLPatch_t; #endif //_HWR_DATA_ diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index 987d70c69..93c61f4e7 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -253,6 +253,7 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_SIGN &lspr[NOLIGHT], // SPR_SPIK &lspr[NOLIGHT], // SPR_SFLM + &lspr[NOLIGHT], // SPR_TFLM &lspr[NOLIGHT], // SPR_USPK &lspr[NOLIGHT], // SPR_WSPK &lspr[NOLIGHT], // SPR_WSPB diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index c5f63654b..a7e37d231 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5295,7 +5295,7 @@ static void HWR_ProjectSprite(mobj_t *thing) vis->colormap = R_GetTranslationColormap(TC_DEFAULT, vis->mobj->color ? vis->mobj->color : SKINCOLOR_CYAN, GTC_CACHE); } else - vis->colormap = colormaps; + vis->colormap = NULL; // set top/bottom coords vis->gzt = gzt; @@ -5396,7 +5396,7 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) vis->flip = flip; vis->mobj = (mobj_t *)thing; - vis->colormap = colormaps; + vis->colormap = NULL; // set top/bottom coords vis->gzt = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset); diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 9c786e67e..2e944d3e6 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1106,11 +1106,19 @@ static void HWR_GetBlendedTexture(patch_t *patch, patch_t *blendpatch, INT32 ski for (grMipmap = grPatch->mipmap; grMipmap->nextcolormap; ) { grMipmap = grMipmap->nextcolormap; - if (grMipmap->colormap == colormap) + if (grMipmap->colormap && grMipmap->colormap->source == colormap) { if (grMipmap->downloaded && grMipmap->data) { - HWD.pfnSetTexture(grMipmap); // found the colormap, set it to the correct texture + if (memcmp(grMipmap->colormap->data, colormap, 256 * sizeof(UINT8))) + { + M_Memcpy(grMipmap->colormap->data, colormap, 256 * sizeof(UINT8)); + HWR_CreateBlendedTexture(patch, blendpatch, grMipmap, skinnum, color); + HWD.pfnUpdateTexture(grMipmap); + } + else + HWD.pfnSetTexture(grMipmap); // found the colormap, set it to the correct texture + Z_ChangeTag(grMipmap->data, PU_HWRMODELTEXTURE_UNLOCKED); return; } @@ -1128,7 +1136,10 @@ static void HWR_GetBlendedTexture(patch_t *patch, patch_t *blendpatch, INT32 ski if (newMipmap == NULL) I_Error("%s: Out of memory", "HWR_GetBlendedTexture"); grMipmap->nextcolormap = newMipmap; - newMipmap->colormap = colormap; + + newMipmap->colormap = Z_Calloc(sizeof(*newMipmap->colormap), PU_HWRPATCHCOLMIPMAP, NULL); + newMipmap->colormap->source = colormap; + M_Memcpy(newMipmap->colormap->data, colormap, 256 * sizeof(UINT8)); HWR_CreateBlendedTexture(patch, blendpatch, newMipmap, skinnum, color); diff --git a/src/info.c b/src/info.c index 8cba61494..ee836a372 100644 --- a/src/info.c +++ b/src/info.c @@ -150,6 +150,7 @@ char sprnames[NUMSPRITES + 1][5] = "SIGN", // Level end sign "SPIK", // Spike Ball "SFLM", // Spin fire + "TFLM", // Spin fire (team) "USPK", // Floor spike "WSPK", // Wall spike "WSPB", // Wall spike base @@ -1894,6 +1895,13 @@ state_t states[NUMSTATES] = {SPR_SFLM, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_SPINFIRE6}, // S_SPINFIRE5 {SPR_SFLM, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_SPINFIRE1}, // S_SPINFIRE6 + {SPR_TFLM, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE2}, // S_TEAM_SPINFIRE1 + {SPR_TFLM, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE3}, // S_TEAM_SPINFIRE2 + {SPR_TFLM, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE4}, // S_TEAM_SPINFIRE3 + {SPR_TFLM, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE5}, // S_TEAM_SPINFIRE4 + {SPR_TFLM, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE6}, // S_TEAM_SPINFIRE5 + {SPR_TFLM, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE1}, // S_TEAM_SPINFIRE6 + // Floor Spike {SPR_USPK, 0,-1, {A_SpikeRetract}, 1, 0, S_SPIKE2}, // S_SPIKE1 -- Fully extended {SPR_USPK, 1, 2, {A_Pain}, 0, 0, S_SPIKE3}, // S_SPIKE2 @@ -3291,18 +3299,18 @@ state_t states[NUMSTATES] = {SPR_WZAP, FF_TRANS10|FF_ANIMATE|FF_RANDOMANIM, 4, {NULL}, 3, 2, S_NULL}, // S_WATERZAP // Spindash dust - {SPR_DUST, 0, 7, {NULL}, 0, 0, S_SPINDUST2}, // S_SPINDUST1 - {SPR_DUST, 1, 6, {NULL}, 0, 0, S_SPINDUST3}, // S_SPINDUST2 - {SPR_DUST, FF_TRANS30|2, 4, {NULL}, 0, 0, S_SPINDUST4}, // S_SPINDUST3 - {SPR_DUST, FF_TRANS60|3, 3, {NULL}, 0, 0, S_NULL}, // S_SPINDUST4 - {SPR_BUBL, 0, 7, {NULL}, 0, 0, S_SPINDUST_BUBBLE2}, // S_SPINDUST_BUBBLE1 - {SPR_BUBL, 0, 6, {NULL}, 0, 0, S_SPINDUST_BUBBLE3}, // S_SPINDUST_BUBBLE2 - {SPR_BUBL, FF_TRANS30|0, 4, {NULL}, 0, 0, S_SPINDUST_BUBBLE4}, // S_SPINDUST_BUBBLE3 - {SPR_BUBL, FF_TRANS60|0, 3, {NULL}, 0, 0, S_NULL}, // S_SPINDUST_BUBBLE4 - {SPR_FPRT, 0, 7, {NULL}, 0, 0, S_SPINDUST_FIRE2}, // S_SPINDUST_FIRE1 - {SPR_FPRT, 0, 6, {NULL}, 0, 0, S_SPINDUST_FIRE3}, // S_SPINDUST_FIRE2 - {SPR_FPRT, FF_TRANS30|0, 4, {NULL}, 0, 0, S_SPINDUST_FIRE4}, // S_SPINDUST_FIRE3 - {SPR_FPRT, FF_TRANS60|0, 3, {NULL}, 0, 0, S_NULL}, // S_SPINDUST_FIRE4 + {SPR_DUST, 0, 7, {NULL}, 0, 0, S_SPINDUST2}, // S_SPINDUST1 + {SPR_DUST, 1, 6, {NULL}, 0, 0, S_SPINDUST3}, // S_SPINDUST2 + {SPR_DUST, FF_TRANS30|2, 4, {NULL}, 0, 0, S_SPINDUST4}, // S_SPINDUST3 + {SPR_DUST, FF_TRANS60|3, 3, {NULL}, 0, 0, S_NULL}, // S_SPINDUST4 + {SPR_BUBL, 0, 7, {NULL}, 0, 0, S_SPINDUST_BUBBLE2}, // S_SPINDUST_BUBBLE1 + {SPR_BUBL, 0, 6, {NULL}, 0, 0, S_SPINDUST_BUBBLE3}, // S_SPINDUST_BUBBLE2 + {SPR_BUBL, FF_TRANS30|0, 4, {NULL}, 0, 0, S_SPINDUST_BUBBLE4}, // S_SPINDUST_BUBBLE3 + {SPR_BUBL, FF_TRANS60|0, 3, {NULL}, 0, 0, S_NULL}, // S_SPINDUST_BUBBLE4 + {SPR_FPRT, FF_FULLBRIGHT|0, 7, {NULL}, 0, 0, S_SPINDUST_FIRE2}, // S_SPINDUST_FIRE1 + {SPR_FPRT, FF_FULLBRIGHT|0, 6, {NULL}, 0, 0, S_SPINDUST_FIRE3}, // S_SPINDUST_FIRE2 + {SPR_FPRT, FF_FULLBRIGHT|FF_TRANS30|0, 4, {NULL}, 0, 0, S_SPINDUST_FIRE4}, // S_SPINDUST_FIRE3 + {SPR_FPRT, FF_FULLBRIGHT|FF_TRANS60|0, 3, {NULL}, 0, 0, S_NULL}, // S_SPINDUST_FIRE4 {SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50, 2, {NULL}, 0, 0, S_FOG2}, // S_FOG1 diff --git a/src/info.h b/src/info.h index c6a2a2c44..60e970246 100644 --- a/src/info.h +++ b/src/info.h @@ -684,6 +684,7 @@ typedef enum sprite SPR_SIGN, // Level end sign SPR_SPIK, // Spike Ball SPR_SFLM, // Spin fire + SPR_TFLM, // Spin fire (team) SPR_USPK, // Floor spike SPR_WSPK, // Wall spike SPR_WSPB, // Wall spike base @@ -2324,6 +2325,13 @@ typedef enum state S_SPINFIRE5, S_SPINFIRE6, + S_TEAM_SPINFIRE1, + S_TEAM_SPINFIRE2, + S_TEAM_SPINFIRE3, + S_TEAM_SPINFIRE4, + S_TEAM_SPINFIRE5, + S_TEAM_SPINFIRE6, + // Spikes S_SPIKE1, S_SPIKE2, diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 515f6f0ba..c5f847be6 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -155,6 +155,8 @@ static const struct { {META_PIVOTLIST, "spriteframepivot_t[]"}, {META_FRAMEPIVOT, "spriteframepivot_t"}, + {META_TAGLIST, "taglist"}, + {META_MOBJ, "mobj_t"}, {META_MAPTHING, "mapthing_t"}, @@ -186,6 +188,9 @@ static const struct { {META_CVAR, "consvar_t"}, {META_SECTORLINES, "sector_t.lines"}, +#ifdef MUTABLE_TAGS + {META_SECTORTAGLIST, "sector_t.taglist"}, +#endif {META_SIDENUM, "line_t.sidenum"}, {META_LINEARGS, "line_t.args"}, {META_LINESTRINGARGS, "line_t.stringargs"}, diff --git a/src/lua_libs.h b/src/lua_libs.h index 54ac89bcc..fbe8d4878 100644 --- a/src/lua_libs.h +++ b/src/lua_libs.h @@ -12,6 +12,8 @@ extern lua_State *gL; +#define MUTABLE_TAGS + #define LREG_VALID "VALID_USERDATA" #define LREG_EXTVARS "LUA_VARS" #define LREG_STATEACTION "STATE_ACTION" @@ -27,6 +29,8 @@ extern lua_State *gL; #define META_PIVOTLIST "SPRITEFRAMEPIVOT_T[]" #define META_FRAMEPIVOT "SPRITEFRAMEPIVOT_T*" +#define META_TAGLIST "TAGLIST" + #define META_MOBJ "MOBJ_T*" #define META_MAPTHING "MAPTHING_T*" @@ -58,6 +62,9 @@ extern lua_State *gL; #define META_CVAR "CONSVAR_T*" #define META_SECTORLINES "SECTOR_T*LINES" +#ifdef MUTABLE_TAGS +#define META_SECTORTAGLIST "sector_t.taglist" +#endif #define META_SIDENUM "LINE_T*SIDENUM" #define META_LINEARGS "LINE_T*ARGS" #define META_LINESTRINGARGS "LINE_T*STRINGARGS" @@ -95,6 +102,7 @@ int LUA_PlayerLib(lua_State *L); int LUA_SkinLib(lua_State *L); int LUA_ThinkerLib(lua_State *L); int LUA_MapLib(lua_State *L); +int LUA_TagLib(lua_State *L); int LUA_PolyObjLib(lua_State *L); int LUA_BlockmapLib(lua_State *L); int LUA_HudLib(lua_State *L); diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 83744c74d..6a9091cc9 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -37,6 +37,7 @@ enum sector_e { sector_lightlevel, sector_special, sector_tag, + sector_taglist, sector_thinglist, sector_heightsec, sector_camsec, @@ -55,6 +56,7 @@ static const char *const sector_opt[] = { "lightlevel", "special", "tag", + "taglist", "thinglist", "heightsec", "camsec", @@ -89,6 +91,7 @@ enum line_e { line_flags, line_special, line_tag, + line_taglist, line_args, line_stringargs, line_sidenum, @@ -113,6 +116,7 @@ static const char *const line_opt[] = { "flags", "special", "tag", + "taglist", "args", "stringargs", "sidenum", @@ -581,6 +585,9 @@ static int sector_get(lua_State *L) case sector_tag: lua_pushinteger(L, Tag_FGet(§or->tags)); return 1; + case sector_taglist: + LUA_PushUserdata(L, §or->tags, META_SECTORTAGLIST); + return 1; case sector_thinglist: // thinglist lua_pushcfunction(L, lib_iterateSectorThinglist); LUA_PushUserdata(L, sector->thinglist, META_MOBJ); @@ -682,6 +689,8 @@ static int sector_set(lua_State *L) case sector_tag: Tag_SectorFSet((UINT32)(sector - sectors), (INT16)luaL_checkinteger(L, 3)); break; + case sector_taglist: + return LUA_ErrSetDirectly(L, "sector_t", "taglist"); } return 0; } @@ -821,6 +830,9 @@ static int line_get(lua_State *L) case line_tag: lua_pushinteger(L, Tag_FGet(&line->tags)); return 1; + case line_taglist: + LUA_PushUserdata(L, &line->tags, META_TAGLIST); + return 1; case line_args: LUA_PushUserdata(L, line->args, META_LINEARGS); return 1; @@ -1385,25 +1397,15 @@ static int lib_iterateSectors(lua_State *L) static int lib_getSector(lua_State *L) { - int field; INLEVEL - lua_settop(L, 2); - lua_remove(L, 1); // dummy userdata table is unused. - if (lua_isnumber(L, 1)) + if (lua_isnumber(L, 2)) { - size_t i = lua_tointeger(L, 1); + size_t i = lua_tointeger(L, 2); if (i >= numsectors) return 0; LUA_PushUserdata(L, §ors[i], META_SECTOR); return 1; } - field = luaL_checkoption(L, 1, NULL, array_opt); - switch(field) - { - case 0: // iterate - lua_pushcfunction(L, lib_iterateSectors); - return 1; - } return 0; } @@ -1489,25 +1491,15 @@ static int lib_iterateLines(lua_State *L) static int lib_getLine(lua_State *L) { - int field; INLEVEL - lua_settop(L, 2); - lua_remove(L, 1); // dummy userdata table is unused. - if (lua_isnumber(L, 1)) + if (lua_isnumber(L, 2)) { - size_t i = lua_tointeger(L, 1); + size_t i = lua_tointeger(L, 2); if (i >= numlines) return 0; LUA_PushUserdata(L, &lines[i], META_LINE); return 1; } - field = luaL_checkoption(L, 1, NULL, array_opt); - switch(field) - { - case 0: // iterate - lua_pushcfunction(L, lib_iterateLines); - return 1; - } return 0; } @@ -2360,15 +2352,13 @@ int LUA_MapLib(lua_State *L) //lua_setfield(L, -2, "__len"); lua_pop(L, 1); - lua_newuserdata(L, 0); - lua_createtable(L, 0, 2); - lua_pushcfunction(L, lib_getSector); - lua_setfield(L, -2, "__index"); - - lua_pushcfunction(L, lib_numsectors); - lua_setfield(L, -2, "__len"); - lua_setmetatable(L, -2); - lua_setglobal(L, "sectors"); + LUA_PushTaggableObjectArray(L, "sectors", + lib_iterateSectors, + lib_getSector, + lib_numsectors, + tags_sectors, + &numsectors, §ors, + sizeof (sector_t), META_SECTOR); lua_newuserdata(L, 0); lua_createtable(L, 0, 2); @@ -2380,15 +2370,13 @@ int LUA_MapLib(lua_State *L) lua_setmetatable(L, -2); lua_setglobal(L, "subsectors"); - lua_newuserdata(L, 0); - lua_createtable(L, 0, 2); - lua_pushcfunction(L, lib_getLine); - lua_setfield(L, -2, "__index"); - - lua_pushcfunction(L, lib_numlines); - lua_setfield(L, -2, "__len"); - lua_setmetatable(L, -2); - lua_setglobal(L, "lines"); + LUA_PushTaggableObjectArray(L, "lines", + lib_iterateLines, + lib_getLine, + lib_numlines, + tags_lines, + &numlines, &lines, + sizeof (line_t), META_LINE); lua_newuserdata(L, 0); lua_createtable(L, 0, 2); diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 7aae18c90..65adceb15 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -22,8 +22,6 @@ #include "lua_hud.h" // hud_running errors #include "lua_hook.h" // hook_cmd_running errors -static const char *const array_opt[] ={"iterate",NULL}; - enum mobj_e { mobj_valid = 0, mobj_x, @@ -904,6 +902,11 @@ static int mapthing_get(lua_State *L) number = mt->extrainfo; else if(fastcmp(field,"tag")) number = Tag_FGet(&mt->tags); + else if(fastcmp(field,"taglist")) + { + LUA_PushUserdata(L, &mt->tags, META_TAGLIST); + return 1; + } else if(fastcmp(field,"args")) { LUA_PushUserdata(L, mt->args, META_THINGARGS); @@ -966,6 +969,8 @@ static int mapthing_set(lua_State *L) } else if (fastcmp(field,"tag")) Tag_FSet(&mt->tags, (INT16)luaL_checkinteger(L, 3)); + else if (fastcmp(field,"taglist")) + return LUA_ErrSetDirectly(L, "mapthing_t", "taglist"); else if(fastcmp(field,"mobj")) mt->mobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); else @@ -1003,25 +1008,15 @@ static int lib_iterateMapthings(lua_State *L) static int lib_getMapthing(lua_State *L) { - int field; INLEVEL - lua_settop(L, 2); - lua_remove(L, 1); // dummy userdata table is unused. - if (lua_isnumber(L, 1)) + if (lua_isnumber(L, 2)) { - size_t i = lua_tointeger(L, 1); + size_t i = lua_tointeger(L, 2); if (i >= nummapthings) return 0; LUA_PushUserdata(L, &mapthings[i], META_MAPTHING); return 1; } - field = luaL_checkoption(L, 1, NULL, array_opt); - switch(field) - { - case 0: // iterate - lua_pushcfunction(L, lib_iterateMapthings); - return 1; - } return 0; } @@ -1068,14 +1063,13 @@ int LUA_MobjLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L,1); - lua_newuserdata(L, 0); - lua_createtable(L, 0, 2); - lua_pushcfunction(L, lib_getMapthing); - lua_setfield(L, -2, "__index"); + LUA_PushTaggableObjectArray(L, "mapthings", + lib_iterateMapthings, + lib_getMapthing, + lib_nummapthings, + tags_mapthings, + &nummapthings, &mapthings, + sizeof (mapthing_t), META_MAPTHING); - lua_pushcfunction(L, lib_nummapthings); - lua_setfield(L, -2, "__len"); - lua_setmetatable(L, -2); - lua_setglobal(L, "mapthings"); return 0; } diff --git a/src/lua_script.c b/src/lua_script.c index a649942b8..310995de3 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -53,6 +53,7 @@ static lua_CFunction liblist[] = { LUA_SkinLib, // skin_t, skins[] LUA_ThinkerLib, // thinker_t LUA_MapLib, // line_t, side_t, sector_t, subsector_t + LUA_TagLib, // tags LUA_PolyObjLib, // polyobj_t LUA_BlockmapLib, // blockmap stuff LUA_HudLib, // HUD stuff @@ -739,25 +740,37 @@ void LUA_PushLightUserdata (lua_State *L, void *data, const char *meta) // Pushes it to the stack and stores it in the registry. void LUA_PushUserdata(lua_State *L, void *data, const char *meta) { + if (LUA_RawPushUserdata(L, data) == LPUSHED_NEW) + { + luaL_getmetatable(L, meta); + lua_setmetatable(L, -2); + } +} + +// Same as LUA_PushUserdata but don't set a metatable yet. +lpushed_t LUA_RawPushUserdata(lua_State *L, void *data) +{ + lpushed_t status = LPUSHED_NIL; + void **userdata; if (!data) { // push a NULL lua_pushnil(L); - return; + return status; } lua_getfield(L, LUA_REGISTRYINDEX, LREG_VALID); I_Assert(lua_istable(L, -1)); + lua_pushlightuserdata(L, data); lua_rawget(L, -2); + if (lua_isnil(L, -1)) { // no userdata? deary me, we'll have to make one. lua_pop(L, 1); // pop the nil // create the userdata userdata = lua_newuserdata(L, sizeof(void *)); *userdata = data; - luaL_getmetatable(L, meta); - lua_setmetatable(L, -2); // Set it in the registry so we can find it again lua_pushlightuserdata(L, data); // k (store the userdata via the data's pointer) @@ -765,8 +778,15 @@ void LUA_PushUserdata(lua_State *L, void *data, const char *meta) lua_rawset(L, -4); // stack is left with the userdata on top, as if getting it had originally succeeded. + + status = LPUSHED_NEW; } + else + status = LPUSHED_EXISTING; + lua_remove(L, -2); // remove LREG_VALID + + return status; } // When userdata is freed, use this function to remove it from Lua. @@ -826,6 +846,7 @@ void LUA_InvalidateLevel(void) { LUA_InvalidateUserdata(§ors[i]); LUA_InvalidateUserdata(§ors[i].lines); + LUA_InvalidateUserdata(§ors[i].tags); if (sectors[i].ffloors) { for (rover = sectors[i].ffloors; rover; rover = rover->next) @@ -835,6 +856,7 @@ void LUA_InvalidateLevel(void) for (i = 0; i < numlines; i++) { LUA_InvalidateUserdata(&lines[i]); + LUA_InvalidateUserdata(&lines[i].tags); LUA_InvalidateUserdata(lines[i].sidenum); } for (i = 0; i < numsides; i++) @@ -866,7 +888,10 @@ void LUA_InvalidateMapthings(void) return; for (i = 0; i < nummapthings; i++) + { LUA_InvalidateUserdata(&mapthings[i]); + LUA_InvalidateUserdata(&mapthings[i].tags); + } } void LUA_InvalidatePlayer(player_t *player) @@ -1681,3 +1706,36 @@ int Lua_optoption(lua_State *L, int narg, return i; return -1; } + +void LUA_PushTaggableObjectArray +( lua_State *L, + const char *field, + lua_CFunction iterator, + lua_CFunction indexer, + lua_CFunction counter, + taggroup_t *garray[], + size_t * max_elements, + void * element_array, + size_t sizeof_element, + const char *meta) +{ + lua_newuserdata(L, 0); + lua_createtable(L, 0, 2); + lua_createtable(L, 0, 2); + lua_pushcfunction(L, iterator); + lua_setfield(L, -2, "iterate"); + + LUA_InsertTaggroupIterator(L, garray, + max_elements, element_array, sizeof_element, meta); + + lua_createtable(L, 0, 1); + lua_pushcfunction(L, indexer); + lua_setfield(L, -2, "__index"); + lua_setmetatable(L, -2); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, counter); + lua_setfield(L, -2, "__len"); + lua_setmetatable(L, -2); + lua_setglobal(L, field); +} diff --git a/src/lua_script.h b/src/lua_script.h index e9104f3d5..3bb692f22 100644 --- a/src/lua_script.h +++ b/src/lua_script.h @@ -10,10 +10,14 @@ /// \file lua_script.h /// \brief Lua scripting basics +#ifndef LUA_SCRIPT_H +#define LUA_SCRIPT_H + #include "m_fixed.h" #include "doomtype.h" #include "d_player.h" #include "g_state.h" +#include "taglist.h" #include "blua/lua.h" #include "blua/lualib.h" @@ -46,12 +50,6 @@ void LUA_LoadLump(UINT16 wad, UINT16 lump, boolean noresults); void LUA_DumpFile(const char *filename); #endif fixed_t LUA_EvalMath(const char *word); -void LUA_PushLightUserdata(lua_State *L, void *data, const char *meta); -void LUA_PushUserdata(lua_State *L, void *data, const char *meta); -void LUA_InvalidateUserdata(void *data); -void LUA_InvalidateLevel(void); -void LUA_InvalidateMapthings(void); -void LUA_InvalidatePlayer(player_t *player); void LUA_Step(void); void LUA_Archive(void); void LUA_UnArchive(void); @@ -63,11 +61,49 @@ int Lua_optoption(lua_State *L, int narg, const char *def, const char *const lst[]); void LUA_HookNetArchive(lua_CFunction archFunc); +void LUA_PushTaggableObjectArray +( lua_State *L, + const char *field, + lua_CFunction iterator, + lua_CFunction indexer, + lua_CFunction counter, + taggroup_t *garray[], + size_t * max_elements, + void * element_array, + size_t sizeof_element, + const char *meta); + +void LUA_InsertTaggroupIterator +( lua_State *L, + taggroup_t *garray[], + size_t * max_elements, + void * element_array, + size_t sizeof_element, + const char * meta); + +typedef enum { + LPUSHED_NIL, + LPUSHED_NEW, + LPUSHED_EXISTING, +} lpushed_t; + +void LUA_PushLightUserdata(lua_State *L, void *data, const char *meta); +void LUA_PushUserdata(lua_State *L, void *data, const char *meta); +lpushed_t LUA_RawPushUserdata(lua_State *L, void *data); + +void LUA_InvalidateUserdata(void *data); + +void LUA_InvalidateLevel(void); +void LUA_InvalidateMapthings(void); +void LUA_InvalidatePlayer(player_t *player); + // Console wrapper void COM_Lua_f(void); #define LUA_ErrInvalid(L, type) luaL_error(L, "accessed " type " doesn't exist anymore, please check 'valid' before using " type "."); +#define LUA_ErrSetDirectly(L, type, field) luaL_error(L, type " field " LUA_QL(field) " cannot be set directly.") + // Deprecation warnings // Shows once upon use. Then doesn't show again. #define LUA_Deprecated(L,this_func,use_instead)\ @@ -98,3 +134,5 @@ void COM_Lua_f(void); #define INLEVEL if (! ISINLEVEL)\ return luaL_error(L, "This can only be used in a level!"); + +#endif/*LUA_SCRIPT_H*/ diff --git a/src/lua_taglib.c b/src/lua_taglib.c new file mode 100644 index 000000000..c9f320fe8 --- /dev/null +++ b/src/lua_taglib.c @@ -0,0 +1,451 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2020 by James R. +// Copyright (C) 2020 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file lua_taglib.c +/// \brief tag list iterator for Lua scripting + +#include "doomdef.h" +#include "taglist.h" +#include "r_state.h" + +#include "lua_script.h" +#include "lua_libs.h" + +#ifdef MUTABLE_TAGS +#include "z_zone.h" +#endif + +static int tag_iterator(lua_State *L) +{ + INT32 tag = lua_isnil(L, 2) ? -1 : lua_tonumber(L, 2); + do + { + if (++tag >= MAXTAGS) + return 0; + } + while (! in_bit_array(tags_available, tag)) ; + lua_pushnumber(L, tag); + return 1; +} + +enum { +#define UPVALUE lua_upvalueindex + up_garray = UPVALUE(1), + up_max_elements = UPVALUE(2), + up_element_array = UPVALUE(3), + up_sizeof_element = UPVALUE(4), + up_meta = UPVALUE(5), +#undef UPVALUE +}; + +static INT32 next_element(lua_State *L, const mtag_t tag, const size_t p) +{ + taggroup_t ** garray = lua_touserdata(L, up_garray); + const size_t * max_elements = lua_touserdata(L, up_max_elements); + return Taggroup_Iterate(garray, *max_elements, tag, p); +} + +static void push_element(lua_State *L, void *element) +{ + if (LUA_RawPushUserdata(L, element) == LPUSHED_NEW) + { + lua_pushvalue(L, up_meta); + lua_setmetatable(L, -2); + } +} + +static void push_next_element(lua_State *L, const INT32 element) +{ + char * element_array = *(char **)lua_touserdata(L, up_element_array); + const size_t sizeof_element = lua_tonumber(L, up_sizeof_element); + push_element(L, &element_array[element * sizeof_element]); +} + +struct element_iterator_state { + mtag_t tag; + size_t p; +}; + +static int element_iterator(lua_State *L) +{ + struct element_iterator_state * state = lua_touserdata(L, 1); + if (lua_isnoneornil(L, 3)) + state->p = 0; + lua_pushnumber(L, ++state->p); + lua_gettable(L, 1); + return 1; +} + +static int lib_iterateTags(lua_State *L) +{ + if (lua_gettop(L) < 2) + { + lua_pushcfunction(L, tag_iterator); + return 1; + } + else + return tag_iterator(L); +} + +static int lib_numTags(lua_State *L) +{ + lua_pushnumber(L, num_tags); + return 1; +} + +static int lib_getTaggroup(lua_State *L) +{ + struct element_iterator_state *state; + + mtag_t tag; + + if (lua_gettop(L) > 1) + return luaL_error(L, "too many arguments"); + + if (lua_isnoneornil(L, 1)) + { + tag = MTAG_GLOBAL; + } + else + { + tag = lua_tonumber(L, 1); + luaL_argcheck(L, tag >= -1, 1, "tag out of range"); + } + + state = lua_newuserdata(L, sizeof *state); + state->tag = tag; + state->p = 0; + + lua_pushvalue(L, lua_upvalueindex(1)); + lua_setmetatable(L, -2); + + return 1; +} + +static int lib_getTaggroupElement(lua_State *L) +{ + const size_t p = luaL_checknumber(L, 2) - 1; + const mtag_t tag = *(mtag_t *)lua_touserdata(L, 1); + const INT32 element = next_element(L, tag, p); + + if (element == -1) + return 0; + else + { + push_next_element(L, element); + return 1; + } +} + +static int lib_numTaggroupElements(lua_State *L) +{ + const mtag_t tag = *(mtag_t *)lua_touserdata(L, 1); + if (tag == MTAG_GLOBAL) + lua_pushnumber(L, *(size_t *)lua_touserdata(L, up_max_elements)); + else + { + const taggroup_t ** garray = lua_touserdata(L, up_garray); + lua_pushnumber(L, Taggroup_Count(garray[tag])); + } + return 1; +} + +#ifdef MUTABLE_TAGS +static int meta_ref[2]; +#endif + +static int has_valid_field(lua_State *L) +{ + int equal; + lua_rawgeti(L, LUA_ENVIRONINDEX, 1); + equal = lua_rawequal(L, 2, -1); + lua_pop(L, 1); + return equal; +} + +static taglist_t * valid_taglist(lua_State *L, int idx, boolean getting) +{ + taglist_t *list = *(taglist_t **)lua_touserdata(L, idx); + + if (list == NULL) + { + if (getting && has_valid_field(L)) + lua_pushboolean(L, 0); + else + LUA_ErrInvalid(L, "taglist");/* doesn't actually return */ + return NULL; + } + else + return list; +} + +static taglist_t * check_taglist(lua_State *L, int idx) +{ + if (lua_isuserdata(L, idx) && lua_getmetatable(L, idx)) + { + lua_getref(L, meta_ref[0]); + lua_getref(L, meta_ref[1]); + + if (lua_rawequal(L, -3, -2) || lua_rawequal(L, -3, -1)) + { + lua_pop(L, 3); + return valid_taglist(L, idx, false); + } + } + + return luaL_argerror(L, idx, "must be a tag list"), NULL; +} + +static int taglist_get(lua_State *L) +{ + const taglist_t *list = valid_taglist(L, 1, true); + + if (list == NULL)/* valid check */ + return 1; + + if (lua_isnumber(L, 2)) + { + const size_t i = lua_tonumber(L, 2); + + if (list && i <= list->count) + { + lua_pushnumber(L, list->tags[i - 1]); + return 1; + } + else + return 0; + } + else if (has_valid_field(L)) + { + lua_pushboolean(L, 1); + return 1; + } + else + { + lua_getmetatable(L, 1); + lua_replace(L, 1); + lua_rawget(L, 1); + return 1; + } +} + +static int taglist_len(lua_State *L) +{ + const taglist_t *list = valid_taglist(L, 1, false); + lua_pushnumber(L, list->count); + return 1; +} + +static int taglist_equal(lua_State *L) +{ + const taglist_t *lhs = check_taglist(L, 1); + const taglist_t *rhs = check_taglist(L, 2); + lua_pushboolean(L, Tag_Compare(lhs, rhs)); + return 1; +} + +static int taglist_iterator(lua_State *L) +{ + const taglist_t *list = valid_taglist(L, 1, false); + const size_t i = 1 + lua_tonumber(L, lua_upvalueindex(1)); + if (i <= list->count) + { + lua_pushnumber(L, list->tags[i - 1]); + /* watch me exploit an upvalue as a control because + I want to use the control as the value */ + lua_pushnumber(L, i); + lua_replace(L, lua_upvalueindex(1)); + return 1; + } + else + return 0; +} + +static int taglist_iterate(lua_State *L) +{ + check_taglist(L, 1); + lua_pushnumber(L, 0); + lua_pushcclosure(L, taglist_iterator, 1); + lua_pushvalue(L, 1); + return 2; +} + +static int taglist_find(lua_State *L) +{ + const taglist_t *list = check_taglist(L, 1); + const mtag_t tag = luaL_checknumber(L, 2); + lua_pushboolean(L, Tag_Find(list, tag)); + return 1; +} + +static int taglist_shares(lua_State *L) +{ + const taglist_t *lhs = check_taglist(L, 1); + const taglist_t *rhs = check_taglist(L, 2); + lua_pushboolean(L, Tag_Share(lhs, rhs)); + return 1; +} + +/* only sector tags are mutable... */ + +#ifdef MUTABLE_TAGS +static size_t sector_of_taglist(taglist_t *list) +{ + return (sector_t *)((char *)list - offsetof (sector_t, tags)) - sectors; +} + +static int this_taglist(lua_State *L) +{ + lua_settop(L, 1); + return 1; +} + +static int taglist_add(lua_State *L) +{ + taglist_t *list = *(taglist_t **)luaL_checkudata(L, 1, META_SECTORTAGLIST); + const mtag_t tag = luaL_checknumber(L, 2); + + if (! Tag_Find(list, tag)) + { + Taggroup_Add(tags_sectors, tag, sector_of_taglist(list)); + Tag_Add(list, tag); + } + + return this_taglist(L); +} + +static int taglist_remove(lua_State *L) +{ + taglist_t *list = *(taglist_t **)luaL_checkudata(L, 1, META_SECTORTAGLIST); + const mtag_t tag = luaL_checknumber(L, 2); + + size_t i; + + for (i = 0; i < list->count; ++i) + { + if (list->tags[i] == tag) + { + if (list->count > 1) + { + memmove(&list->tags[i], &list->tags[i + 1], + (list->count - 1 - i) * sizeof (mtag_t)); + list->tags = Z_Realloc(list->tags, + (--list->count) * sizeof (mtag_t), PU_LEVEL, NULL); + Taggroup_Remove(tags_sectors, tag, sector_of_taglist(list)); + } + else/* reset to default tag */ + Tag_SectorFSet(sector_of_taglist(list), 0); + break; + } + } + + return this_taglist(L); +} +#endif/*MUTABLE_TAGS*/ + +void LUA_InsertTaggroupIterator +( lua_State *L, + taggroup_t *garray[], + size_t * max_elements, + void * element_array, + size_t sizeof_element, + const char * meta) +{ + lua_createtable(L, 0, 3); + lua_pushlightuserdata(L, garray); + lua_pushlightuserdata(L, max_elements); + + lua_pushvalue(L, -2); + lua_pushvalue(L, -2); + lua_pushlightuserdata(L, element_array); + lua_pushnumber(L, sizeof_element); + luaL_getmetatable(L, meta); + lua_pushcclosure(L, lib_getTaggroupElement, 5); + lua_setfield(L, -4, "__index"); + + lua_pushcclosure(L, lib_numTaggroupElements, 2); + lua_setfield(L, -2, "__len"); + + lua_pushcfunction(L, element_iterator); + lua_setfield(L, -2, "__call"); + lua_pushcclosure(L, lib_getTaggroup, 1); + lua_setfield(L, -2, "tagged"); +} + +static luaL_Reg taglist_lib[] = { + {"iterate", taglist_iterate}, + {"find", taglist_find}, + {"shares", taglist_shares}, +#ifdef MUTABLE_TAGS + {"add", taglist_add}, + {"remove", taglist_remove}, +#endif + {0} +}; + +static void open_taglist(lua_State *L) +{ + luaL_register(L, "taglist", taglist_lib); + + lua_getfield(L, -1, "find"); + lua_setfield(L, -2, "has"); +} + +#define new_literal(L, s) \ + (lua_pushliteral(L, s), luaL_ref(L, -2)) + +#ifdef MUTABLE_TAGS +static int +#else +static void +#endif +set_taglist_metatable(lua_State *L, const char *meta) +{ + luaL_newmetatable(L, meta); + lua_pushcfunction(L, taglist_get); + lua_createtable(L, 0, 1); + new_literal(L, "valid"); + lua_setfenv(L, -2); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, taglist_len); + lua_setfield(L, -2, "__len"); + + lua_pushcfunction(L, taglist_equal); + lua_setfield(L, -2, "__eq"); +#ifdef MUTABLE_TAGS + return luaL_ref(L, LUA_REGISTRYINDEX); +#endif +} + +int LUA_TagLib(lua_State *L) +{ + lua_newuserdata(L, 0); + lua_createtable(L, 0, 2); + lua_createtable(L, 0, 1); + lua_pushcfunction(L, lib_iterateTags); + lua_setfield(L, -2, "iterate"); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, lib_numTags); + lua_setfield(L, -2, "__len"); + lua_setmetatable(L, -2); + lua_setglobal(L, "tags"); + + open_taglist(L); + +#ifdef MUTABLE_TAGS + meta_ref[0] = set_taglist_metatable(L, META_TAGLIST); + meta_ref[1] = set_taglist_metatable(L, META_SECTORTAGLIST); +#else + set_taglist_metatable(L, META_TAGLIST); +#endif + + return 0; +} diff --git a/src/m_menu.c b/src/m_menu.c index 783c74852..73f6d9685 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -8421,7 +8421,7 @@ static void M_DrawLoadGameData(void) sprdef = &charbotskin->sprites[SPR2_SIGN]; if (!sprdef->numframes) goto skipbot; - colormap = R_GetTranslationColormap(savegameinfo[savetodraw].botskin-1, charbotskin->prefcolor, 0); + colormap = R_GetTranslationColormap(savegameinfo[savetodraw].botskin-1, charbotskin->prefcolor, GTC_CACHE); sprframe = &sprdef->spriteframes[0]; patch = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH); @@ -8431,8 +8431,6 @@ static void M_DrawLoadGameData(void) charbotskin->highresscale, 0, patch, colormap); - Z_Free(colormap); - tempx -= (20<sprites[SPR2_SIGN]; - colormap = R_GetTranslationColormap(savegameinfo[savetodraw].skinnum, charskin->prefcolor, 0); + colormap = R_GetTranslationColormap(savegameinfo[savetodraw].skinnum, charskin->prefcolor, GTC_CACHE); if (!sprdef->numframes) goto skipsign; sprframe = &sprdef->spriteframes[0]; @@ -8481,8 +8479,6 @@ skipsign: charskin->highresscale/2, 0, patch, colormap); skiplife: - if (colormap) - Z_Free(colormap); patch = W_CachePatchName("STLIVEX", PU_PATCH); @@ -11753,7 +11749,7 @@ static void M_DrawSetupMultiPlayerMenu(void) goto faildraw; // ok, draw player sprite for sure now - colormap = R_GetTranslationColormap(setupm_fakeskin, setupm_fakecolor->color, 0); + colormap = R_GetTranslationColormap(setupm_fakeskin, setupm_fakecolor->color, GTC_CACHE); if (multi_frame >= sprdef->numframes) multi_frame = 0; @@ -11771,7 +11767,6 @@ static void M_DrawSetupMultiPlayerMenu(void) FixedDiv(skins[setupm_fakeskin].highresscale, skins[setupm_fakeskin].shieldscale), flags, patch, colormap); - Z_Free(colormap); goto colordraw; faildraw: diff --git a/src/p_local.h b/src/p_local.h index 8caab0d27..9359290fa 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -279,6 +279,7 @@ mobjtype_t P_GetMobjtype(UINT16 mthingtype); void P_RespawnSpecials(void); mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type); +void P_SetMobjSpawnDefaults(mobj_t *mobj); void P_RecalcPrecipInSector(sector_t *sector); void P_PrecipitationEffects(void); diff --git a/src/p_mobj.c b/src/p_mobj.c index d8e129690..26ceb5a82 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9837,7 +9837,7 @@ static void P_FlagFuseThink(mobj_t *mobj) 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); + CONS_Printf(M_GetText("The \205Red flag\200 has returned to base.\n")); // Assumedly in splitscreen players will be on opposing teams if (players[consoleplayer].ctfteam == 1 || splitscreen) @@ -9850,7 +9850,7 @@ static void P_FlagFuseThink(mobj_t *mobj) 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); + CONS_Printf(M_GetText("The \204Blue flag\200 has returned to base.\n")); // Assumedly in splitscreen players will be on opposing teams if (players[consoleplayer].ctfteam == 2 || splitscreen) @@ -10440,52 +10440,12 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) mobj->x = x; mobj->y = y; - mobj->radius = info->radius; - mobj->height = info->height; - mobj->flags = info->flags; - - mobj->health = (info->spawnhealth ? info->spawnhealth : 1); - - mobj->reactiontime = info->reactiontime; - - mobj->lastlook = -1; // stuff moved in P_enemy.P_LookForPlayer - - // do not set the state with P_SetMobjState, - // because action routines can not be called yet - st = &states[info->spawnstate]; - - mobj->state = st; - mobj->tics = st->tics; - mobj->sprite = st->sprite; - mobj->frame = st->frame; // FF_FRAMEMASK for frame, and other bits.. - P_SetupStateAnimation(mobj, st); - - mobj->friction = ORIG_FRICTION; - - mobj->movefactor = FRACUNIT; - - // All mobjs are created at 100% scale. - mobj->scale = FRACUNIT; - mobj->destscale = mobj->scale; - mobj->scalespeed = FRACUNIT/12; - - // TODO: Make this a special map header - if ((maptol & TOL_ERZ3) && !(mobj->type == MT_BLACKEGGMAN)) - mobj->destscale = FRACUNIT/2; - - // Sprite rendering - mobj->blendmode = AST_TRANSLUCENT; - mobj->spritexscale = mobj->spriteyscale = mobj->scale; - mobj->spritexoffset = mobj->spriteyoffset = 0; - mobj->floorspriteslope = NULL; + P_SetMobjSpawnDefaults(mobj); // set subsector and/or block links P_SetThingPosition(mobj); I_Assert(mobj->subsector != NULL); - // Make sure scale matches destscale immediately when spawned - P_SetScale(mobj, mobj->destscale); - mobj->floorz = P_GetSectorFloorZAt (mobj->subsector->sector, x, y); mobj->ceilingz = P_GetSectorCeilingZAt(mobj->subsector->sector, x, y); @@ -10787,6 +10747,8 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) mobj->frame &= ~FF_FRAMEMASK; } + st = &states[info->spawnstate]; + // Call action functions when the state is set if (st->action.acp1 && (mobj->flags & MF_RUNSPAWNFUNC)) { @@ -10817,6 +10779,52 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) return mobj; } +void P_SetMobjSpawnDefaults(mobj_t *mobj) +{ + const mobjinfo_t *info = mobj->info; + state_t *st = &states[info->spawnstate]; + + mobj->radius = info->radius; + mobj->height = info->height; + mobj->flags = info->flags; + + mobj->health = (info->spawnhealth ? info->spawnhealth : 1); + + mobj->reactiontime = info->reactiontime; + + mobj->lastlook = -1; // stuff moved in P_enemy.P_LookForPlayer + + // do not set the state with P_SetMobjState, + // because action routines can not be called yet + mobj->state = st; + mobj->tics = st->tics; + mobj->sprite = st->sprite; + mobj->frame = st->frame; // FF_FRAMEMASK for frame, and other bits.. + P_SetupStateAnimation(mobj, st); + + mobj->friction = ORIG_FRICTION; + + mobj->movefactor = FRACUNIT; + + // All mobjs are created at 100% scale. + mobj->scale = FRACUNIT; + mobj->destscale = mobj->scale; + mobj->scalespeed = FRACUNIT/12; + + // TODO: Make this a special map header + if ((maptol & TOL_ERZ3) && !(mobj->type == MT_BLACKEGGMAN)) + mobj->destscale = FRACUNIT/2; + + // Make sure scale matches destscale immediately when spawned + P_SetScale(mobj, mobj->destscale); + + // Sprite rendering + mobj->blendmode = AST_TRANSLUCENT; + mobj->spritexscale = mobj->spriteyscale = FRACUNIT; + mobj->spritexoffset = mobj->spriteyoffset = 0; + mobj->floorspriteslope = NULL; +} + static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) { state_t *st; @@ -11798,7 +11806,7 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i) if (!(G_CoopGametype() || (mthing->options & MTF_EXTRA))) return false; // she doesn't hang out here - if (!mariomode && !(netgame || multiplayer) && players[consoleplayer].skin == 3) + if (!(netgame || multiplayer) && players[consoleplayer].skin == 3) return false; // no doubles break; diff --git a/src/p_saveg.c b/src/p_saveg.c index adedea049..c1364e08f 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -1506,7 +1506,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) { const mobj_t *mobj = (const mobj_t *)th; UINT32 diff; - UINT16 diff2; + UINT32 diff2; // Ignore stationary hoops - these will be respawned from mapthings. if (mobj->type == MT_HOOP) @@ -1638,7 +1638,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) diff2 |= MD2_SHADOWSCALE; if (mobj->renderflags) diff2 |= MD2_RENDERFLAGS; - if (mobj->renderflags) + if (mobj->blendmode != AST_TRANSLUCENT) diff2 |= MD2_BLENDMODE; if (mobj->spritexscale != FRACUNIT) diff2 |= MD2_SPRITEXSCALE; @@ -1646,6 +1646,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) diff2 |= MD2_SPRITEYSCALE; if (mobj->spritexoffset) diff2 |= MD2_SPRITEXOFFSET; + if (mobj->spriteyoffset) + diff2 |= MD2_SPRITEYOFFSET; if (mobj->floorspriteslope) { pslope_t *slope = mobj->floorspriteslope; @@ -1667,7 +1669,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) WRITEUINT8(save_p, type); WRITEUINT32(save_p, diff); if (diff & MD_MORE) - WRITEUINT16(save_p, diff2); + WRITEUINT32(save_p, diff2); // save pointer, at load time we will search this pointer to reinitilize pointers WRITEUINT32(save_p, (size_t)mobj); @@ -2615,14 +2617,14 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) thinker_t *next; mobj_t *mobj; UINT32 diff; - UINT16 diff2; + UINT32 diff2; INT32 i; fixed_t z, floorz, ceilingz; ffloor_t *floorrover = NULL, *ceilingrover = NULL; diff = READUINT32(save_p); if (diff & MD_MORE) - diff2 = READUINT16(save_p); + diff2 = READUINT32(save_p); else diff2 = 0; @@ -2690,7 +2692,10 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) } mobj->type = i; } + mobj->info = &mobjinfo[mobj->type]; + P_SetMobjSpawnDefaults(mobj); + if (diff & MD_POS) { mobj->x = READFIXED(save_p); @@ -2716,35 +2721,21 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) if (diff & MD_RADIUS) mobj->radius = READFIXED(save_p); - else - mobj->radius = mobj->info->radius; if (diff & MD_HEIGHT) mobj->height = READFIXED(save_p); - else - mobj->height = mobj->info->height; if (diff & MD_FLAGS) mobj->flags = READUINT32(save_p); - else - mobj->flags = mobj->info->flags; if (diff & MD_FLAGS2) mobj->flags2 = READUINT32(save_p); if (diff & MD_HEALTH) mobj->health = READINT32(save_p); - else - mobj->health = mobj->info->spawnhealth; if (diff & MD_RTIME) mobj->reactiontime = READINT32(save_p); - else - mobj->reactiontime = mobj->info->reactiontime; if (diff & MD_STATE) mobj->state = &states[READUINT16(save_p)]; - else - mobj->state = &states[mobj->info->spawnstate]; if (diff & MD_TICS) mobj->tics = READINT32(save_p); - else - mobj->tics = mobj->state->tics; if (diff & MD_SPRITE) { mobj->sprite = READUINT16(save_p); if (mobj->sprite == SPR_PLAY) @@ -2760,11 +2751,6 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) mobj->frame = READUINT32(save_p); mobj->anim_duration = READUINT16(save_p); } - else - { - mobj->frame = mobj->state->frame; - mobj->anim_duration = (UINT16)mobj->state->var2; - } if (diff & MD_EFLAGS) mobj->eflags = READUINT16(save_p); if (diff & MD_PLAYER) @@ -2781,20 +2767,14 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) mobj->threshold = READINT32(save_p); if (diff & MD_LASTLOOK) mobj->lastlook = READINT32(save_p); - else - mobj->lastlook = -1; if (diff & MD_TARGET) mobj->target = (mobj_t *)(size_t)READUINT32(save_p); if (diff & MD_TRACER) mobj->tracer = (mobj_t *)(size_t)READUINT32(save_p); if (diff & MD_FRICTION) mobj->friction = READFIXED(save_p); - else - mobj->friction = ORIG_FRICTION; if (diff & MD_MOVEFACTOR) mobj->movefactor = READFIXED(save_p); - else - mobj->movefactor = FRACUNIT; if (diff & MD_FUSE) mobj->fuse = READINT32(save_p); if (diff & MD_WATERTOP) @@ -2803,16 +2783,10 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) mobj->waterbottom = READFIXED(save_p); if (diff & MD_SCALE) mobj->scale = READFIXED(save_p); - else - mobj->scale = FRACUNIT; if (diff & MD_DSCALE) mobj->destscale = READFIXED(save_p); - else - mobj->destscale = mobj->scale; if (diff2 & MD2_SCALESPEED) mobj->scalespeed = READFIXED(save_p); - else - mobj->scalespeed = FRACUNIT/12; if (diff2 & MD2_CUSVAL) mobj->cusval = READINT32(save_p); if (diff2 & MD2_CVMEM) diff --git a/src/p_setup.c b/src/p_setup.c index 0ab43a8bc..4229f547a 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3171,7 +3171,7 @@ static void P_ConvertBinaryMap(void) switch (mapthings[i].type) { case 750: - Tag_Add(&mapthings[i].tags, mapthings[i].angle); + Tag_FSet(&mapthings[i].tags, mapthings[i].angle); break; case 760: case 761: diff --git a/src/p_spec.c b/src/p_spec.c index 9a4467468..008a794a9 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -4304,7 +4304,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers if (leveltime % (TICRATE/2) == 0 && player->rings > 0) { player->rings--; - S_StartSound(player->mo, sfx_itemup); + S_StartSound(player->mo, sfx_antiri); } break; case 11: // Special Stage Damage @@ -4604,7 +4604,7 @@ DoneSection2: HU_SetCEchoFlags(V_AUTOFADEOUT|V_ALLOWLOWERCASE); HU_SetCEchoDuration(5); - HU_DoCEcho(va(M_GetText("%s%s%s\\CAPTURED THE %sBLUE FLAG%s.\\\\\\\\"), "\x85", player_names[player-players], "\x80", "\x84", "\x80")); + HU_DoCEcho(va(M_GetText("\205%s\200\\CAPTURED THE \204BLUE FLAG\200.\\\\\\\\"), player_names[player-players])); if (splitscreen || players[consoleplayer].ctfteam == 1) S_StartSound(NULL, sfx_flgcap); @@ -4637,7 +4637,7 @@ DoneSection2: HU_SetCEchoFlags(V_AUTOFADEOUT|V_ALLOWLOWERCASE); HU_SetCEchoDuration(5); - HU_DoCEcho(va(M_GetText("%s%s%s\\CAPTURED THE %sRED FLAG%s.\\\\\\\\"), "\x84", player_names[player-players], "\x80", "\x85", "\x80")); + HU_DoCEcho(va(M_GetText("\204%s\200\\CAPTURED THE \205RED FLAG\200.\\\\\\\\"), player_names[player-players])); if (splitscreen || players[consoleplayer].ctfteam == 2) S_StartSound(NULL, sfx_flgcap); @@ -4827,6 +4827,8 @@ DoneSection2: if (player->laps >= (UINT8)cv_numlaps.value) CONS_Printf(M_GetText("%s has finished the race.\n"), player_names[player-players]); + else if (player->laps == (UINT8)cv_numlaps.value-1) + CONS_Printf(M_GetText("%s started the \205final lap\200!\n"), player_names[player-players]); else CONS_Printf(M_GetText("%s started lap %u\n"), player_names[player-players], (UINT32)player->laps+1); diff --git a/src/p_user.c b/src/p_user.c index cccc1cbea..6ab74869d 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -5024,7 +5024,7 @@ static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lock if ((player->powers[pw_shield] & SH_NOSTACK) && !player->powers[pw_super] && !(player->pflags & PF_SPINDOWN) && ((!(player->pflags & PF_THOKKED) || (((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP || (player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT) && player->secondjump == UINT8_MAX) ))) // thokked is optional if you're bubblewrapped / 3dblasted { - if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT) + if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT && !(player->charflags & SF_NOSHIELDABILITY)) { if ((lockonshield = P_LookForEnemies(player, false, false))) { @@ -5047,7 +5047,7 @@ static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lock } } } - if (cmd->buttons & BT_SPIN && !LUA_HookPlayer(player, HOOK(ShieldSpecial))) // Spin button effects + if ((!(player->charflags & SF_NOSHIELDABILITY)) && (cmd->buttons & BT_SPIN && !LUA_HookPlayer(player, HOOK(ShieldSpecial)))) // Spin button effects { // Force stop if ((player->powers[pw_shield] & ~(SH_FORCEHP|SH_STACK)) == SH_FORCE) @@ -5495,7 +5495,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) break; } } - else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_WHIRLWIND && !player->powers[pw_super]) + else if ((!(player->charflags & SF_NOSHIELDABILITY)) && ((player->powers[pw_shield] & SH_NOSTACK) == SH_WHIRLWIND && !player->powers[pw_super] && !LUA_HookPlayer(player, HOOK(ShieldSpecial)))) P_DoJumpShield(player); } @@ -7756,6 +7756,11 @@ void P_ElementalFire(player_t *player, boolean cropcircle) flame->eflags = (flame->eflags & ~MFE_VERTICALFLIP)|(player->mo->eflags & MFE_VERTICALFLIP); P_InstaThrust(flame, flame->angle, FixedMul(3*FRACUNIT, flame->scale)); P_SetObjectMomZ(flame, 3*FRACUNIT, false); + if (!(gametyperules & GTR_FRIENDLY)) + { + P_SetMobjState(flame, S_TEAM_SPINFIRE1); + flame->color = player->mo->color; + } } #undef limitangle #undef numangles @@ -7783,6 +7788,11 @@ void P_ElementalFire(player_t *player, boolean cropcircle) flame->destscale = player->mo->scale; P_SetScale(flame, player->mo->scale); flame->eflags = (flame->eflags & ~MFE_VERTICALFLIP)|(player->mo->eflags & MFE_VERTICALFLIP); + if (!(gametyperules & GTR_FRIENDLY)) + { + P_SetMobjState(flame, S_TEAM_SPINFIRE1); + flame->color = player->mo->color; + } flame->momx = 8; // this is a hack which is used to ensure it still behaves as a missile and can damage others P_XYMovement(flame); diff --git a/src/r_picformats.c b/src/r_picformats.c index 02f1de4ab..f87362c76 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -544,21 +544,22 @@ void *Picture_GetPatchPixel( UINT16 *s16 = NULL; UINT32 *s32 = NULL; softwarepatch_t *doompatch = (softwarepatch_t *)patch; + boolean isdoompatch = Picture_IsDoomPatchFormat(informat); INT16 width; if (patch == NULL) I_Error("Picture_GetPatchPixel: patch == NULL"); - width = (Picture_IsDoomPatchFormat(informat) ? patch->width : SHORT(patch->width)); + width = (isdoompatch ? SHORT(doompatch->width) : patch->width); if (x >= 0 && x < width) { INT32 colx = (flags & PICFLAGS_XFLIP) ? (width-1)-x : x; INT32 topdelta, prevdelta = -1; - INT32 colofs = (Picture_IsDoomPatchFormat(informat) ? LONG(patch->columnofs[colx]) : patch->columnofs[colx]); + INT32 colofs = (isdoompatch ? LONG(doompatch->columnofs[colx]) : patch->columnofs[colx]); - // Column offsets are pointers so no casting required - if (Picture_IsDoomPatchFormat(informat)) + // Column offsets are pointers, so no casting is required. + if (isdoompatch) column = (column_t *)((UINT8 *)doompatch + colofs); else column = (column_t *)((UINT8 *)patch->columns + colofs); diff --git a/src/r_plane.c b/src/r_plane.c index c54b32382..45d635213 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -607,6 +607,7 @@ void R_MakeSpans(INT32 x, INT32 t1, INT32 b1, INT32 t2, INT32 b2) void R_DrawPlanes(void) { visplane_t *pl; + angle_t va = viewangle; INT32 i; R_UpdatePlaneRipple(); @@ -621,6 +622,8 @@ void R_DrawPlanes(void) R_DrawSinglePlane(pl); } } + + viewangle = va; } // R_DrawSkyPlane @@ -705,9 +708,9 @@ void R_CalculateSlopeVectors(pslope_t *slope, fixed_t planeviewx, fixed_t planev n.z = -xscale * cos(ang); ang = ANG2RAD(planeangle); - temp = P_GetSlopeZAt(slope, planeviewx + yscale * FLOAT_TO_FIXED(sin(ang)), planeviewy + yscale * FLOAT_TO_FIXED(cos(ang))); + temp = P_GetSlopeZAt(slope, planeviewx + FLOAT_TO_FIXED(yscale * sin(ang)), planeviewy + FLOAT_TO_FIXED(yscale * cos(ang))); m.y = FIXED_TO_FLOAT(temp) - zeroheight; - temp = P_GetSlopeZAt(slope, planeviewx + xscale * FLOAT_TO_FIXED(cos(ang)), planeviewy - xscale * FLOAT_TO_FIXED(sin(ang))); + temp = P_GetSlopeZAt(slope, planeviewx + FLOAT_TO_FIXED(xscale * cos(ang)), planeviewy - FLOAT_TO_FIXED(xscale * sin(ang))); n.y = FIXED_TO_FLOAT(temp) - zeroheight; if (ds_powersoftwo) @@ -788,7 +791,6 @@ void R_DrawSinglePlane(visplane_t *pl) ffloor_t *rover; int type; int spanfunctype = BASEDRAWFUNC; - angle_t viewang = viewangle; if (!(pl->minx <= pl->maxx)) return; @@ -1153,8 +1155,6 @@ using the palette colors. } } #endif - - viewangle = viewang; } void R_PlaneBounds(visplane_t *plane) diff --git a/src/r_skins.c b/src/r_skins.c index 522d9236a..6f150f234 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -514,6 +514,7 @@ static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value) GETFLAG(NOSUPERSPRITES) GETFLAG(NOSUPERJUMPBOOST) GETFLAG(CANBUSTWALLS) + GETFLAG(NOSHIELDABILITY) #undef GETFLAG else // let's check if it's a sound, otherwise error out diff --git a/src/r_textures.c b/src/r_textures.c index 9de9649e2..a006d739f 100644 --- a/src/r_textures.c +++ b/src/r_textures.c @@ -604,7 +604,7 @@ void *R_GetLevelFlat(levelflat_t *levelflat) levelflat->height = ds_flatheight = SHORT(patch->height); levelflat->picture = Z_Malloc(levelflat->width * levelflat->height, PU_LEVEL, NULL); - converted = Picture_FlatConvert(PICFMT_DOOMPATCH, patch, PICFMT_FLAT, 0, &size, levelflat->width, levelflat->height, patch->topoffset, patch->leftoffset, 0); + converted = Picture_FlatConvert(PICFMT_DOOMPATCH, patch, PICFMT_FLAT, 0, &size, levelflat->width, levelflat->height, SHORT(patch->topoffset), SHORT(patch->leftoffset), 0); M_Memcpy(levelflat->picture, converted, size); Z_Free(converted); } diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index c64164caa..5cae48077 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -1298,6 +1298,10 @@ boolean I_PlaySong(boolean looping) if (gme) { gme_equalizer_t eq = {GME_TREBLE, GME_BASS, 0,0,0,0,0,0,0,0}; +#if GME_VERSION >= 0x000603 + if (looping) + gme_set_autoload_playback_limit(gme, 0); +#endif gme_set_equalizer(gme, &eq); gme_start_track(gme, 0); current_track = 0; diff --git a/src/taglist.c b/src/taglist.c index b11216b6c..a759f4d02 100644 --- a/src/taglist.c +++ b/src/taglist.c @@ -15,6 +15,11 @@ #include "z_zone.h" #include "r_data.h" +// Bit array of whether a tag exists for sectors/lines/things. +bitarray_t tags_available[BIT_ARRAY_SIZE (MAXTAGS)]; + +size_t num_tags; + // Taggroups are used to list elements of the same tag, for iteration. // Since elements can now have multiple tags, it means an element may appear // in several taggroups at the same time. These are built on level load. @@ -105,6 +110,39 @@ size_t Taggroup_Find (const taggroup_t *group, const size_t id) return -1; } +/// group->count, but also checks for NULL +size_t Taggroup_Count (const taggroup_t *group) +{ + return group ? group->count : 0; +} + +/// Iterate thru elements in a global taggroup. +INT32 Taggroup_Iterate +( taggroup_t *garray[], + const size_t max_elements, + const mtag_t tag, + const size_t p) +{ + const taggroup_t *group; + + if (tag == MTAG_GLOBAL) + { + if (p < max_elements) + return p; + return -1; + } + + group = garray[(UINT16)tag]; + + if (group) + { + if (p < group->count) + return group->elements[p]; + return -1; + } + return -1; +} + /// Add an element to a global taggroup. void Taggroup_Add (taggroup_t *garray[], const mtag_t tag, size_t id) { @@ -120,6 +158,12 @@ void Taggroup_Add (taggroup_t *garray[], const mtag_t tag, size_t id) if (Taggroup_Find(group, id) != (size_t)-1) return; + if (! in_bit_array(tags_available, tag)) + { + num_tags++; + set_bit_array(tags_available, tag); + } + // Create group if empty. if (!group) { @@ -133,25 +177,34 @@ void Taggroup_Add (taggroup_t *garray[], const mtag_t tag, size_t id) for (i = 0; i < group->count; i++) if (group->elements[i] > id) break; - - group->elements = Z_Realloc(group->elements, (group->count + 1) * sizeof(size_t), PU_LEVEL, NULL); - - // Offset existing elements to make room for the new one. - if (i < group->count) - memmove(&group->elements[i + 1], &group->elements[i], group->count - i); } + group->elements = Z_Realloc(group->elements, (group->count + 1) * sizeof(size_t), PU_LEVEL, NULL); + + // Offset existing elements to make room for the new one. + if (i < group->count) + memmove(&group->elements[i + 1], &group->elements[i], group->count - i); + group->count++; - group->elements = Z_Realloc(group->elements, group->count * sizeof(size_t), PU_LEVEL, NULL); group->elements[i] = id; } +static size_t total_elements_with_tag (const mtag_t tag) +{ + return + ( + Taggroup_Count(tags_sectors[tag]) + + Taggroup_Count(tags_lines[tag]) + + Taggroup_Count(tags_mapthings[tag]) + ); +} + /// Remove an element from a global taggroup. void Taggroup_Remove (taggroup_t *garray[], const mtag_t tag, size_t id) { taggroup_t *group; size_t rempos; - size_t newcount; + size_t oldcount; if (tag == MTAG_GLOBAL) return; @@ -161,8 +214,14 @@ void Taggroup_Remove (taggroup_t *garray[], const mtag_t tag, size_t id) if ((rempos = Taggroup_Find(group, id)) == (size_t)-1) return; + if (group->count == 1 && total_elements_with_tag(tag) == 1) + { + num_tags--; + unset_bit_array(tags_available, tag); + } + // Strip away taggroup if no elements left. - if (!(newcount = --group->count)) + if (!(oldcount = group->count--)) { Z_Free(group->elements); Z_Free(group); @@ -170,19 +229,18 @@ void Taggroup_Remove (taggroup_t *garray[], const mtag_t tag, size_t id) } else { - size_t *newelements = Z_Malloc(newcount * sizeof(size_t), PU_LEVEL, NULL); + size_t *newelements = Z_Malloc(group->count * sizeof(size_t), PU_LEVEL, NULL); size_t i; // Copy the previous entries save for the one to remove. for (i = 0; i < rempos; i++) newelements[i] = group->elements[i]; - for (i = rempos + 1; i < group->count; i++) + for (i = rempos + 1; i < oldcount; i++) newelements[i - 1] = group->elements[i]; Z_Free(group->elements); group->elements = newelements; - group->count = newcount; } } @@ -209,6 +267,9 @@ void Taglist_InitGlobalTables(void) { size_t i, j; + memset(tags_available, 0, sizeof tags_available); + num_tags = 0; + for (i = 0; i < MAXTAGS; i++) { tags_sectors[i] = NULL; @@ -236,56 +297,17 @@ void Taglist_InitGlobalTables(void) INT32 Tag_Iterate_Sectors (const mtag_t tag, const size_t p) { - if (tag == MTAG_GLOBAL) - { - if (p < numsectors) - return p; - return -1; - } - - if (tags_sectors[(UINT16)tag]) - { - if (p < tags_sectors[(UINT16)tag]->count) - return tags_sectors[(UINT16)tag]->elements[p]; - return -1; - } - return -1; + return Taggroup_Iterate(tags_sectors, numsectors, tag, p); } INT32 Tag_Iterate_Lines (const mtag_t tag, const size_t p) { - if (tag == MTAG_GLOBAL) - { - if (p < numlines) - return p; - return -1; - } - - if (tags_lines[(UINT16)tag]) - { - if (p < tags_lines[(UINT16)tag]->count) - return tags_lines[(UINT16)tag]->elements[p]; - return -1; - } - return -1; + return Taggroup_Iterate(tags_lines, numlines, tag, p); } INT32 Tag_Iterate_Things (const mtag_t tag, const size_t p) { - if (tag == MTAG_GLOBAL) - { - if (p < nummapthings) - return p; - return -1; - } - - if (tags_mapthings[(UINT16)tag]) - { - if (p < tags_mapthings[(UINT16)tag]->count) - return tags_mapthings[(UINT16)tag]->elements[p]; - return -1; - } - return -1; + return Taggroup_Iterate(tags_mapthings, nummapthings, tag, p); } INT32 Tag_FindLineSpecial(const INT16 special, const mtag_t tag) diff --git a/src/taglist.h b/src/taglist.h index 0e6d9f842..a0529ab6b 100644 --- a/src/taglist.h +++ b/src/taglist.h @@ -43,6 +43,10 @@ typedef struct size_t count; } taggroup_t; +extern bitarray_t tags_available[]; + +extern size_t num_tags; + extern taggroup_t* tags_sectors[]; extern taggroup_t* tags_lines[]; extern taggroup_t* tags_mapthings[]; @@ -50,6 +54,13 @@ extern taggroup_t* tags_mapthings[]; void Taggroup_Add (taggroup_t *garray[], const mtag_t tag, size_t id); void Taggroup_Remove (taggroup_t *garray[], const mtag_t tag, size_t id); size_t Taggroup_Find (const taggroup_t *group, const size_t id); +size_t Taggroup_Count (const taggroup_t *group); + +INT32 Taggroup_Iterate +( taggroup_t *garray[], + const size_t max_elements, + const mtag_t tag, + const size_t p); void Taglist_InitGlobalTables(void); diff --git a/src/w_wad.c b/src/w_wad.c index 4aae2ee46..6566800c0 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -1747,6 +1747,9 @@ void *W_CachePatchNum(lumpnum_t lumpnum, INT32 tag) void W_UnlockCachedPatch(void *patch) { + if (!patch) + return; + // The hardware code does its own memory management, as its patches // have different lifetimes from software's. #ifdef HWRENDER diff --git a/src/y_inter.c b/src/y_inter.c index 5930d35ec..384fbc194 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1229,7 +1229,10 @@ void Y_StartIntermission(void) data.coop.tics = players[consoleplayer].realtime; for (i = 0; i < 4; ++i) - data.coop.bonuspatches[i] = W_CachePatchName(data.coop.bonuses[i].patch, PU_PATCH); + { + if (strlen(data.coop.bonuses[i].patch)) + data.coop.bonuspatches[i] = W_CachePatchName(data.coop.bonuses[i].patch, PU_PATCH); + } data.coop.ptotal = W_CachePatchName("YB_TOTAL", PU_PATCH); // get act number @@ -1733,7 +1736,6 @@ static void Y_SetNullBonus(player_t *player, y_bonus_t *bstruct) { (void)player; memset(bstruct, 0, sizeof(y_bonus_t)); - strncpy(bstruct->patch, "MISSING", sizeof(bstruct->patch)); } // diff --git a/src/z_zone.c b/src/z_zone.c index ad64a3a07..d7da17e51 100644 --- a/src/z_zone.c +++ b/src/z_zone.c @@ -813,12 +813,12 @@ static void Command_Memfree_f(void) #ifdef HWRENDER if (rendermode == render_opengl) { - CONS_Printf(M_GetText("Patch info headers: %7s KB\n"), sizeu1(Z_TagUsage(PU_HWRPATCHINFO)>>10)); - CONS_Printf(M_GetText("Mipmap patches : %7s KB\n"), sizeu1(Z_TagUsage(PU_HWRPATCHCOLMIPMAP)>>10)); - CONS_Printf(M_GetText("HW Texture cache : %7s KB\n"), sizeu1(Z_TagUsage(PU_HWRCACHE)>>10)); - CONS_Printf(M_GetText("Plane polygons : %7s KB\n"), sizeu1(Z_TagUsage(PU_HWRPLANE)>>10)); - CONS_Printf(M_GetText("HW model textures : %7s KB\n"), sizeu1(Z_TagUsage(PU_HWRMODELTEXTURE)>>10)); - CONS_Printf(M_GetText("HW Texture used : %7d KB\n"), HWR_GetTextureUsed()>>10); + CONS_Printf(M_GetText("Patch info headers : %7s KB\n"), sizeu1(Z_TagUsage(PU_HWRPATCHINFO)>>10)); + CONS_Printf(M_GetText("Cached textures : %7s KB\n"), sizeu1(Z_TagUsage(PU_HWRCACHE)>>10)); + CONS_Printf(M_GetText("Texture colormaps : %7s KB\n"), sizeu1(Z_TagUsage(PU_HWRPATCHCOLMIPMAP)>>10)); + CONS_Printf(M_GetText("Model textures : %7s KB\n"), sizeu1(Z_TagUsage(PU_HWRMODELTEXTURE)>>10)); + CONS_Printf(M_GetText("Plane polygons : %7s KB\n"), sizeu1(Z_TagUsage(PU_HWRPLANE)>>10)); + CONS_Printf(M_GetText("All GPU textures : %7d KB\n"), HWR_GetTextureUsed()>>10); } #endif