Merge branch 'next' into hwr-texture-cache-refactor

This commit is contained in:
Jaime Ita Passos 2020-12-19 13:54:31 -03:00
commit 4c813e7b7f
18 changed files with 830 additions and 230 deletions

View file

@ -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

View file

@ -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

View file

@ -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();
}

View file

@ -379,6 +379,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

View file

@ -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"},

View file

@ -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);

View file

@ -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(&sector->tags));
return 1;
case sector_taglist:
LUA_PushUserdata(L, &sector->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, &sectors[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, &sectors,
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);

View file

@ -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;
}

View file

@ -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(&sectors[i]);
LUA_InvalidateUserdata(&sectors[i].lines);
LUA_InvalidateUserdata(&sectors[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);
}

View file

@ -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 LUAh_NetArchiveHook(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*/

451
src/lua_taglib.c Normal file
View file

@ -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;
}

View file

@ -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);

View file

@ -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;

View file

@ -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)

View file

@ -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:

View file

@ -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)

View file

@ -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)

View file

@ -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);