diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a1f752ed7..124a89b09 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -169,6 +169,7 @@ set(SRB2_CORE_GAME_SOURCES p_telept.c p_tick.c p_user.c + taglist.c p_local.h p_maputl.h @@ -180,6 +181,7 @@ set(SRB2_CORE_GAME_SOURCES p_slopes.h p_spec.h p_tick.h + taglist.h ) if(NOT (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) diff --git a/src/Makefile b/src/Makefile index da918e205..2cd6d5f6b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -522,6 +522,7 @@ OBJS:=$(i_main_o) \ $(OBJDIR)/r_picformats.o \ $(OBJDIR)/r_portal.o \ $(OBJDIR)/screen.o \ + $(OBJDIR)/taglist.o \ $(OBJDIR)/v_video.o \ $(OBJDIR)/s_sound.o \ $(OBJDIR)/sounds.o \ diff --git a/src/doomdata.h b/src/doomdata.h index f3890c846..b3f7f5c4d 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -23,6 +23,7 @@ // Some global defines, that configure the game. #include "doomdef.h" +#include "taglist.h" #include "m_fixed.h" // See the mapthing_t scale. // @@ -208,11 +209,10 @@ typedef struct UINT16 options; INT16 z; UINT8 extrainfo; + taglist_t tags; fixed_t scale; - INT16 tag; INT32 args[NUMMAPTHINGARGS]; char *stringargs[NUMMAPTHINGSTRINGARGS]; - struct mobj_s *mobj; } mapthing_t; diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index bd977ed15..a0fd3e9f7 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -1608,7 +1608,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom //Hurdler: 3d-floors test - if (gl_frontsector && gl_backsector && gl_frontsector->tag != gl_backsector->tag && (gl_backsector->ffloors || gl_frontsector->ffloors)) + if (gl_frontsector && gl_backsector && !Tag_Compare(&gl_frontsector->tags, &gl_backsector->tags) && (gl_backsector->ffloors || gl_frontsector->ffloors)) { ffloor_t * rover; fixed_t highcut = 0, lowcut = 0; @@ -1625,6 +1625,18 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom { for (rover = gl_backsector->ffloors; rover; rover = rover->next) { + boolean bothsides = false; + // Skip if it exists on both sectors. + ffloor_t * r2; + for (r2 = gl_frontsector->ffloors; r2; r2 = r2->next) + if (rover->master == r2->master) + { + bothsides = true; + break; + } + + if (bothsides) continue; + if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERSIDES)) continue; if (!(rover->flags & FF_ALLSIDES) && rover->flags & FF_INVERTSIDES) @@ -1759,6 +1771,18 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom { for (rover = gl_frontsector->ffloors; rover; rover = rover->next) { + boolean bothsides = false; + // Skip if it exists on both sectors. + ffloor_t * r2; + for (r2 = gl_backsector->ffloors; r2; r2 = r2->next) + if (rover->master == r2->master) + { + bothsides = true; + break; + } + + if (bothsides) continue; + if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERSIDES)) continue; if (!(rover->flags & FF_ALLSIDES || rover->flags & FF_INVERTSIDES)) @@ -2384,7 +2408,7 @@ static void HWR_AddLine(seg_t * line) if (!line->polyseg && !line->sidedef->midtexture && ((!gl_frontsector->ffloors && !gl_backsector->ffloors) - || (gl_frontsector->tag == gl_backsector->tag))) + || Tag_Compare(&gl_frontsector->tags, &gl_backsector->tags))) return; // line is empty, don't even bother // treat like wide open window instead HWR_ProcessSeg(); // Doesn't need arguments because they're defined globally :D @@ -2423,7 +2447,7 @@ static void HWR_AddLine(seg_t * line) if (!line->polyseg && !line->sidedef->midtexture && ((!gl_frontsector->ffloors && !gl_backsector->ffloors) - || (gl_frontsector->tag == gl_backsector->tag))) + || Tag_Compare(&gl_frontsector->tags, &gl_backsector->tags))) return; // line is empty, don't even bother goto clippass; // treat like wide open window instead diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 739c8aeb7..157d4fe37 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -32,6 +32,7 @@ #include "lua_script.h" #include "lua_libs.h" #include "lua_hud.h" // hud_running errors +#include "taglist.h" // P_FindSpecialLineFromTag #include "lua_hook.h" // hook_cmd_running errors #define NOHUD if (hud_running)\ diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 5f6dbc4d6..95cc8c101 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -99,8 +99,6 @@ enum line_e { line_slopetype, line_frontsector, line_backsector, - line_firsttag, - line_nexttag, line_polyobj, line_text, line_callcount @@ -125,8 +123,6 @@ static const char *const line_opt[] = { "slopetype", "frontsector", "backsector", - "firsttag", - "nexttag", "polyobj", "text", "callcount", @@ -583,7 +579,7 @@ static int sector_get(lua_State *L) lua_pushinteger(L, sector->special); return 1; case sector_tag: - lua_pushinteger(L, sector->tag); + lua_pushinteger(L, Tag_FGet(§or->tags)); return 1; case sector_thinglist: // thinglist lua_pushcfunction(L, lib_iterateSectorThinglist); @@ -684,7 +680,7 @@ static int sector_set(lua_State *L) sector->special = (INT16)luaL_checkinteger(L, 3); break; case sector_tag: - P_ChangeSectorTag((UINT32)(sector - sectors), (INT16)luaL_checkinteger(L, 3)); + Tag_SectorFSet((UINT32)(sector - sectors), (INT16)luaL_checkinteger(L, 3)); break; } return 0; @@ -823,7 +819,7 @@ static int line_get(lua_State *L) lua_pushinteger(L, line->special); return 1; case line_tag: - lua_pushinteger(L, line->tag); + lua_pushinteger(L, Tag_FGet(&line->tags)); return 1; case line_args: LUA_PushUserdata(L, line->args, META_LINEARGS); @@ -871,12 +867,6 @@ static int line_get(lua_State *L) case line_backsector: LUA_PushUserdata(L, line->backsector, META_SECTOR); return 1; - case line_firsttag: - lua_pushinteger(L, line->firsttag); - return 1; - case line_nexttag: - lua_pushinteger(L, line->nexttag); - return 1; case line_polyobj: LUA_PushUserdata(L, line->polyobj, META_POLYOBJ); return 1; diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index a1a3e96c9..824e9df6b 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -848,7 +848,7 @@ static int mapthing_get(lua_State *L) else if(fastcmp(field,"extrainfo")) number = mt->extrainfo; else if(fastcmp(field,"tag")) - number = mt->tag; + number = Tag_FGet(&mt->tags); else if(fastcmp(field,"args")) { LUA_PushUserdata(L, mt->args, META_THINGARGS); @@ -910,7 +910,7 @@ static int mapthing_set(lua_State *L) mt->extrainfo = (UINT8)extrainfo; } else if (fastcmp(field,"tag")) - mt->tag = (INT16)luaL_checkinteger(L, 3); + Tag_FSet(&mt->tags, (INT16)luaL_checkinteger(L, 3)); else if(fastcmp(field,"mobj")) mt->mobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); else diff --git a/src/m_cheat.c b/src/m_cheat.c index 365bcee8c..6e0fb8c5c 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -1108,7 +1108,6 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c mt->options = (mt->z << ZSHIFT) | (UINT16)cv_opflags.value; mt->scale = player->mo->scale; - mt->tag = 0; memset(mt->args, 0, NUMMAPTHINGARGS*sizeof(*mt->args)); memset(mt->stringargs, 0x00, NUMMAPTHINGSTRINGARGS*sizeof(*mt->stringargs)); mt->pitch = mt->roll = 0; diff --git a/src/p_ceilng.c b/src/p_ceilng.c index 3c3c507cd..f12499d5c 100644 --- a/src/p_ceilng.c +++ b/src/p_ceilng.c @@ -394,8 +394,10 @@ INT32 EV_DoCeiling(line_t *line, ceiling_e type) INT32 secnum = -1; sector_t *sec; ceiling_t *ceiling; + mtag_t tag = Tag_FGet(&line->tags); + TAG_ITER_DECLARECOUNTER(0); - while ((secnum = P_FindSectorFromTag(line->tag,secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { sec = §ors[secnum]; @@ -593,7 +595,7 @@ INT32 EV_DoCeiling(line_t *line, ceiling_e type) } - ceiling->tag = sec->tag; + ceiling->tag = tag; ceiling->type = type; firstone = 0; } @@ -614,8 +616,10 @@ INT32 EV_DoCrush(line_t *line, ceiling_e type) INT32 secnum = -1; sector_t *sec; ceiling_t *ceiling; + mtag_t tag = Tag_FGet(&line->tags); + TAG_ITER_DECLARECOUNTER(0); - while ((secnum = P_FindSectorFromTag(line->tag,secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { sec = §ors[secnum]; @@ -670,7 +674,7 @@ INT32 EV_DoCrush(line_t *line, ceiling_e type) break; } - ceiling->tag = sec->tag; + ceiling->tag = tag; ceiling->type = type; } return rtn; diff --git a/src/p_enemy.c b/src/p_enemy.c index ddb01b63b..f9baf1813 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -3925,11 +3925,12 @@ void A_BossDeath(mobj_t *mo) else { // Bring the egg trap up to the surface - junk.tag = LE_CAPSULE0; + // Incredibly shitty code ahead + Tag_FSet(&junk.tags, LE_CAPSULE0); EV_DoElevator(&junk, elevateHighest, false); - junk.tag = LE_CAPSULE1; + Tag_FSet(&junk.tags, LE_CAPSULE1); EV_DoElevator(&junk, elevateUp, false); - junk.tag = LE_CAPSULE2; + Tag_FSet(&junk.tags, LE_CAPSULE2); EV_DoElevator(&junk, elevateHighest, false); if (mapheaderinfo[gamemap-1]->muspostbossname[0] && @@ -4052,7 +4053,7 @@ bossjustdie: } case MT_KOOPA: { - junk.tag = LE_KOOPA; + Tag_FSet(&junk.tags, LE_KOOPA); EV_DoCeiling(&junk, raiseToHighest); return; } @@ -6157,7 +6158,7 @@ void A_RockSpawn(mobj_t *actor) { mobj_t *mo; mobjtype_t type; - INT32 i = P_FindSpecialLineFromTag(12, (INT16)actor->threshold, -1); + INT32 i = Tag_FindLineSpecial(12, (INT16)actor->threshold); line_t *line; fixed_t dist; fixed_t randomoomph; diff --git a/src/p_floor.c b/src/p_floor.c index a0f7edd9c..ed49b03a3 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -632,8 +632,10 @@ void T_BounceCheese(bouncecheese_t *bouncer) fixed_t waterheight; fixed_t floorheight; sector_t *actionsector; - INT32 i; boolean remove; + INT32 i; + mtag_t tag = Tag_FGet(&bouncer->sourceline->tags); + TAG_ITER_DECLARECOUNTER(0); if (bouncer->sector->crumblestate == CRUMBLE_RESTORE || bouncer->sector->crumblestate == CRUMBLE_WAIT || bouncer->sector->crumblestate == CRUMBLE_ACTIVATED) // Oops! Crumbler says to remove yourself! @@ -648,7 +650,7 @@ void T_BounceCheese(bouncecheese_t *bouncer) } // You can use multiple target sectors, but at your own risk!!! - for (i = -1; (i = P_FindSectorFromTag(bouncer->sourceline->tag, i)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, i) { actionsector = §ors[i]; actionsector->moved = true; @@ -772,6 +774,8 @@ void T_StartCrumble(crumble_t *crumble) ffloor_t *rover; sector_t *sector; INT32 i; + mtag_t tag = Tag_FGet(&crumble->sourceline->tags); + TAG_ITER_DECLARECOUNTER(0); // Once done, the no-return thinker just sits there, // constantly 'returning'... kind of an oxymoron, isn't it? @@ -800,7 +804,7 @@ void T_StartCrumble(crumble_t *crumble) } else if (++crumble->timer == 0) // Reposition back to original spot { - for (i = -1; (i = P_FindSectorFromTag(crumble->sourceline->tag, i)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, i) { sector = §ors[i]; @@ -836,7 +840,7 @@ void T_StartCrumble(crumble_t *crumble) // Flash to indicate that the platform is about to return. if (crumble->timer > -224 && (leveltime % ((abs(crumble->timer)/8) + 1) == 0)) { - for (i = -1; (i = P_FindSectorFromTag(crumble->sourceline->tag, i)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, i) { sector = §ors[i]; @@ -928,7 +932,7 @@ void T_StartCrumble(crumble_t *crumble) P_RemoveThinker(&crumble->thinker); } - for (i = -1; (i = P_FindSectorFromTag(crumble->sourceline->tag, i)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, i) { sector = §ors[i]; sector->moved = true; @@ -944,6 +948,7 @@ void T_StartCrumble(crumble_t *crumble) void T_MarioBlock(mariothink_t *block) { INT32 i; + TAG_ITER_DECLARECOUNTER(0); T_MovePlane ( @@ -978,8 +983,7 @@ void T_MarioBlock(mariothink_t *block) block->sector->ceilspeed = 0; block->direction = 0; } - - for (i = -1; (i = P_FindSectorFromTag(block->tag, i)) >= 0 ;) + TAG_ITER_SECTORS(0, (INT16)block->tag, i) P_RecalcPrecipInSector(§ors[i]); } @@ -992,8 +996,7 @@ void T_FloatSector(floatthink_t *floater) // Just find the first sector with the tag. // Doesn't work with multiple sectors that have different floor/ceiling heights. - secnum = P_FindSectorFromTag(floater->tag, -1); - if (secnum <= 0) + if ((secnum = Tag_Iterate_Sectors((INT16)floater->tag, 0)) < 0) return; actionsector = §ors[secnum]; @@ -1131,10 +1134,8 @@ void T_ThwompSector(thwomp_t *thwomp) // Just find the first sector with the tag. // Doesn't work with multiple sectors that have different floor/ceiling heights. - secnum = P_FindSectorFromTag(thwomp->tag, -1); - - if (secnum <= 0) - return; // Bad bad bad! + if ((secnum = Tag_Iterate_Sectors((INT16)thwomp->tag, 0)) < 0) + return; actionsector = §ors[secnum]; @@ -1293,8 +1294,10 @@ void T_NoEnemiesSector(noenemies_t *nobaddies) sector_t *sec = NULL; INT32 secnum = -1; boolean FOFsector = false; + mtag_t tag = Tag_FGet(&nobaddies->sourceline->tags); + TAG_ITER_DECLARECOUNTER(0); - while ((secnum = P_FindSectorFromTag(nobaddies->sourceline->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { sec = §ors[secnum]; @@ -1304,13 +1307,15 @@ void T_NoEnemiesSector(noenemies_t *nobaddies) for (i = 0; i < sec->linecount; i++) { INT32 targetsecnum = -1; + mtag_t tag2 = Tag_FGet(&sec->lines[i]->tags); + TAG_ITER_DECLARECOUNTER(1); if (sec->lines[i]->special < 100 || sec->lines[i]->special >= 300) continue; FOFsector = true; - while ((targetsecnum = P_FindSectorFromTag(sec->lines[i]->tag, targetsecnum)) >= 0) + TAG_ITER_SECTORS(1, tag2, targetsecnum) { if (T_SectorHasEnemies(§ors[targetsecnum])) return; @@ -1321,7 +1326,7 @@ void T_NoEnemiesSector(noenemies_t *nobaddies) return; } - CONS_Debug(DBG_GAMELOGIC, "Running no-more-enemies exec with tag of %d\n", nobaddies->sourceline->tag); + CONS_Debug(DBG_GAMELOGIC, "Running no-more-enemies exec with tag of %d\n", tag); // No enemies found, run the linedef exec and terminate this thinker P_RunTriggerLinedef(nobaddies->sourceline, NULL, NULL); @@ -1396,6 +1401,8 @@ void T_EachTimeThinker(eachtime_t *eachtime) boolean floortouch = false; fixed_t bottomheight, topheight; ffloor_t *rover; + mtag_t tag = Tag_FGet(&eachtime->sourceline->tags); + TAG_ITER_DECLARECOUNTER(0); for (i = 0; i < MAXPLAYERS; i++) { @@ -1405,7 +1412,7 @@ void T_EachTimeThinker(eachtime_t *eachtime) eachtime->playersOnArea[i] = false; } - while ((secnum = P_FindSectorFromTag(eachtime->sourceline->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { sec = §ors[secnum]; @@ -1422,13 +1429,15 @@ void T_EachTimeThinker(eachtime_t *eachtime) for (i = 0; i < sec->linecount; i++) { INT32 targetsecnum = -1; + mtag_t tag2 = Tag_FGet(&sec->lines[i]->tags); + TAG_ITER_DECLARECOUNTER(1); if (sec->lines[i]->special < 100 || sec->lines[i]->special >= 300) continue; FOFsector = true; - while ((targetsecnum = P_FindSectorFromTag(sec->lines[i]->tag, targetsecnum)) >= 0) + TAG_ITER_SECTORS(1, tag2, targetsecnum) { targetsec = §ors[targetsecnum]; @@ -1530,7 +1539,7 @@ void T_EachTimeThinker(eachtime_t *eachtime) if (!playersArea[i] && (!eachtime->triggerOnExit || !P_IsPlayerValid(i))) continue; - CONS_Debug(DBG_GAMELOGIC, "Trying to activate each time executor with tag %d\n", eachtime->sourceline->tag); + CONS_Debug(DBG_GAMELOGIC, "Trying to activate each time executor with tag %d\n", tag); // 03/08/14 -Monster Iestyn // No more stupid hacks involving changing eachtime->sourceline's tag or special or whatever! @@ -1562,11 +1571,13 @@ void T_RaiseSector(raise_t *raise) fixed_t distToNearestEndpoint; INT32 direction; result_e res = 0; + mtag_t tag = raise->tag; + TAG_ITER_DECLARECOUNTER(0); if (raise->sector->crumblestate >= CRUMBLE_FALL || raise->sector->ceilingdata) return; - for (i = -1; (i = P_FindSectorFromTag(raise->tag, i)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, i) { sector = §ors[i]; @@ -1693,7 +1704,7 @@ void T_RaiseSector(raise_t *raise) raise->sector->ceilspeed = 42; raise->sector->floorspeed = speed*direction; - for (i = -1; (i = P_FindSectorFromTag(raise->tag, i)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, i) P_RecalcPrecipInSector(§ors[i]); } @@ -1810,8 +1821,10 @@ void EV_DoFloor(line_t *line, floor_e floortype) INT32 secnum = -1; sector_t *sec; floormove_t *dofloor; + mtag_t tag = Tag_FGet(&line->tags); + TAG_ITER_DECLARECOUNTER(0); - while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { sec = §ors[secnum]; @@ -2025,9 +2038,11 @@ void EV_DoElevator(line_t *line, elevator_e elevtype, boolean customspeed) INT32 secnum = -1; sector_t *sec; elevator_t *elevator; + mtag_t tag = Tag_FGet(&line->tags); + TAG_ITER_DECLARECOUNTER(0); // act on all sectors with the same tag as the triggering linedef - while ((secnum = P_FindSectorFromTag(line->tag,secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { sec = §ors[secnum]; @@ -2148,6 +2163,7 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover) INT16 flags; sector_t *controlsec = rover->master->frontsector; + mtag_t tag = Tag_FGet(&controlsec->tags); if (sec == NULL) { @@ -2176,9 +2192,9 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover) lifetime = 3*TICRATE; flags = 0; - if (controlsec->tag != 0) + if (tag != 0) { - INT32 tagline = P_FindSpecialLineFromTag(14, controlsec->tag, -1); + INT32 tagline = Tag_FindLineSpecial(14, tag); if (tagline != -1) { if (sides[lines[tagline].sidenum[0]].toptexture) @@ -2322,6 +2338,8 @@ INT32 EV_StartCrumble(sector_t *sec, ffloor_t *rover, boolean floating, crumble_t *crumble; sector_t *foundsec; INT32 i; + mtag_t tag = Tag_FGet(&rover->master->tags); + TAG_ITER_DECLARECOUNTER(0); // If floor is already activated, skip it if (sec->floordata) @@ -2364,7 +2382,7 @@ INT32 EV_StartCrumble(sector_t *sec, ffloor_t *rover, boolean floating, crumble->sector->crumblestate = CRUMBLE_ACTIVATED; - for (i = -1; (i = P_FindSectorFromTag(crumble->sourceline->tag, i)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, i) { foundsec = §ors[i]; @@ -2413,7 +2431,7 @@ void EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher) block->direction = 1; block->floorstartheight = block->sector->floorheight; block->ceilingstartheight = block->sector->ceilingheight; - block->tag = (INT16)sector->tag; + block->tag = (INT16)Tag_FGet(§or->tags); if (itsamonitor) { diff --git a/src/p_inter.c b/src/p_inter.c index bd044f32a..415c679e4 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1388,7 +1388,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (player->bot) return; - junk.tag = LE_AXE; + Tag_FSet(&junk.tags, LE_AXE); EV_DoElevator(&junk, bridgeFall, false); // scan the remaining thinkers to find koopa diff --git a/src/p_lights.c b/src/p_lights.c index 371077a30..d396e92d3 100644 --- a/src/p_lights.c +++ b/src/p_lights.c @@ -374,8 +374,10 @@ void P_FadeLightBySector(sector_t *sector, INT32 destvalue, INT32 speed, boolean void P_FadeLight(INT16 tag, INT32 destvalue, INT32 speed, boolean ticbased, boolean force) { INT32 i; + TAG_ITER_DECLARECOUNTER(0); + // search all sectors for ones with tag - for (i = -1; (i = P_FindSectorFromTag(tag, i)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, i) { if (!force && ticbased // always let speed fader execute && sectors[i].lightingdata diff --git a/src/p_mobj.c b/src/p_mobj.c index 8b6b66849..4fc561b20 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3536,16 +3536,19 @@ static boolean P_CameraCheckHeat(camera_t *thiscam) { sector_t *sector; fixed_t halfheight = thiscam->z + (thiscam->height >> 1); + size_t i; // see if we are in water sector = thiscam->subsector->sector; - if (P_FindSpecialLineFromTag(13, sector->tag, -1) != -1) - return true; + for (i = 0; i < sector->tags.count; i++) + if (Tag_FindLineSpecial(13, sector->tags.tags[i]) != -1) + return true; if (sector->ffloors) { ffloor_t *rover; + size_t j; for (rover = sector->ffloors; rover; rover = rover->next) { @@ -3557,7 +3560,8 @@ static boolean P_CameraCheckHeat(camera_t *thiscam) if (halfheight <= P_GetFFloorBottomZAt(rover, thiscam->x, thiscam->y)) continue; - if (P_FindSpecialLineFromTag(13, rover->master->frontsector->tag, -1) != -1) + for (j = 0; j < rover->master->frontsector->tags.count; j++) + if (Tag_FindLineSpecial(13, rover->master->frontsector->tags.tags[j]) != -1) return true; } } @@ -4626,16 +4630,18 @@ static boolean P_Boss4MoveCage(mobj_t *mobj, fixed_t delta) const UINT16 tag = 65534 + (mobj->spawnpoint ? mobj->spawnpoint->extrainfo*LE_PARAMWIDTH : 0); INT32 snum; sector_t *sector; - for (snum = sectors[tag%numsectors].firsttag; snum != -1; snum = sector->nexttag) + boolean gotcage = false; + TAG_ITER_DECLARECOUNTER(0); + + TAG_ITER_SECTORS(0, tag, snum) { sector = §ors[snum]; - if (sector->tag != tag) - continue; sector->floorheight += delta; sector->ceilingheight += delta; P_CheckSector(sector, true); + gotcage = true; } - return sectors[tag%numsectors].firsttag != -1; + return gotcage; } // Move Boss4's arms to angle @@ -4707,26 +4713,16 @@ static void P_Boss4PinchSpikeballs(mobj_t *mobj, angle_t angle, fixed_t dz) static void P_Boss4DestroyCage(mobj_t *mobj) { const UINT16 tag = 65534 + (mobj->spawnpoint ? mobj->spawnpoint->extrainfo*LE_PARAMWIDTH : 0); - INT32 snum, next; + INT32 snum; size_t a; sector_t *sector, *rsec; ffloor_t *rover; + TAG_ITER_DECLARECOUNTER(0); - // This will be the final iteration of sector tag. - // We'll destroy the tag list as we go. - next = sectors[tag%numsectors].firsttag; - sectors[tag%numsectors].firsttag = -1; - - for (snum = next; snum != -1; snum = next) + TAG_ITER_SECTORS(0, tag, snum) { sector = §ors[snum]; - next = sector->nexttag; - sector->nexttag = -1; - if (sector->tag != tag) - continue; - sector->tag = 0; - // Destroy the FOFs. for (a = 0; a < sector->numattached; a++) { @@ -10046,11 +10042,12 @@ void P_MobjThinker(mobj_t *mobj) // Sector special (2,8) allows ANY mobj to trigger a linedef exec if (mobj->subsector && GETSECSPECIAL(mobj->subsector->sector->special, 2) == 8) { - sector_t *sec2; - - sec2 = P_ThingOnSpecial3DFloor(mobj); + sector_t *sec2 = P_ThingOnSpecial3DFloor(mobj); if (sec2 && GETSECSPECIAL(sec2->special, 2) == 1) - P_LinedefExecute(sec2->tag, mobj, sec2); + { + mtag_t tag = Tag_FGet(&sec2->tags); + P_LinedefExecute(tag, mobj, sec2); + } } if (mobj->scale != mobj->destscale) @@ -10274,14 +10271,19 @@ void P_PushableThinker(mobj_t *mobj) sec = mobj->subsector->sector; if (GETSECSPECIAL(sec->special, 2) == 1 && mobj->z == sec->floorheight) - P_LinedefExecute(sec->tag, mobj, sec); + { + mtag_t tag = Tag_FGet(&sec->tags); + P_LinedefExecute(tag, mobj, sec); + } + // else if (GETSECSPECIAL(sec->special, 2) == 8) { - sector_t *sec2; - - sec2 = P_ThingOnSpecial3DFloor(mobj); + sector_t *sec2 = P_ThingOnSpecial3DFloor(mobj); if (sec2 && GETSECSPECIAL(sec2->special, 2) == 1) - P_LinedefExecute(sec2->tag, mobj, sec2); + { + mtag_t tag = Tag_FGet(&sec2->tags); + P_LinedefExecute(tag, mobj, sec2); + } } // it has to be pushable RIGHT NOW for this part to happen @@ -12030,8 +12032,7 @@ static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) const size_t mthingi = (size_t)(mthing - mapthings); // Find the corresponding linedef special, using angle as tag - // P_FindSpecialLineFromTag works here now =D - line = P_FindSpecialLineFromTag(9, mthing->angle, -1); + line = Tag_FindLineSpecial(9, mthing->angle); if (line == -1) { @@ -12341,7 +12342,7 @@ static boolean P_SetupParticleGen(mapthing_t *mthing, mobj_t *mobj) const size_t mthingi = (size_t)(mthing - mapthings); // Find the corresponding linedef special, using angle as tag - line = P_FindSpecialLineFromTag(15, mthing->angle, -1); + line = Tag_FindLineSpecial(15, mthing->angle); if (line == -1) { @@ -12580,17 +12581,20 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean break; } case MT_SKYBOX: - if (mthing->tag < 0 || mthing->tag > 15) + { + mtag_t tag = Tag_FGet(&mthing->tags); + if (tag < 0 || tag > 15) { - CONS_Debug(DBG_GAMELOGIC, "P_SetupSpawnedMapThing: Skybox ID %d of mapthing %s is not between 0 and 15!\n", mthing->tag, sizeu1((size_t)(mthing - mapthings))); + CONS_Debug(DBG_GAMELOGIC, "P_SetupSpawnedMapThing: Skybox ID %d of mapthing %s is not between 0 and 15!\n", tag, sizeu1((size_t)(mthing - mapthings))); break; } if (mthing->options & MTF_OBJECTSPECIAL) - skyboxcenterpnts[mthing->tag] = mobj; + skyboxcenterpnts[tag] = mobj; else - skyboxviewpnts[mthing->tag] = mobj; + skyboxviewpnts[tag] = mobj; break; + } case MT_EGGSTATUE: if (mthing->options & MTF_EXTRA) { diff --git a/src/p_polyobj.c b/src/p_polyobj.c index 63d062c22..874edbd50 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -556,10 +556,11 @@ static void Polyobj_moveToSpawnSpot(mapthing_t *anchor) polyobj_t *po; vertex_t dist, sspot; size_t i; + mtag_t tag = Tag_FGet(&anchor->tags); - if (!(po = Polyobj_GetForNum(anchor->tag))) + if (!(po = Polyobj_GetForNum(tag))) { - CONS_Debug(DBG_POLYOBJ, "Bad polyobject %d for anchor point\n", anchor->tag); + CONS_Debug(DBG_POLYOBJ, "Bad polyobject %d for anchor point\n", tag); return; } @@ -1342,7 +1343,7 @@ void Polyobj_InitLevel(void) { qitem = (mobjqitem_t *)M_QueueIterator(&spawnqueue); - Polyobj_spawnPolyObj(i, qitem->mo, qitem->mo->spawnpoint->tag); + Polyobj_spawnPolyObj(i, qitem->mo, Tag_FGet(&qitem->mo->spawnpoint->tags)); } // move polyobjects to spawn points @@ -2444,10 +2445,11 @@ boolean EV_DoPolyObjFlag(polyflagdata_t *pfdata) polymove_t *th; size_t i; INT32 start; + mtag_t tag = pfdata->polyObjNum; - if (!(po = Polyobj_GetForNum(pfdata->polyObjNum))) + if (!(po = Polyobj_GetForNum(tag))) { - CONS_Debug(DBG_POLYOBJ, "EV_DoPolyFlag: bad polyobj %d\n", pfdata->polyObjNum); + CONS_Debug(DBG_POLYOBJ, "EV_DoPolyFlag: bad polyobj %d\n", tag); return false; } @@ -2470,7 +2472,7 @@ boolean EV_DoPolyObjFlag(polyflagdata_t *pfdata) po->thinker = &th->thinker; // set fields - th->polyObjNum = pfdata->polyObjNum; + th->polyObjNum = tag; th->distance = 0; th->speed = pfdata->speed; th->angle = pfdata->angle; diff --git a/src/p_saveg.c b/src/p_saveg.c index 6c9c7aff4..2abd65a95 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -923,7 +923,7 @@ static void UnArchiveFFloors(const sector_t *ss) static void ArchiveSectors(void) { - size_t i; + size_t i, j; const sector_t *ss = sectors; const sector_t *spawnss = spawnsectors; UINT8 diff, diff2, diff3; @@ -961,10 +961,8 @@ static void ArchiveSectors(void) if (ss->ceilingpic_angle != spawnss->ceilingpic_angle) diff2 |= SD_CEILANG; - if (ss->tag != spawnss->tag) + if (!Tag_Compare(&ss->tags, &spawnss->tags)) diff2 |= SD_TAG; - if (ss->nexttag != spawnss->nexttag || ss->firsttag != spawnss->firsttag) - diff3 |= SD_TAGLIST; if (ss->extra_colormap != spawnss->extra_colormap) diff3 |= SD_COLORMAP; @@ -1012,12 +1010,11 @@ static void ArchiveSectors(void) WRITEANGLE(save_p, ss->floorpic_angle); if (diff2 & SD_CEILANG) WRITEANGLE(save_p, ss->ceilingpic_angle); - if (diff2 & SD_TAG) // save only the tag - WRITEINT16(save_p, ss->tag); - if (diff3 & SD_TAGLIST) // save both firsttag and nexttag - { // either of these could be changed even if tag isn't - WRITEINT32(save_p, ss->firsttag); - WRITEINT32(save_p, ss->nexttag); + if (diff2 & SD_TAG) + { + WRITEUINT32(save_p, ss->tags.count); + for (j = 0; j < ss->tags.count; j++) + WRITEINT16(save_p, ss->tags.tags[j]); } if (diff3 & SD_COLORMAP) @@ -1035,7 +1032,7 @@ static void ArchiveSectors(void) static void UnArchiveSectors(void) { - UINT16 i; + UINT16 i, j; UINT8 diff, diff2, diff3; for (;;) { @@ -1089,13 +1086,29 @@ static void UnArchiveSectors(void) if (diff2 & SD_CEILANG) sectors[i].ceilingpic_angle = READANGLE(save_p); if (diff2 & SD_TAG) - sectors[i].tag = READINT16(save_p); // DON'T use P_ChangeSectorTag - if (diff3 & SD_TAGLIST) { - sectors[i].firsttag = READINT32(save_p); - sectors[i].nexttag = READINT32(save_p); + size_t ncount = READUINT32(save_p); + + // Remove entries from global lists. + for (j = 0; j < sectors[i].tags.count; j++) + Taggroup_Remove(tags_sectors, sectors[i].tags.tags[j], i); + + // Reallocate if size differs. + if (ncount != sectors[i].tags.count) + { + sectors[i].tags.count = ncount; + sectors[i].tags.tags = Z_Realloc(sectors[i].tags.tags, ncount*sizeof(mtag_t), PU_LEVEL, NULL); + } + + for (j = 0; j < ncount; j++) + sectors[i].tags.tags[j] = READINT16(save_p); + + // Add new entries. + for (j = 0; j < sectors[i].tags.count; j++) + Taggroup_Remove(tags_sectors, sectors[i].tags.tags[j], i); } + if (diff3 & SD_COLORMAP) sectors[i].extra_colormap = GetNetColormapFromList(READUINT32(save_p)); if (diff3 & SD_CRUMBLESTATE) diff --git a/src/p_setup.c b/src/p_setup.c index 23a73b1f5..d3e91d71a 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -82,6 +82,8 @@ #include "fastcmp.h" // textmap parsing +#include "taglist.h" + // // Map MD5, calculated on level load. // Sent to clients in PT_SERVERINFO. @@ -963,8 +965,6 @@ static void P_LoadVertices(UINT8 *data) static void P_InitializeSector(sector_t *ss) { - ss->nexttag = ss->firsttag = -1; - memset(&ss->soundorg, 0, sizeof(ss->soundorg)); ss->validcount = 0; @@ -1035,7 +1035,7 @@ static void P_LoadSectors(UINT8 *data) ss->lightlevel = SHORT(ms->lightlevel); ss->special = SHORT(ms->special); - ss->tag = SHORT(ms->tag); + Tag_FSet(&ss->tags, SHORT(ms->tag)); ss->floor_xoffs = ss->floor_yoffs = 0; ss->ceiling_xoffs = ss->ceiling_yoffs = 0; @@ -1077,7 +1077,6 @@ static void P_InitializeLinedef(line_t *ld) #ifdef WALLSPLATS ld->splats = NULL; #endif - ld->firsttag = ld->nexttag = -1; ld->polyobj = NULL; ld->text = NULL; @@ -1149,7 +1148,7 @@ static void P_LoadLinedefs(UINT8 *data) { ld->flags = SHORT(mld->flags); ld->special = SHORT(mld->special); - ld->tag = SHORT(mld->tag); + Tag_FSet(&ld->tags, SHORT(mld->tag)); memset(ld->args, 0, NUMLINEARGS*sizeof(*ld->args)); memset(ld->stringargs, 0x00, NUMLINESTRINGARGS*sizeof(*ld->stringargs)); ld->alpha = FRACUNIT; @@ -1342,7 +1341,7 @@ static void P_LoadSidedefs(UINT8 *data) || (msd->toptexture[0] >= 'A' && msd->toptexture[0] <= 'F')) sd->toptexture = axtoi(msd->toptexture); else - I_Error("Custom FOF (tag %d) needs a value in the linedef's back side upper texture field.", sd->line->tag); + I_Error("Custom FOF (line id %s) needs a value in the linedef's back side upper texture field.", sizeu1(sd->line - lines)); sd->midtexture = R_TextureNumForName(msd->midtexture); sd->bottomtexture = R_TextureNumForName(msd->bottomtexture); @@ -1382,8 +1381,8 @@ static void P_LoadThings(UINT8 *data) mt->type = READUINT16(data); mt->options = READUINT16(data); mt->extrainfo = (UINT8)(mt->type >> 12); + Tag_FSet(&mt->tags, 0); mt->scale = FRACUNIT; - mt->tag = 0; memset(mt->args, 0, NUMMAPTHINGARGS*sizeof(*mt->args)); memset(mt->stringargs, 0x00, NUMMAPTHINGSTRINGARGS*sizeof(*mt->stringargs)); mt->pitch = mt->roll = 0; @@ -1519,7 +1518,17 @@ static void ParseTextmapSectorParameter(UINT32 i, char *param, char *val) else if (fastcmp(param, "special")) sectors[i].special = atol(val); else if (fastcmp(param, "id")) - sectors[i].tag = atol(val); + Tag_FSet(§ors[i].tags, atol(val)); + else if (fastcmp(param, "moreids")) + { + char* id = val; + while (id) + { + Tag_Add(§ors[i].tags, atol(id)); + if ((id = strchr(id, ' '))) + id++; + } + } else if (fastcmp(param, "xpanningfloor")) sectors[i].floor_xoffs = FLOAT_TO_FIXED(atof(val)); else if (fastcmp(param, "ypanningfloor")) @@ -1597,7 +1606,17 @@ static void ParseTextmapSidedefParameter(UINT32 i, char *param, char *val) static void ParseTextmapLinedefParameter(UINT32 i, char *param, char *val) { if (fastcmp(param, "id")) - lines[i].tag = atol(val); + Tag_FSet(&lines[i].tags, atol(val)); + else if (fastcmp(param, "moreids")) + { + char* id = val; + while (id) + { + Tag_Add(&lines[i].tags, atol(id)); + if ((id = strchr(id, ' '))) + id++; + } + } else if (fastcmp(param, "special")) lines[i].special = atol(val); else if (fastcmp(param, "v1")) @@ -1666,8 +1685,18 @@ static void ParseTextmapLinedefParameter(UINT32 i, char *param, char *val) static void ParseTextmapThingParameter(UINT32 i, char *param, char *val) { if (fastcmp(param, "id")) - mapthings[i].tag = atol(val); - if (fastcmp(param, "x")) + Tag_FSet(&mapthings[i].tags, atol(val)); + else if (fastcmp(param, "moreids")) + { + char* id = val; + while (id) + { + Tag_Add(&mapthings[i].tags, atol(id)); + if ((id = strchr(id, ' '))) + id++; + } + } + else if (fastcmp(param, "x")) mapthings[i].x = atol(val); else if (fastcmp(param, "y")) mapthings[i].y = atol(val); @@ -1824,7 +1853,7 @@ static void P_LoadTextmap(void) sc->lightlevel = 255; sc->special = 0; - sc->tag = 0; + Tag_FSet(&sc->tags, 0); sc->floor_xoffs = sc->floor_yoffs = 0; sc->ceiling_xoffs = sc->ceiling_yoffs = 0; @@ -1842,6 +1871,7 @@ static void P_LoadTextmap(void) textmap_colormap.fadeend = 31; textmap_colormap.flags = 0; TextmapParse(sectorsPos[i], i, ParseTextmapSectorParameter); + P_InitializeSector(sc); if (textmap_colormap.used) { @@ -1858,7 +1888,8 @@ static void P_LoadTextmap(void) ld->v1 = ld->v2 = NULL; ld->flags = 0; ld->special = 0; - ld->tag = 0; + Tag_FSet(&ld->tags, 0); + memset(ld->args, 0, NUMLINEARGS*sizeof(*ld->args)); memset(ld->stringargs, 0x00, NUMLINESTRINGARGS*sizeof(*ld->stringargs)); ld->alpha = FRACUNIT; @@ -1906,8 +1937,8 @@ static void P_LoadTextmap(void) mt->options = 0; mt->z = 0; mt->extrainfo = 0; + Tag_FSet(&mt->tags, 0); mt->scale = FRACUNIT; - mt->tag = 0; memset(mt->args, 0, NUMMAPTHINGARGS*sizeof(*mt->args)); memset(mt->stringargs, 0x00, NUMMAPTHINGSTRINGARGS*sizeof(*mt->stringargs)); mt->mobj = NULL; @@ -2924,30 +2955,6 @@ static void P_LinkMapData(void) } } -/** Hashes the sector tags across the sectors and linedefs. - * - * \sa P_FindSectorFromTag, P_ChangeSectorTag - * \author Lee Killough - */ -static inline void P_InitTagLists(void) -{ - register size_t i; - - for (i = numsectors - 1; i != (size_t)-1; i--) - { - size_t j = (unsigned)sectors[i].tag % numsectors; - sectors[i].nexttag = sectors[j].firsttag; - sectors[j].firsttag = (INT32)i; - } - - for (i = numlines - 1; i != (size_t)-1; i--) - { - size_t j = (unsigned)lines[i].tag % numlines; - lines[i].nexttag = lines[j].firsttag; - lines[j].firsttag = (INT32)i; - } -} - //For maps in binary format, converts setup of specials to UDMF format. static void P_ConvertBinaryMap(void) { @@ -2955,14 +2962,28 @@ static void P_ConvertBinaryMap(void) for (i = 0; i < numlines; i++) { + mtag_t tag = Tag_FGet(&lines[i].tags); + switch (lines[i].special) { case 20: //PolyObject first line { - INT32 paramline = P_FindSpecialLineFromTag(22, lines[i].tag, -1); + INT32 check = -1; + INT32 paramline = -1; + + TAG_ITER_DECLARECOUNTER(0); + + TAG_ITER_LINES(0, tag, check) + { + if (lines[check].special == 22) + { + paramline = check; + break; + } + } //PolyObject ID - lines[i].args[0] = lines[i].tag; + lines[i].args[0] = tag; //Default: Invisible planes lines[i].args[3] |= TMPF_INVISIBLEPLANES; @@ -3008,7 +3029,7 @@ static void P_ConvertBinaryMap(void) CONS_Alert(CONS_WARNING, "Linedef %s is missing the hook name of the Lua function to call! (This should be given in the front texture fields)\n", sizeu1(i)); break; case 447: //Change colormap - lines[i].args[0] = lines[i].tag; + lines[i].args[0] = Tag_FGet(&lines[i].tags); if (lines[i].flags & ML_EFFECT3) lines[i].args[2] |= TMCF_RELATIVE; if (lines[i].flags & ML_EFFECT1) @@ -3024,7 +3045,7 @@ static void P_ConvertBinaryMap(void) abs(sides[lines[i].sidenum[1]].rowoffset >> FRACBITS) : abs(sides[lines[i].sidenum[0]].rowoffset >> FRACBITS)); - lines[i].args[0] = lines[i].tag; + lines[i].args[0] = Tag_FGet(&lines[i].tags); if (lines[i].flags & ML_EFFECT4) lines[i].args[2] = speed; else @@ -3044,10 +3065,10 @@ static void P_ConvertBinaryMap(void) break; } case 456: //Stop fading colormap - lines[i].args[0] = lines[i].tag; + lines[i].args[0] = Tag_FGet(&lines[i].tags); break; case 606: //Colormap - lines[i].args[0] = lines[i].tag; + lines[i].args[0] = Tag_FGet(&lines[i].tags); break; case 700: //Slope front sector floor case 701: //Slope front sector ceiling @@ -3088,7 +3109,7 @@ static void P_ConvertBinaryMap(void) else if (lines[i].special == 715) lines[i].args[0] = TMSP_BACKCEILING; - lines[i].args[1] = lines[i].tag; + lines[i].args[1] = tag; if (lines[i].flags & ML_EFFECT6) { @@ -3120,9 +3141,9 @@ static void P_ConvertBinaryMap(void) case 721: //Copy front side ceiling slope case 722: //Copy front side floor and ceiling slope if (lines[i].special != 721) - lines[i].args[0] = lines[i].tag; + lines[i].args[0] = tag; if (lines[i].special != 720) - lines[i].args[1] = lines[i].tag; + lines[i].args[1] = tag; lines[i].special = 720; break; case 900: //Translucent wall (10%) @@ -3155,21 +3176,39 @@ static void P_ConvertBinaryMap(void) switch (mapthings[i].type) { case 750: + Tag_Add(&mapthings[i].tags, mapthings[i].angle); + break; case 760: case 761: - mapthings[i].tag = mapthings[i].angle; + Tag_FSet(&mapthings[i].tags, mapthings[i].angle); break; case 762: { - INT32 firstline = P_FindSpecialLineFromTag(20, mapthings[i].angle, -1); + INT32 check = -1; + INT32 firstline = -1; + mtag_t tag = mapthings[i].angle; + + TAG_ITER_DECLARECOUNTER(0); + + Tag_FSet(&mapthings[i].tags, tag); + + TAG_ITER_LINES(0, tag, check) + { + if (lines[check].special == 20) + { + firstline = check; + break; + } + } + if (firstline != -1) lines[firstline].args[3] |= TMPF_CRUSH; - mapthings[i].tag = mapthings[i].angle; + mapthings[i].type = 761; break; } case 780: - mapthings[i].tag = mapthings[i].extrainfo; + Tag_FSet(&mapthings[i].tags, mapthings[i].extrainfo); break; default: break; @@ -3243,6 +3282,7 @@ static boolean P_LoadMapFromFile(void) { virtres_t *virt = vres_GetMap(lastloadedmaplumpnum); virtlump_t *textmap = vres_Find(virt, "TEXTMAP"); + size_t i; udmf = textmap != NULL; if (!P_LoadMapData(virt)) @@ -3252,7 +3292,7 @@ static boolean P_LoadMapFromFile(void) P_LinkMapData(); - P_InitTagLists(); // Create xref tables for tags + Taglist_InitGlobalTables(); if (!udmf) P_ConvertBinaryMap(); @@ -3266,6 +3306,10 @@ static boolean P_LoadMapFromFile(void) memcpy(spawnlines, lines, numlines * sizeof(*lines)); memcpy(spawnsides, sides, numsides * sizeof(*sides)); + for (i = 0; i < numsectors; i++) + if (sectors[i].tags.count) + spawnsectors[i].tags.tags = memcpy(Z_Malloc(sectors[i].tags.count*sizeof(mtag_t), PU_LEVEL, NULL), sectors[i].tags.tags, sectors[i].tags.count*sizeof(mtag_t)); + P_MakeMapMD5(virt, &mapmd5); vres_Free(virt); diff --git a/src/p_slopes.c b/src/p_slopes.c index e93b0f6c9..aa46a8402 100644 --- a/src/p_slopes.c +++ b/src/p_slopes.c @@ -139,7 +139,7 @@ void T_DynamicSlopeVert (dynplanethink_t* th) INT32 l; for (i = 0; i < 3; i++) { - l = P_FindSpecialLineFromTag(799, th->tags[i], -1); + l = Tag_FindLineSpecial(799, th->tags[i]); if (l != -1) { th->vex[i].z = lines[l].frontsector->floorheight; } @@ -405,9 +405,6 @@ static void line_SpawnViaLine(const int linenum, const boolean spawnthinker) P_AddDynSlopeThinker(cslope, DP_BACKCEIL, line, extent, NULL, NULL); } } - - if(!line->tag) - return; } /// Creates a new slope from three mapthings with the specified IDs @@ -426,11 +423,11 @@ static pslope_t *MakeViaMapthings(INT16 tag1, INT16 tag2, INT16 tag3, UINT8 flag if (mt->type != 750) // Haha, I'm hijacking the old Chaos Spawn thingtype for something! continue; - if (!vertices[0] && mt->tag == tag1) + if (!vertices[0] && Tag_Find(&mt->tags, tag1)) vertices[0] = mt; - else if (!vertices[1] && mt->tag == tag2) + else if (!vertices[1] && Tag_Find(&mt->tags, tag2)) vertices[1] = mt; - else if (!vertices[2] && mt->tag == tag3) + else if (!vertices[2] && Tag_Find(&mt->tags, tag3)) vertices[2] = mt; } @@ -549,11 +546,11 @@ static boolean P_SetSlopeFromTag(sector_t *sec, INT32 tag, boolean ceiling) { INT32 i; pslope_t **secslope = ceiling ? &sec->c_slope : &sec->f_slope; + TAG_ITER_DECLARECOUNTER(0); if (!tag || *secslope) return false; - - for (i = -1; (i = P_FindSectorFromTag(tag, i)) >= 0;) + TAG_ITER_SECTORS(0, tag, i) { pslope_t *srcslope = ceiling ? sectors[i].c_slope : sectors[i].f_slope; if (srcslope) diff --git a/src/p_spec.c b/src/p_spec.c index 7a79bd494..a1afdd00d 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -988,99 +988,12 @@ static sector_t *P_FindModelCeilingSector(fixed_t ceildestheight, INT32 secnum) } #endif -/** Searches the tag lists for the next sector with a given tag. - * - * \param tag Tag number to look for. - * \param start -1 to start anew, or the result of a previous call to keep - * searching. - * \return Number of the next tagged sector found. - */ -INT32 P_FindSectorFromTag(INT16 tag, INT32 start) -{ - if (tag == -1) - { - start++; - - if (start >= (INT32)numsectors) - return -1; - - return start; - } - else - { - start = start >= 0 ? sectors[start].nexttag : - sectors[(unsigned)tag % numsectors].firsttag; - while (start >= 0 && sectors[start].tag != tag) - start = sectors[start].nexttag; - return start; - } -} - -/** Searches the tag lists for the next line with a given tag and special. - * - * \param tag Tag number. - * \param start -1 to start anew, or the result of a previous call to keep - * searching. - * \return Number of next suitable line found. - * \author Graue - */ -static INT32 P_FindLineFromTag(INT32 tag, INT32 start) -{ - if (tag == -1) - { - start++; - - if (start >= (INT32)numlines) - return -1; - - return start; - } - else - { - start = start >= 0 ? lines[start].nexttag : - lines[(unsigned)tag % numlines].firsttag; - while (start >= 0 && lines[start].tag != tag) - start = lines[start].nexttag; - return start; - } -} - -INT32 P_FindSpecialLineFromTag(INT16 special, INT16 tag, INT32 start) -{ - if (tag == -1) - { - start++; - - // This redundant check stops the compiler from complaining about function expansion - // elsewhere for some reason and everything is awful - if (start >= (INT32)numlines) - return -1; - - while (start < (INT32)numlines && lines[start].special != special) - start++; - - if (start >= (INT32)numlines) - return -1; - - return start; - } - else - { - start = start >= 0 ? lines[start].nexttag : - lines[(unsigned)tag % numlines].firsttag; - while (start >= 0 && (lines[start].tag != tag || lines[start].special != special)) - start = lines[start].nexttag; - return start; - } -} - - // Parses arguments for parameterized polyobject door types static boolean PolyDoor(line_t *line) { polydoordata_t pdd; - pdd.polyObjNum = line->tag; // polyobject id + pdd.polyObjNum = Tag_FGet(&line->tags); // polyobject id switch(line->special) { @@ -1117,7 +1030,7 @@ static boolean PolyMove(line_t *line) { polymovedata_t pmd; - pmd.polyObjNum = line->tag; + pmd.polyObjNum = Tag_FGet(&line->tags); pmd.speed = sides[line->sidenum[0]].textureoffset / 8; pmd.angle = R_PointToAngle2(line->v1->x, line->v1->y, line->v2->x, line->v2->y); pmd.distance = sides[line->sidenum[0]].rowoffset; @@ -1131,7 +1044,7 @@ static boolean PolyMove(line_t *line) // If NOCLIMB is ticked, the polyobject will still be tangible, just not visible. static void PolyInvisible(line_t *line) { - INT32 polyObjNum = line->tag; + INT32 polyObjNum = Tag_FGet(&line->tags); polyobj_t *po; if (!(po = Polyobj_GetForNum(polyObjNum))) @@ -1155,7 +1068,7 @@ static void PolyInvisible(line_t *line) // If NOCLIMB is ticked, the polyobject will not be tangible, just visible. static void PolyVisible(line_t *line) { - INT32 polyObjNum = line->tag; + INT32 polyObjNum = Tag_FGet(&line->tags); polyobj_t *po; if (!(po = Polyobj_GetForNum(polyObjNum))) @@ -1180,7 +1093,7 @@ static void PolyVisible(line_t *line) // Frontsector floor / 100 = translevel static void PolyTranslucency(line_t *line) { - INT32 polyObjNum = line->tag; + INT32 polyObjNum = Tag_FGet(&line->tags); polyobj_t *po; INT32 value; @@ -1212,7 +1125,7 @@ static void PolyTranslucency(line_t *line) // Makes a polyobject translucency fade and applies tangibility static boolean PolyFade(line_t *line) { - INT32 polyObjNum = line->tag; + INT32 polyObjNum = Tag_FGet(&line->tags); polyobj_t *po; polyfadedata_t pfd; INT32 value; @@ -1274,7 +1187,7 @@ static boolean PolyWaypoint(line_t *line) { polywaypointdata_t pwd; - pwd.polyObjNum = line->tag; + pwd.polyObjNum = Tag_FGet(&line->tags); pwd.speed = sides[line->sidenum[0]].textureoffset / 8; pwd.sequence = sides[line->sidenum[0]].rowoffset >> FRACBITS; // Sequence # @@ -1301,7 +1214,7 @@ static boolean PolyRotate(line_t *line) { polyrotdata_t prd; - prd.polyObjNum = line->tag; + prd.polyObjNum = Tag_FGet(&line->tags); prd.speed = sides[line->sidenum[0]].textureoffset >> FRACBITS; // angular speed prd.distance = sides[line->sidenum[0]].rowoffset >> FRACBITS; // angular distance @@ -1326,7 +1239,7 @@ static boolean PolyFlag(line_t *line) { polyflagdata_t pfd; - pfd.polyObjNum = line->tag; + pfd.polyObjNum = Tag_FGet(&line->tags); pfd.speed = P_AproxDistance(line->dx, line->dy) >> FRACBITS; pfd.angle = R_PointToAngle2(line->v1->x, line->v1->y, line->v2->x, line->v2->y) >> ANGLETOFINESHIFT; pfd.momx = sides[line->sidenum[0]].textureoffset >> FRACBITS; @@ -1339,7 +1252,7 @@ static boolean PolyDisplace(line_t *line) { polydisplacedata_t pdd; - pdd.polyObjNum = line->tag; + pdd.polyObjNum = Tag_FGet(&line->tags); pdd.controlSector = line->frontsector; pdd.dx = line->dx>>8; @@ -1355,7 +1268,7 @@ static boolean PolyRotDisplace(line_t *line) polyrotdisplacedata_t pdd; fixed_t anginter, distinter; - pdd.polyObjNum = line->tag; + pdd.polyObjNum = Tag_FGet(&line->tags); pdd.controlSector = line->frontsector; // Rotate 'anginter' interval for each 'distinter' interval from the control sector. @@ -1375,66 +1288,6 @@ static boolean PolyRotDisplace(line_t *line) return EV_DoPolyObjRotDisplace(&pdd); } -/** Changes a sector's tag. - * Used by the linedef executor tag changer and by crumblers. - * - * \param sector Sector whose tag will be changed. - * \param newtag New tag number for this sector. - * \sa P_InitTagLists, P_FindSectorFromTag - * \author Graue - */ -void P_ChangeSectorTag(UINT32 sector, INT16 newtag) -{ - INT16 oldtag; - INT32 i; - - I_Assert(sector < numsectors); - - if ((oldtag = sectors[sector].tag) == newtag) - return; - - // first you have to remove it from the old tag's taglist - i = sectors[(unsigned)oldtag % numsectors].firsttag; - - if (i == -1) // shouldn't happen - I_Error("Corrupt tag list for sector %u\n", sector); - else if ((UINT32)i == sector) - sectors[(unsigned)oldtag % numsectors].firsttag = sectors[sector].nexttag; - else - { - while (sectors[i].nexttag != -1 && (UINT32)sectors[i].nexttag < sector ) - i = sectors[i].nexttag; - - sectors[i].nexttag = sectors[sector].nexttag; - } - - sectors[sector].tag = newtag; - - // now add it to the new tag's taglist - if ((UINT32)sectors[(unsigned)newtag % numsectors].firsttag > sector) - { - sectors[sector].nexttag = sectors[(unsigned)newtag % numsectors].firsttag; - sectors[(unsigned)newtag % numsectors].firsttag = sector; - } - else - { - i = sectors[(unsigned)newtag % numsectors].firsttag; - - if (i == -1) - { - sectors[(unsigned)newtag % numsectors].firsttag = sector; - sectors[sector].nexttag = -1; - } - else - { - while (sectors[i].nexttag != -1 && (UINT32)sectors[i].nexttag < sector ) - i = sectors[i].nexttag; - - sectors[sector].nexttag = sectors[i].nexttag; - sectors[i].nexttag = sector; - } - } -} // // P_RunNightserizeExecutors @@ -2103,7 +1956,7 @@ void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller) for (masterline = 0; masterline < numlines; masterline++) { - if (lines[masterline].tag != tag) + if (Tag_FGet(&lines[masterline].tags) != tag) continue; // "No More Enemies" and "Level Load" take care of themselves. @@ -2369,6 +2222,8 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) { INT32 secnum = -1; mobj_t *bot = NULL; + mtag_t tag = Tag_FGet(&line->tags); + TAG_ITER_DECLARECOUNTER(0); I_Assert(!mo || !P_MobjWasRemoved(mo)); // If mo is there, mo must be valid! @@ -2396,7 +2251,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) newceilinglightsec = line->frontsector->ceilinglightsec; // act on all sectors with the same tag as the triggering linedef - while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { if (sectors[secnum].lightingdata) { @@ -2451,17 +2306,17 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 409: // Change tagged sectors' tag // (formerly "Change calling sectors' tag", but behavior was changed) { - while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) - P_ChangeSectorTag(secnum,(INT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS)); + TAG_ITER_SECTORS(0, tag, secnum) + Tag_SectorFSet(secnum,(INT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS)); break; } case 410: // Change front sector's tag - P_ChangeSectorTag((UINT32)(line->frontsector - sectors), (INT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS)); + Tag_SectorFSet((UINT32)(line->frontsector - sectors), (INT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS)); break; case 411: // Stop floor/ceiling movement in tagged sector(s) - while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { if (sectors[secnum].floordata) { @@ -2531,7 +2386,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } else { - if ((secnum = P_FindSectorFromTag(line->tag, -1)) < 0) + if ((secnum = Tag_Iterate_Sectors(tag, 0)) < 0) return; dest = P_GetObjectTypeInSectorNum(MT_TELEPORTMAN, secnum); @@ -2638,7 +2493,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) return; } - if (line->tag != 0) // Do special stuff only if a non-zero linedef tag is set + if (tag != 0) // Do special stuff only if a non-zero linedef tag is set { // Play sounds from tagged sectors' origins. if (line->flags & ML_EFFECT5) // Repeat Midtexture @@ -2646,7 +2501,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) // Additionally play the sound from tagged sectors' soundorgs sector_t *sec; - while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { sec = §ors[secnum]; S_StartSound(&sec->soundorg, sfxnum); @@ -2666,7 +2521,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) if (!camobj) continue; - if (foundit || (camobj->subsector->sector->tag == line->tag)) + if (foundit || Tag_Find(&camobj->subsector->sector->tags, tag)) { foundit = true; break; @@ -2675,7 +2530,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) // Only trigger if mobj is touching the tag for(rover = camobj->subsector->sector->ffloors; rover; rover = rover->next) { - if (rover->master->frontsector->tag != line->tag) + if (!Tag_Find(&rover->master->frontsector->tags, tag)) continue; if (camobj->z > P_GetSpecialTopZ(camobj, sectors + rover->secnum, camobj->subsector->sector)) @@ -2761,7 +2616,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 416: // Spawn adjustable fire flicker - while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { if (line->flags & ML_NOCLIMB && line->backsector) { @@ -2795,7 +2650,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 417: // Spawn adjustable glowing light - while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { if (line->flags & ML_NOCLIMB && line->backsector) { @@ -2829,7 +2684,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 418: // Spawn adjustable strobe flash (unsynchronized) - while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { if (line->flags & ML_NOCLIMB && line->backsector) { @@ -2863,7 +2718,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 419: // Spawn adjustable strobe flash (synchronized) - while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { if (line->flags & ML_NOCLIMB && line->backsector) { @@ -2897,7 +2752,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 420: // Fade light levels in tagged sectors to new value - P_FadeLight(line->tag, + P_FadeLight(tag, (line->flags & ML_DONTPEGBOTTOM) ? max(sides[line->sidenum[0]].textureoffset>>FRACBITS, 0) : line->frontsector->lightlevel, // failsafe: if user specifies Back Y Offset and NOT Front Y Offset, use the Back Offset // to be consistent with other light and fade specials @@ -2911,7 +2766,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 421: // Stop lighting effect in tagged sectors - while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) if (sectors[secnum].lightingdata) { P_RemoveThinker(&((elevator_t *)sectors[secnum].lightingdata)->thinker); @@ -2926,7 +2781,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) if ((!mo || !mo->player) && !titlemapinaction) // only players have views, and title screens return; - if ((secnum = P_FindSectorFromTag(line->tag, -1)) < 0) + if ((secnum = Tag_Iterate_Sectors(tag, 0)) < 0) return; altview = P_GetObjectTypeInSectorNum(MT_ALTVIEWMAN, secnum); @@ -3108,8 +2963,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) continue; scroller = (scroll_t *)th; - - if (sectors[scroller->affectee].tag != line->tag) + if (!Tag_Find(§ors[scroller->affectee].tags, tag)) continue; scroller->dx = FixedMul(line->dx>>SCROLL_SHIFT, CARRYFACTOR); @@ -3126,7 +2980,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) ffloor_t *rover; // FOF that we are going to crumble boolean foundrover = false; // for debug, "Can't find a FOF" message - for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;) + TAG_ITER_SECTORS(0, sectag, secnum) { sec = sectors + secnum; @@ -3138,7 +2992,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) for (rover = sec->ffloors; rover; rover = rover->next) { - if (rover->master->frontsector->tag == foftag) + if (Tag_Find(&rover->master->frontsector->tags, foftag)) { foundrover = true; @@ -3185,12 +3039,13 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) size_t linenum; side_t *set = &sides[line->sidenum[0]], *this; boolean always = !(line->flags & ML_NOCLIMB); // If noclimb: Only change mid texture if mid texture already exists on tagged lines, etc. + for (linenum = 0; linenum < numlines; linenum++) { if (lines[linenum].special == 439) continue; // Don't override other set texture lines! - if (lines[linenum].tag != line->tag) + if (!Tag_Find(&lines[linenum].tags, tag)) continue; // Find tagged lines // Front side @@ -3250,7 +3105,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) if (line->sidenum[1] != 0xffff) state = (statenum_t)sides[line->sidenum[1]].toptexture; - while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { boolean tryagain; sec = sectors + secnum; @@ -3310,7 +3165,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) boolean foundrover = false; // for debug, "Can't find a FOF" message ffloortype_e oldflags; // store FOF's old flags - for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;) + TAG_ITER_SECTORS(0, sectag, secnum) { sec = sectors + secnum; @@ -3322,7 +3177,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) for (rover = sec->ffloors; rover; rover = rover->next) { - if (rover->master->frontsector->tag == foftag) + if (Tag_Find(&rover->master->frontsector->tags, foftag)) { foundrover = true; @@ -3368,7 +3223,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) if (line->flags & ML_NOCLIMB) // don't respawn! respawn = false; - for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;) + TAG_ITER_SECTORS(0, sectag, secnum) { sec = sectors + secnum; @@ -3380,7 +3235,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) for (rover = sec->ffloors; rover; rover = rover->next) { - if (rover->master->frontsector->tag == foftag) + if (Tag_Find(&rover->master->frontsector->tags, foftag)) { foundrover = true; @@ -3415,7 +3270,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) source = line->frontsector->extra_colormap; else { - INT32 sourcesec = P_FindSectorFromTag(line->args[1], -1); + INT32 sourcesec = Tag_Iterate_Sectors(line->args[1], 0); if (sourcesec == -1) { CONS_Debug(DBG_GAMELOGIC, "Line type 447 Executor: Can't find sector with source colormap (tag %d)!\n", line->args[1]); @@ -3424,8 +3279,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) source = sectors[sourcesec].extra_colormap; } } - - for (secnum = -1; (secnum = P_FindSectorFromTag(line->args[0], secnum)) >= 0;) + TAG_ITER_SECTORS(0, line->args[0], secnum) { if (sectors[secnum].colormap_protected) continue; @@ -3477,7 +3331,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) { CONS_Alert(CONS_WARNING, M_GetText("Skybox switch linedef (tag %d) doesn't have anything to do.\nConsider changing the linedef's flag configuration or removing it entirely.\n"), - line->tag); + tag); } else { @@ -3515,7 +3369,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) { CONS_Alert(CONS_WARNING, M_GetText("Boss enable linedef (tag %d) has an invalid texture x offset.\nConsider changing it or removing it entirely.\n"), - line->tag); + tag); break; } if (line->flags & ML_NOCLIMB) @@ -3532,7 +3386,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } case 450: // Execute Linedef Executor - for recursion - P_LinedefExecute(line->tag, mo, NULL); + P_LinedefExecute(tag, mo, NULL); break; case 451: // Execute Random Linedef Executor @@ -3560,7 +3414,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) ffloor_t *rover; // FOF that we are going to operate boolean foundrover = false; // for debug, "Can't find a FOF" message - for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;) + TAG_ITER_SECTORS(0, sectag, secnum) { sec = sectors + secnum; @@ -3572,7 +3426,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) for (rover = sec->ffloors; rover; rover = rover->next) { - if (rover->master->frontsector->tag == foftag) + if (Tag_Find(&rover->master->frontsector->tags, foftag)) { foundrover = true; @@ -3624,7 +3478,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) boolean foundrover = false; // for debug, "Can't find a FOF" message size_t j = 0; // sec->ffloors is saved as ffloor #0, ss->ffloors->next is #1, etc - for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;) + TAG_ITER_SECTORS(0, sectag, secnum) { sec = sectors + secnum; @@ -3636,7 +3490,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) for (rover = sec->ffloors; rover; rover = rover->next) { - if (rover->master->frontsector->tag == foftag) + if (Tag_Find(&rover->master->frontsector->tags, foftag)) { foundrover = true; @@ -3709,7 +3563,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) ffloor_t *rover; // FOF that we are going to operate boolean foundrover = false; // for debug, "Can't find a FOF" message - for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;) + TAG_ITER_SECTORS(0, sectag, secnum) { sec = sectors + secnum; @@ -3721,7 +3575,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) for (rover = sec->ffloors; rover; rover = rover->next) { - if (rover->master->frontsector->tag == foftag) + if (Tag_Find(&rover->master->frontsector->tags, foftag)) { foundrover = true; @@ -3750,7 +3604,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) dest = line->frontsector->extra_colormap; else { - INT32 destsec = P_FindSectorFromTag(line->args[1], -1); + INT32 destsec = Tag_Iterate_Sectors(line->args[1], 0); if (destsec == -1) { CONS_Debug(DBG_GAMELOGIC, "Line type 455 Executor: Can't find sector with destination colormap (tag %d)!\n", line->args[1]); @@ -3760,7 +3614,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } } - for (secnum = -1; (secnum = P_FindSectorFromTag(line->args[0], secnum)) >= 0;) + TAG_ITER_SECTORS(0, line->args[0], secnum) { extracolormap_t *source_exc, *dest_exc, *exc; @@ -3840,7 +3694,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; } case 456: // Stop fade colormap - for (secnum = -1; (secnum = P_FindSectorFromTag(line->args[0], secnum)) >= 0 ;) + TAG_ITER_SECTORS(0, line->args[0], secnum) P_ResetColormapFader(§ors[secnum]); break; @@ -3854,7 +3708,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) boolean persist = (line->flags & ML_EFFECT2); mobj_t *anchormo; - if ((secnum = P_FindSectorFromTag(line->tag, -1)) < 0) + if ((secnum = Tag_Iterate_Sectors(tag, 0)) < 0) return; anchormo = P_GetObjectTypeInSectorNum(MT_ANGLEMAN, secnum); @@ -3885,7 +3739,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) { INT32 promptnum = max(0, (sides[line->sidenum[0]].textureoffset>>FRACBITS)-1); INT32 pagenum = max(0, (sides[line->sidenum[0]].rowoffset>>FRACBITS)-1); - INT32 postexectag = abs((line->sidenum[1] != 0xFFFF) ? sides[line->sidenum[1]].textureoffset>>FRACBITS : line->tag); + INT32 postexectag = abs((line->sidenum[1] != 0xFFFF) ? sides[line->sidenum[1]].textureoffset>>FRACBITS : tag); boolean closetextprompt = (line->flags & ML_BLOCKMONSTERS); //boolean allplayers = (line->flags & ML_NOCLIMB); @@ -4009,7 +3863,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) if (!mo2->spawnpoint) continue; - if (mo2->spawnpoint->angle != line->tag) + if (mo2->spawnpoint->angle != tag) continue; P_KillMobj(mo2, NULL, mo, 0); @@ -4033,11 +3887,12 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 465: // Set linedef executor delay { INT32 linenum; + TAG_ITER_DECLARECOUNTER(1); if (!udmf) break; - for (linenum = -1; (linenum = P_FindLineFromTag(line->args[0], linenum)) >= 0 ;) + TAG_ITER_LINES(1, line->args[0], linenum) { if (line->args[2]) lines[linenum].executordelay += line->args[1]; @@ -4382,6 +4237,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers INT32 i = 0; INT32 section1, section2, section3, section4; INT32 special; + mtag_t sectag = Tag_FGet(§or->tags); section1 = GETSECSPECIAL(sector->special, 1); section2 = GETSECSPECIAL(sector->special, 2); @@ -4536,7 +4392,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers case 6: // Linedef executor (7 Emeralds) case 7: // Linedef executor (NiGHTS Mare) if (!player->bot) - P_LinedefExecute(sector->tag, player->mo, sector); + P_LinedefExecute(sectag, player->mo, sector); break; case 8: // Tells pushable things to check FOFs break; @@ -4565,14 +4421,14 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers sector->special = 0; // Move the button down - junk.tag = 680; + Tag_FSet(&junk.tags, 680); EV_DoElevator(&junk, elevateDown, false); // Open the top FOF - junk.tag = 681; + Tag_FSet(&junk.tags, 681); EV_DoFloor(&junk, raiseFloorToNearestFast); // Open the bottom FOF - junk.tag = 682; + Tag_FSet(&junk.tags, 682); EV_DoCeiling(&junk, lowerToLowestFast); // Mark all players with the time to exit thingy! @@ -4607,7 +4463,7 @@ DoneSection2: if (player->powers[pw_flashing] != 0 && player->powers[pw_flashing] < TICRATE/2) break; - i = P_FindSpecialLineFromTag(4, sector->tag, -1); + i = Tag_FindLineSpecial(4, sectag); if (i != -1) { @@ -4620,7 +4476,7 @@ DoneSection2: if (linespeed == 0) { - CONS_Debug(DBG_GAMELOGIC, "ERROR: Speed pad (tag %d) at zero speed.\n", sector->tag); + CONS_Debug(DBG_GAMELOGIC, "ERROR: Speed pad (tag %d) at zero speed.\n", sectag); break; } @@ -4714,7 +4570,7 @@ DoneSection2: // important: use sector->tag on next line instead of player->mo->subsector->tag // this part is different from in P_PlayerThink, this is what was causing // FOF custom exits not to work. - lineindex = P_FindSpecialLineFromTag(2, sector->tag, -1); + lineindex = Tag_FindLineSpecial(2, sectag); if (G_CoopGametype() && lineindex != -1) // Custom exit! { @@ -4840,7 +4696,7 @@ DoneSection2: break; // Find line #3 tagged to this sector - lineindex = P_FindSpecialLineFromTag(3, sector->tag, -1); + lineindex = Tag_FindLineSpecial(3, sectag); if (lineindex == -1) { @@ -4905,7 +4761,7 @@ DoneSection2: break; // Find line #3 tagged to this sector - lineindex = P_FindSpecialLineFromTag(3, sector->tag, -1); + lineindex = Tag_FindLineSpecial(3, sectag); if (lineindex == -1) { @@ -5034,7 +4890,7 @@ DoneSection2: memset(&resulthigh, 0x00, sizeof(resulthigh)); // Find line #11 tagged to this sector - lineindex = P_FindSpecialLineFromTag(11, sector->tag, -1); + lineindex = Tag_FindLineSpecial(11, sectag); if (lineindex == -1) { @@ -5654,7 +5510,7 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f { fixed_t tempceiling = sec2->ceilingheight; //flip the sector around and print an error instead of crashing 12.1.08 -Inuyasha - CONS_Alert(CONS_ERROR, M_GetText("A FOF tagged %d has a top height below its bottom.\n"), master->tag); + CONS_Alert(CONS_ERROR, M_GetText("FOF (line %s) has a top height below its bottom.\n"), sizeu1(master - lines)); sec2->ceilingheight = sec2->floorheight; sec2->floorheight = tempceiling; } @@ -5794,7 +5650,7 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f if ((flags & FF_FLOATBOB)) { - P_AddFloatThinker(sec2, sec->tag, master); + P_AddFloatThinker(sec2, Tag_FGet(&master->tags), master); CheckForFloatBob = true; } @@ -5950,7 +5806,7 @@ static void P_AddAirbob(sector_t *sec, INT16 tag, fixed_t dist, boolean raise, b * \sa P_SpawnSpecials, T_ThwompSector * \author SSNTails */ -static inline void P_AddThwompThinker(sector_t *sec, INT16 tag, line_t *sourceline, fixed_t crushspeed, fixed_t retractspeed, UINT16 sound) +static inline void P_AddThwompThinker(sector_t *sec, line_t *sourceline, fixed_t crushspeed, fixed_t retractspeed, UINT16 sound) { thwomp_t *thwomp; @@ -5974,7 +5830,7 @@ static inline void P_AddThwompThinker(sector_t *sec, INT16 tag, line_t *sourceli thwomp->floorstartheight = sec->floorheight; thwomp->ceilingstartheight = sec->ceilingheight; thwomp->delay = 1; - thwomp->tag = tag; + thwomp->tag = Tag_FGet(&sourceline->tags); thwomp->sound = sound; sec->floordata = thwomp; @@ -6066,8 +5922,9 @@ void T_LaserFlash(laserthink_t *flash) sector_t *sector; sector_t *sourcesec = flash->sourceline->frontsector; fixed_t top, bottom; + TAG_ITER_DECLARECOUNTER(0); - for (s = -1; (s = P_FindSectorFromTag(flash->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, flash->tag, s) { sector = §ors[s]; for (fflr = sector->ffloors; fflr; fflr = fflr->next) @@ -6322,6 +6179,8 @@ void P_SpawnSpecials(boolean fromnetsave) // Init line EFFECTs for (i = 0; i < numlines; i++) { + mtag_t tag = Tag_FGet(&lines[i].tags); + if (lines[i].special != 7) // This is a hack. I can at least hope nobody wants to prevent flat alignment in netgames... { // set line specials to 0 here too, same reason as above @@ -6345,10 +6204,11 @@ void P_SpawnSpecials(boolean fromnetsave) INT32 s; size_t sec; ffloortype_e ffloorflags; + TAG_ITER_DECLARECOUNTER(0); case 1: // Definable gravity per sector sec = sides[*lines[i].sidenum].sector - sectors; - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) { sectors[s].gravity = §ors[sec].floorheight; // This allows it to change in realtime! @@ -6372,7 +6232,7 @@ void P_SpawnSpecials(boolean fromnetsave) case 5: // Change camera info sec = sides[*lines[i].sidenum].sector - sectors; - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) P_AddCameraScanner(§ors[sec], §ors[s], R_PointToAngle2(lines[i].v2->x, lines[i].v2->y, lines[i].v1->x, lines[i].v1->y)); break; @@ -6395,22 +6255,22 @@ void P_SpawnSpecials(boolean fromnetsave) } //If no tag is given, apply to front sector - if (lines[i].tag == 0) + if (tag == 0) P_ApplyFlatAlignment(lines + i, lines[i].frontsector, flatangle, xoffs, yoffs); else { - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0;) + TAG_ITER_SECTORS(0, tag, s) P_ApplyFlatAlignment(lines + i, sectors + s, flatangle, xoffs, yoffs); } } else // Otherwise, print a helpful warning. Can I do no less? CONS_Alert(CONS_WARNING, M_GetText("Flat alignment linedef (tag %d) doesn't have anything to do.\nConsider changing the linedef's flag configuration or removing it entirely.\n"), - lines[i].tag); + tag); break; case 8: // Sector Parameters - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) { if (lines[i].flags & ML_NOCLIMB) { @@ -6437,8 +6297,7 @@ void P_SpawnSpecials(boolean fromnetsave) break; case 10: // Vertical culling plane for sprites and FOFs - sec = sides[*lines[i].sidenum].sector - sectors; - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) sectors[s].cullheight = &lines[i]; // This allows it to change in realtime! break; @@ -6499,36 +6358,38 @@ void P_SpawnSpecials(boolean fromnetsave) case 63: // support for drawn heights coming from different sector sec = sides[*lines[i].sidenum].sector-sectors; - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) sectors[s].heightsec = (INT32)sec; break; case 64: // Appearing/Disappearing FOF option if (lines[i].flags & ML_BLOCKMONSTERS) { // Find FOFs by control sector tag - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) for (j = 0; (unsigned)j < sectors[s].linecount; j++) if (sectors[s].lines[j]->special >= 100 && sectors[s].lines[j]->special < 300) Add_MasterDisappearer(abs(lines[i].dx>>FRACBITS), abs(lines[i].dy>>FRACBITS), abs(sides[lines[i].sidenum[0]].sector->floorheight>>FRACBITS), (INT32)(sectors[s].lines[j]-lines), (INT32)i); } else // Find FOFs by effect sector tag - for (s = -1; (s = P_FindLineFromTag(lines[i].tag, s)) >= 0 ;) + { + TAG_ITER_LINES(0, tag, s) { if ((size_t)s == i) continue; - if (sides[lines[s].sidenum[0]].sector->tag == sides[lines[i].sidenum[0]].sector->tag) + if (Tag_Find(&sides[lines[s].sidenum[0]].sector->tags, Tag_FGet(&sides[lines[i].sidenum[0]].sector->tags))) Add_MasterDisappearer(abs(lines[i].dx>>FRACBITS), abs(lines[i].dy>>FRACBITS), abs(sides[lines[i].sidenum[0]].sector->floorheight>>FRACBITS), s, (INT32)i); } + } break; case 66: // Displace floor by front sector - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) P_AddPlaneDisplaceThinker(pd_floor, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s, !!(lines[i].flags & ML_NOCLIMB)); break; case 67: // Displace ceiling by front sector - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) P_AddPlaneDisplaceThinker(pd_ceiling, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s, !!(lines[i].flags & ML_NOCLIMB)); break; case 68: // Displace both floor AND ceiling by front sector - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) P_AddPlaneDisplaceThinker(pd_both, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s, !!(lines[i].flags & ML_NOCLIMB)); break; @@ -6725,16 +6586,16 @@ void P_SpawnSpecials(boolean fromnetsave) { fixed_t dist = (lines[i].special == 150) ? 16*FRACUNIT : P_AproxDistance(lines[i].dx, lines[i].dy); P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); - P_AddAirbob(lines[i].frontsector, lines[i].tag, dist, false, !!(lines[i].flags & ML_NOCLIMB), false); + P_AddAirbob(lines[i].frontsector, tag, dist, false, !!(lines[i].flags & ML_NOCLIMB), false); break; } case 152: // Adjustable air bobbing platform in reverse P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); - P_AddAirbob(lines[i].frontsector, lines[i].tag, P_AproxDistance(lines[i].dx, lines[i].dy), true, !!(lines[i].flags & ML_NOCLIMB), false); + P_AddAirbob(lines[i].frontsector, tag, P_AproxDistance(lines[i].dx, lines[i].dy), true, !!(lines[i].flags & ML_NOCLIMB), false); break; case 153: // Dynamic Sinking Platform P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); - P_AddAirbob(lines[i].frontsector, lines[i].tag, P_AproxDistance(lines[i].dx, lines[i].dy), false, !!(lines[i].flags & ML_NOCLIMB), true); + P_AddAirbob(lines[i].frontsector, tag, P_AproxDistance(lines[i].dx, lines[i].dy), false, !!(lines[i].flags & ML_NOCLIMB), true); break; case 160: // Float/bob platform @@ -6784,13 +6645,13 @@ void P_SpawnSpecials(boolean fromnetsave) case 176: // Air bobbing platform that will crumble and bob on the water when it falls and hits P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_FLOATBOB|FF_CRUMBLE, secthinkers); - P_AddAirbob(lines[i].frontsector, lines[i].tag, 16*FRACUNIT, false, !!(lines[i].flags & ML_NOCLIMB), false); + P_AddAirbob(lines[i].frontsector, tag, 16*FRACUNIT, false, !!(lines[i].flags & ML_NOCLIMB), false); break; case 177: // Air bobbing platform that will crumble and bob on // the water when it falls and hits, then never return P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_FLOATBOB|FF_CRUMBLE|FF_NORETURN, secthinkers); - P_AddAirbob(lines[i].frontsector, lines[i].tag, 16*FRACUNIT, false, !!(lines[i].flags & ML_NOCLIMB), false); + P_AddAirbob(lines[i].frontsector, tag, 16*FRACUNIT, false, !!(lines[i].flags & ML_NOCLIMB), false); break; case 178: // Crumbling platform that will float when it hits water @@ -6803,7 +6664,7 @@ void P_SpawnSpecials(boolean fromnetsave) case 180: // Air bobbing platform that will crumble P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_CRUMBLE, secthinkers); - P_AddAirbob(lines[i].frontsector, lines[i].tag, 16*FRACUNIT, false, !!(lines[i].flags & ML_NOCLIMB), false); + P_AddAirbob(lines[i].frontsector, tag, 16*FRACUNIT, false, !!(lines[i].flags & ML_NOCLIMB), false); break; case 190: // Rising Platform FOF (solid, opaque, shadows) @@ -6830,7 +6691,7 @@ void P_SpawnSpecials(boolean fromnetsave) ffloorflags |= FF_NOSHADE; P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); - P_AddRaiseThinker(lines[i].frontsector, lines[i].tag, speed, ceilingtop, ceilingbottom, !!(lines[i].flags & ML_BLOCKMONSTERS), !!(lines[i].flags & ML_NOCLIMB)); + P_AddRaiseThinker(lines[i].frontsector, tag, speed, ceilingtop, ceilingbottom, !!(lines[i].flags & ML_BLOCKMONSTERS), !!(lines[i].flags & ML_NOCLIMB)); break; } @@ -6892,7 +6753,7 @@ void P_SpawnSpecials(boolean fromnetsave) fixed_t crushspeed = (lines[i].flags & ML_EFFECT5) ? lines[i].dy >> 3 : 10*FRACUNIT; fixed_t retractspeed = (lines[i].flags & ML_EFFECT5) ? lines[i].dx >> 3 : 2*FRACUNIT; UINT16 sound = (lines[i].flags & ML_EFFECT4) ? sides[lines[i].sidenum[0]].textureoffset >> FRACBITS : sfx_thwomp; - P_AddThwompThinker(lines[i].frontsector, lines[i].tag, &lines[i], crushspeed, retractspeed, sound); + P_AddThwompThinker(lines[i].frontsector, &lines[i], crushspeed, retractspeed, sound); P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); break; } @@ -6934,7 +6795,7 @@ void P_SpawnSpecials(boolean fromnetsave) break; case 258: // Laser block - P_AddLaserThinker(lines[i].tag, lines + i, !!(lines[i].flags & ML_EFFECT1)); + P_AddLaserThinker(tag, lines + i, !!(lines[i].flags & ML_EFFECT1)); P_AddFakeFloorsByLine(i, FF_EXISTS|FF_RENDERALL|FF_NOSHADE|FF_EXTRA|FF_CUTEXTRA|FF_TRANSLUCENT, secthinkers); break; @@ -6945,7 +6806,7 @@ void P_SpawnSpecials(boolean fromnetsave) P_AddFakeFloorsByLine(i, fofflags, secthinkers); } else - I_Error("Custom FOF (tag %d) found without a linedef back side!", lines[i].tag); + I_Error("Custom FOF (tag %d) found without a linedef back side!", tag); break; case 300: // Linedef executor (combines with sector special 974/975) and commands @@ -7075,7 +6936,7 @@ void P_SpawnSpecials(boolean fromnetsave) { CONS_Alert(CONS_WARNING, M_GetText("Boss enable linedef (tag %d) has an invalid texture x offset.\nConsider changing it or removing it entirely.\n"), - lines[i].tag); + tag); break; } if (!(lines[i].flags & ML_NOCLIMB)) @@ -7124,46 +6985,46 @@ void P_SpawnSpecials(boolean fromnetsave) case 600: // floor lighting independently (e.g. lava) sec = sides[*lines[i].sidenum].sector-sectors; - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) sectors[s].floorlightsec = (INT32)sec; break; case 601: // ceiling lighting independently sec = sides[*lines[i].sidenum].sector-sectors; - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) sectors[s].ceilinglightsec = (INT32)sec; break; case 602: // Adjustable pulsating light sec = sides[*lines[i].sidenum].sector - sectors; - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) P_SpawnAdjustableGlowingLight(§ors[sec], §ors[s], P_AproxDistance(lines[i].dx, lines[i].dy)>>FRACBITS); break; case 603: // Adjustable flickering light sec = sides[*lines[i].sidenum].sector - sectors; - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) P_SpawnAdjustableFireFlicker(§ors[sec], §ors[s], P_AproxDistance(lines[i].dx, lines[i].dy)>>FRACBITS); break; case 604: // Adjustable Blinking Light (unsynchronized) sec = sides[*lines[i].sidenum].sector - sectors; - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) P_SpawnAdjustableStrobeFlash(§ors[sec], §ors[s], abs(lines[i].dx)>>FRACBITS, abs(lines[i].dy)>>FRACBITS, false); break; case 605: // Adjustable Blinking Light (synchronized) sec = sides[*lines[i].sidenum].sector - sectors; - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) P_SpawnAdjustableStrobeFlash(§ors[sec], §ors[s], abs(lines[i].dx)>>FRACBITS, abs(lines[i].dy)>>FRACBITS, true); break; case 606: // HACK! Copy colormaps. Just plain colormaps. - for (s = -1; (s = P_FindSectorFromTag(lines[i].args[0], s)) >= 0;) + TAG_ITER_SECTORS(0, lines[i].args[0], s) { extracolormap_t *exc; @@ -7178,7 +7039,7 @@ void P_SpawnSpecials(boolean fromnetsave) exc = lines[i].frontsector->extra_colormap; else { - INT32 sourcesec = P_FindSectorFromTag(lines[i].args[1], -1); + INT32 sourcesec = Tag_Iterate_Sectors(lines[i].args[1], 0); if (sourcesec == -1) { CONS_Debug(DBG_GAMELOGIC, "Line type 606: Can't find sector with source colormap (tag %d)!\n", lines[i].args[1]); @@ -7237,11 +7098,14 @@ void P_SpawnSpecials(boolean fromnetsave) */ static void P_AddFakeFloorsByLine(size_t line, ffloortype_e ffloorflags, thinkerlist_t *secthinkers) { + TAG_ITER_DECLARECOUNTER(0); INT32 s; + mtag_t tag = Tag_FGet(&lines[line].tags); size_t sec = sides[*lines[line].sidenum].sector-sectors; - for (s = -1; (s = P_FindSectorFromTag(lines[line].tag, s)) >= 0 ;) - P_AddFakeFloor(§ors[s], §ors[sec], lines+line, ffloorflags, secthinkers); + line_t* li = lines + line; + TAG_ITER_SECTORS(0, tag, s) + P_AddFakeFloor(§ors[s], §ors[sec], li, ffloorflags, secthinkers); } /* @@ -7350,6 +7214,7 @@ void T_Scroll(scroll_t *s) size_t i; INT32 sect; ffloor_t *rover; + TAG_ITER_DECLARECOUNTER(0); case sc_side: // scroll wall texture side = sides + s->affectee; @@ -7386,7 +7251,7 @@ void T_Scroll(scroll_t *s) if (!is3dblock) continue; - for (sect = -1; (sect = P_FindSectorFromTag(line->tag, sect)) >= 0 ;) + TAG_ITER_SECTORS(0, Tag_FGet(&line->tags), sect) { sector_t *psec; psec = sectors + sect; @@ -7461,8 +7326,7 @@ void T_Scroll(scroll_t *s) if (!is3dblock) continue; - - for (sect = -1; (sect = P_FindSectorFromTag(line->tag, sect)) >= 0 ;) + TAG_ITER_SECTORS(0, Tag_FGet(&line->tags), sect) { sector_t *psec; psec = sectors + sect; @@ -7560,6 +7424,7 @@ static void P_SpawnScrollers(void) { size_t i; line_t *l = lines; + mtag_t tag; for (i = 0; i < numlines; i++, l++) { @@ -7568,6 +7433,8 @@ static void P_SpawnScrollers(void) INT32 control = -1, accel = 0; // no control sector or acceleration INT32 special = l->special; + tag = Tag_FGet(&l->tags); + // These types are same as the ones they get set to except that the // first side's sector's heights cause scrolling when they change, and // this linedef controls the direction and speed of the scrolling. The @@ -7599,10 +7466,11 @@ static void P_SpawnScrollers(void) switch (special) { register INT32 s; + TAG_ITER_DECLARECOUNTER(0); case 513: // scroll effect ceiling case 533: // scroll and carry objects on ceiling - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) Add_Scroller(sc_ceiling, -dx, dy, control, s, accel, l->flags & ML_NOCLIMB); if (special != 533) break; @@ -7611,13 +7479,13 @@ static void P_SpawnScrollers(void) case 523: // carry objects on ceiling dx = FixedMul(dx, CARRYFACTOR); dy = FixedMul(dy, CARRYFACTOR); - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) Add_Scroller(sc_carry_ceiling, dx, dy, control, s, accel, l->flags & ML_NOCLIMB); break; case 510: // scroll effect floor case 530: // scroll and carry objects on floor - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) Add_Scroller(sc_floor, -dx, dy, control, s, accel, l->flags & ML_NOCLIMB); if (special != 530) break; @@ -7626,14 +7494,15 @@ static void P_SpawnScrollers(void) case 520: // carry objects on floor dx = FixedMul(dx, CARRYFACTOR); dy = FixedMul(dy, CARRYFACTOR); - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) Add_Scroller(sc_carry, dx, dy, control, s, accel, l->flags & ML_NOCLIMB); break; // scroll wall according to linedef // (same direction and speed as scrolling floors) case 502: - for (s = -1; (s = P_FindLineFromTag(l->tag, s)) >= 0 ;) + { + TAG_ITER_LINES(0, tag, s) if (s != (INT32)i) { if (l->flags & ML_EFFECT2) // use texture offsets instead @@ -7650,6 +7519,7 @@ static void P_SpawnScrollers(void) Add_Scroller(sc_side, dx, dy, control, lines[s].sidenum[0], accel, 0); } break; + } case 505: s = lines[i].sidenum[0]; @@ -7733,8 +7603,10 @@ void T_Disappear(disappear_t *d) { ffloor_t *rover; register INT32 s; + mtag_t afftag = Tag_FGet(&lines[d->affectee].tags); + TAG_ITER_DECLARECOUNTER(0); - for (s = -1; (s = P_FindSectorFromTag(lines[d->affectee].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, afftag, s) { for (rover = sectors[s].ffloors; rover; rover = rover->next) { @@ -8460,14 +8332,17 @@ static void P_SpawnFriction(void) { size_t i; line_t *l = lines; + mtag_t tag; register INT32 s; fixed_t strength; // frontside texture offset controls magnitude fixed_t friction; // friction value to be applied during movement INT32 movefactor; // applied to each player move to simulate inertia + TAG_ITER_DECLARECOUNTER(0); for (i = 0; i < numlines; i++, l++) if (l->special == 540) { + tag = Tag_FGet(&l->tags); strength = sides[l->sidenum[0]].textureoffset>>FRACBITS; if (strength > 0) // sludge strength = strength*2; // otherwise, the maximum sludginess value is +967... @@ -8488,7 +8363,7 @@ static void P_SpawnFriction(void) else movefactor = FRACUNIT; - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) Add_Friction(friction, movefactor, s, -1); } } @@ -9004,22 +8879,26 @@ static void P_SpawnPushers(void) { size_t i; line_t *l = lines; + mtag_t tag; register INT32 s; mobj_t *thing; + TAG_ITER_DECLARECOUNTER(0); for (i = 0; i < numlines; i++, l++) + { + tag = Tag_FGet(&l->tags); switch (l->special) { case 541: // wind - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) Add_Pusher(p_wind, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); break; case 544: // current - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) Add_Pusher(p_current, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); break; case 547: // push/pull - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) { thing = P_GetPushThing(s); if (thing) // No MT_P* means no effect @@ -9027,20 +8906,21 @@ static void P_SpawnPushers(void) } break; case 545: // current up - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) Add_Pusher(p_upcurrent, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); break; case 546: // current down - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) Add_Pusher(p_downcurrent, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); break; case 542: // wind up - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) Add_Pusher(p_upwind, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); break; case 543: // wind down - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) Add_Pusher(p_downwind, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); break; } + } } diff --git a/src/p_spec.h b/src/p_spec.h index 596d8171d..bba7c4a40 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -55,9 +55,6 @@ fixed_t P_FindNextLowestFloor(sector_t *sec, fixed_t currentheight); fixed_t P_FindLowestCeilingSurrounding(sector_t *sec); fixed_t P_FindHighestCeilingSurrounding(sector_t *sec); -INT32 P_FindSectorFromTag(INT16 tag, INT32 start); -INT32 P_FindSpecialLineFromTag(INT16 special, INT16 tag, INT32 start); - INT32 P_FindMinSurroundingLight(sector_t *sector, INT32 max); void P_SetupSignExit(player_t *player); @@ -67,7 +64,6 @@ void P_SwitchWeather(INT32 weathernum); boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller); void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller); -void P_ChangeSectorTag(UINT32 sector, INT16 newtag); void P_RunNightserizeExecutors(mobj_t *actor); void P_RunDeNightserizeExecutors(mobj_t *actor); void P_RunNightsLapExecutors(mobj_t *actor); diff --git a/src/p_user.c b/src/p_user.c index f9593158f..10b7e970e 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -10579,6 +10579,7 @@ static void P_CalcPostImg(player_t *player) postimg_t *type; INT32 *param; fixed_t pviewheight; + size_t i; if (player->mo->eflags & MFE_VERTICALFLIP) pviewheight = player->mo->z + player->mo->height - player->viewheight; @@ -10603,28 +10604,45 @@ static void P_CalcPostImg(player_t *player) } // see if we are in heat (no, not THAT kind of heat...) - - if (P_FindSpecialLineFromTag(13, sector->tag, -1) != -1) - *type = postimg_heat; - else if (sector->ffloors) + for (i = 0; i < sector->tags.count; i++) { - ffloor_t *rover; - fixed_t topheight; - fixed_t bottomheight; - - for (rover = sector->ffloors; rover; rover = rover->next) + if (Tag_FindLineSpecial(13, sector->tags.tags[i]) != -1) { - if (!(rover->flags & FF_EXISTS)) - continue; + *type = postimg_heat; + break; + } + else if (sector->ffloors) + { + ffloor_t *rover; + fixed_t topheight; + fixed_t bottomheight; + boolean gotres = false; - topheight = P_GetFFloorTopZAt (rover, player->mo->x, player->mo->y); - bottomheight = P_GetFFloorBottomZAt(rover, player->mo->x, player->mo->y); + for (rover = sector->ffloors; rover; rover = rover->next) + { + size_t j; - if (pviewheight >= topheight || pviewheight <= bottomheight) - continue; + if (!(rover->flags & FF_EXISTS)) + continue; - if (P_FindSpecialLineFromTag(13, rover->master->frontsector->tag, -1) != -1) - *type = postimg_heat; + topheight = P_GetFFloorTopZAt (rover, player->mo->x, player->mo->y); + bottomheight = P_GetFFloorBottomZAt(rover, player->mo->x, player->mo->y); + + if (pviewheight >= topheight || pviewheight <= bottomheight) + continue; + + for (j = 0; j < rover->master->frontsector->tags.count; j++) + { + if (Tag_FindLineSpecial(13, rover->master->frontsector->tags.tags[j]) != -1) + { + *type = postimg_heat; + gotres = true; + break; + } + } + } + if (gotres) + break; } } @@ -10723,22 +10741,21 @@ static sector_t *P_GetMinecartSector(fixed_t x, fixed_t y, fixed_t z, fixed_t *n static INT32 P_GetMinecartSpecialLine(sector_t *sec) { INT32 line = -1; + size_t i; if (!sec) return line; - if (sec->tag != 0) - line = P_FindSpecialLineFromTag(16, sec->tag, -1); + for (i = 0; i < sec->tags.count; i++) + if (sec->tags.tags[i] != 0) + line = Tag_FindLineSpecial(16, sec->tags.tags[i]); // Also try for lines facing the sector itself, with tag 0. + for (i = 0; i < sec->linecount; i++) { - UINT32 i; - for (i = 0; i < sec->linecount; i++) - { - line_t *li = sec->lines[i]; - if (li->tag == 0 && li->special == 16 && li->frontsector == sec) - line = li - lines; - } + line_t *li = sec->lines[i]; + if (Tag_Find(&li->tags, 0) && li->special == 16 && li->frontsector == sec) + line = li - lines; } return line; @@ -12297,12 +12314,14 @@ void P_PlayerThink(player_t *player) sector_t *controlsec; for (j=0; jtags); // Does this sector have a colormap? for (i=0; itag) + if (lines[i].special == 606 && linetag == controlsectag) break; } if (i == numlines) - CONS_Debug(DBG_GAMELOGIC, "%d, %d\n", j, sectors[j].tag); + CONS_Debug(DBG_GAMELOGIC, "%d, %d\n", j, sectag); } } diff --git a/src/r_bsp.c b/src/r_bsp.c index 56d038b44..2a3c662aa 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -21,6 +21,7 @@ #include "p_local.h" // camera #include "p_slopes.h" #include "z_zone.h" // Check R_Prep3DFloors +#include "taglist.h" seg_t *curline; side_t *sidedef; @@ -374,7 +375,7 @@ boolean R_IsEmptyLine(seg_t *line, sector_t *front, sector_t *back) // Consider colormaps && back->extra_colormap == front->extra_colormap && ((!front->ffloors && !back->ffloors) - || front->tag == back->tag)); + || Tag_Compare(&front->tags, &back->tags))); } // @@ -448,21 +449,25 @@ static void R_AddLine(seg_t *line) // Portal line if (line->linedef->special == 40 && line->side == 0) { + // Render portal if recursiveness limit hasn't been reached. + // Otherwise, render the wall normally. if (portalrender < cv_maxportals.value) { - // Find the other side! - INT32 line2 = P_FindSpecialLineFromTag(40, line->linedef->tag, -1); - if (line->linedef == &lines[line2]) - line2 = P_FindSpecialLineFromTag(40, line->linedef->tag, line2); - if (line2 >= 0) // found it! + size_t p; + mtag_t tag = Tag_FGet(&line->linedef->tags); + INT32 li1 = line->linedef-lines; + INT32 li2; + + for (p = 0; (li2 = Tag_Iterate_Lines(tag, p)) >= 0; p++) { - Portal_Add2Lines(line->linedef-lines, line2, x1, x2); // Remember the lines for later rendering - //return; // Don't fill in that space now! + // Skip invalid lines. + if ((tag != Tag_FGet(&lines[li2].tags)) || (lines[li1].special != lines[li2].special) || (li1 == li2)) + continue; + + Portal_Add2Lines(li1, li2, x1, x2); goto clipsolid; } } - // Recursed TOO FAR (viewing a portal within a portal) - // So uhhh, render it as a normal wall instead or something ??? } // Single sided line? @@ -483,7 +488,7 @@ static void R_AddLine(seg_t *line) if (!line->polyseg && !line->sidedef->midtexture && ((!frontsector->ffloors && !backsector->ffloors) - || (frontsector->tag == backsector->tag))) + || Tag_Compare(&frontsector->tags, &backsector->tags))) return; // line is empty, don't even bother goto clippass; // treat like wide open window instead diff --git a/src/r_defs.h b/src/r_defs.h index 132106bc8..026edeb0a 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -28,6 +28,8 @@ #include "m_aatree.h" #endif +#include "taglist.h" + // // ClipWallSegment // Clips the given range of columns @@ -281,8 +283,7 @@ typedef struct sector_s INT32 ceilingpic; INT16 lightlevel; INT16 special; - UINT16 tag; - INT32 nexttag, firsttag; // for fast tag searches + taglist_t tags; // origin for any sounds played by the sector // also considered the center for e.g. Mario blocks @@ -389,7 +390,7 @@ typedef struct line_s // Animation related. INT16 flags; INT16 special; - INT16 tag; + taglist_t tags; INT32 args[NUMLINEARGS]; char *stringargs[NUMLINESTRINGARGS]; @@ -412,7 +413,6 @@ typedef struct line_s #if 1//#ifdef WALLSPLATS void *splats; // wallsplat_t list #endif - INT32 firsttag, nexttag; // improves searches for tags. polyobj_t *polyobj; // Belongs to a polyobject? char *text; // a concatenation of all front and back texture names, for linedef specials that require a string. diff --git a/src/r_segs.c b/src/r_segs.c index 2cd7ebab2..aa04777c6 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -25,6 +25,7 @@ #include "p_local.h" // Camera... #include "p_slopes.h" #include "console.h" // con_clipviewtop +#include "taglist.h" // OPTIMIZE: closed two sided lines as single sided @@ -2067,7 +2068,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) || backsector->floorlightsec != frontsector->floorlightsec //SoM: 4/3/2000: Check for colormaps || frontsector->extra_colormap != backsector->extra_colormap - || (frontsector->ffloors != backsector->ffloors && frontsector->tag != backsector->tag)) + || (frontsector->ffloors != backsector->ffloors && !Tag_Compare(&frontsector->tags, &backsector->tags))) { markfloor = true; } @@ -2098,7 +2099,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) || backsector->ceilinglightsec != frontsector->ceilinglightsec //SoM: 4/3/2000: Check for colormaps || frontsector->extra_colormap != backsector->extra_colormap - || (frontsector->ffloors != backsector->ffloors && frontsector->tag != backsector->tag)) + || (frontsector->ffloors != backsector->ffloors && !Tag_Compare(&frontsector->tags, &backsector->tags))) { markceiling = true; } @@ -2188,7 +2189,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) rw_bottomtexturemid += sidedef->rowoffset; // allocate space for masked texture tables - if (frontsector && backsector && frontsector->tag != backsector->tag && (backsector->ffloors || frontsector->ffloors)) + if (frontsector && backsector && !Tag_Compare(&frontsector->tags, &backsector->tags) && (backsector->ffloors || frontsector->ffloors)) { ffloor_t *rover; ffloor_t *r2; @@ -2230,6 +2231,9 @@ void R_StoreWallRange(INT32 start, INT32 stop) for (r2 = frontsector->ffloors; r2; r2 = r2->next) { + if (r2->master == rover->master) // Skip if same control line. + break; + if (!(r2->flags & FF_EXISTS) || !(r2->flags & FF_RENDERSIDES)) continue; @@ -2285,6 +2289,9 @@ void R_StoreWallRange(INT32 start, INT32 stop) for (r2 = backsector->ffloors; r2; r2 = r2->next) { + if (r2->master == rover->master) // Skip if same control line. + break; + if (!(r2->flags & FF_EXISTS) || !(r2->flags & FF_RENDERSIDES)) continue; diff --git a/src/taglist.c b/src/taglist.c new file mode 100644 index 000000000..b11216b6c --- /dev/null +++ b/src/taglist.c @@ -0,0 +1,366 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 2020 by Nev3r. +// +// 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 taglist.c +/// \brief Ingame sector/line/mapthing tagging. + +#include "taglist.h" +#include "z_zone.h" +#include "r_data.h" + +// 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. +taggroup_t* tags_sectors[MAXTAGS + 1]; +taggroup_t* tags_lines[MAXTAGS + 1]; +taggroup_t* tags_mapthings[MAXTAGS + 1]; + +/// Adds a tag to a given element's taglist. +/// \warning This does not rebuild the global taggroups, which are used for iteration. +void Tag_Add (taglist_t* list, const mtag_t tag) +{ + list->tags = Z_Realloc(list->tags, (list->count + 1) * sizeof(list->tags), PU_LEVEL, NULL); + list->tags[list->count++] = tag; +} + +/// Sets the first tag entry in a taglist. +/// Replicates the old way of accessing element->tag. +void Tag_FSet (taglist_t* list, const mtag_t tag) +{ + if (!list->count) + { + Tag_Add(list, tag); + return; + } + + list->tags[0] = tag; +} + +/// Gets the first tag entry in a taglist. +/// Replicates the old way of accessing element->tag. +mtag_t Tag_FGet (const taglist_t* list) +{ + if (list->count) + return list->tags[0]; + + return 0; +} + +/// Returns true if the given tag exist inside the list. +boolean Tag_Find (const taglist_t* list, const mtag_t tag) +{ + size_t i; + for (i = 0; i < list->count; i++) + if (list->tags[i] == tag) + return true; + + return false; +} + +/// Returns true if at least one tag is shared between two given lists. +boolean Tag_Share (const taglist_t* list1, const taglist_t* list2) +{ + size_t i; + for (i = 0; i < list1->count; i++) + if (Tag_Find(list2, list1->tags[i])) + return true; + + return false; +} + +/// Returns true if both lists are identical. +boolean Tag_Compare (const taglist_t* list1, const taglist_t* list2) +{ + size_t i; + + if (list1->count != list2->count) + return false; + + for (i = 0; i < list1->count; i++) + if (list1->tags[i] != list2->tags[i]) + return false; + + return true; +} + +/// Search for an element inside a global taggroup. +size_t Taggroup_Find (const taggroup_t *group, const size_t id) +{ + size_t i; + + if (!group) + return -1; + + for (i = 0; i < group->count; i++) + if (group->elements[i] == id) + return i; + + return -1; +} + +/// Add an element to a global taggroup. +void Taggroup_Add (taggroup_t *garray[], const mtag_t tag, size_t id) +{ + taggroup_t *group; + size_t i; // Insert position. + + if (tag == MTAG_GLOBAL) + return; + + group = garray[(UINT16)tag]; + + // Don't add duplicate entries. + if (Taggroup_Find(group, id) != (size_t)-1) + return; + + // Create group if empty. + if (!group) + { + i = 0; + group = garray[(UINT16)tag] = Z_Calloc(sizeof(taggroup_t), PU_LEVEL, NULL); + } + else + { + // Keep the group element ids in an ascending order. + // Find the location to insert the element to. + 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->count++; + group->elements = Z_Realloc(group->elements, group->count * sizeof(size_t), PU_LEVEL, NULL); + group->elements[i] = id; +} + +/// 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; + + if (tag == MTAG_GLOBAL) + return; + + group = garray[(UINT16)tag]; + + if ((rempos = Taggroup_Find(group, id)) == (size_t)-1) + return; + + // Strip away taggroup if no elements left. + if (!(newcount = --group->count)) + { + Z_Free(group->elements); + Z_Free(group); + garray[(UINT16)tag] = NULL; + } + else + { + size_t *newelements = Z_Malloc(newcount * 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++) + newelements[i - 1] = group->elements[i]; + + Z_Free(group->elements); + group->elements = newelements; + group->count = newcount; + } +} + +// Initialization. + +static void Taglist_AddToSectors (const mtag_t tag, const size_t itemid) +{ + Taggroup_Add(tags_sectors, tag, itemid); +} + +static void Taglist_AddToLines (const mtag_t tag, const size_t itemid) +{ + Taggroup_Add(tags_lines, tag, itemid); +} + +static void Taglist_AddToMapthings (const mtag_t tag, const size_t itemid) +{ + Taggroup_Add(tags_mapthings, tag, itemid); +} + +/// After all taglists have been built for each element (sectors, lines, things), +/// the global taggroups, made for iteration, are built here. +void Taglist_InitGlobalTables(void) +{ + size_t i, j; + + for (i = 0; i < MAXTAGS; i++) + { + tags_sectors[i] = NULL; + tags_lines[i] = NULL; + tags_mapthings[i] = NULL; + } + for (i = 0; i < numsectors; i++) + { + for (j = 0; j < sectors[i].tags.count; j++) + Taglist_AddToSectors(sectors[i].tags.tags[j], i); + } + for (i = 0; i < numlines; i++) + { + for (j = 0; j < lines[i].tags.count; j++) + Taglist_AddToLines(lines[i].tags.tags[j], i); + } + for (i = 0; i < nummapthings; i++) + { + for (j = 0; j < mapthings[i].tags.count; j++) + Taglist_AddToMapthings(mapthings[i].tags.tags[j], i); + } +} + +// Iteration, ingame search. + +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; +} + +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; +} + +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; +} + +INT32 Tag_FindLineSpecial(const INT16 special, const mtag_t tag) +{ + size_t i; + + if (tag == MTAG_GLOBAL) + { + for (i = 0; i < numlines; i++) + if (lines[i].special == special) + return i; + } + else if (tags_lines[(UINT16)tag]) + { + taggroup_t *tagged = tags_lines[(UINT16)tag]; + for (i = 0; i < tagged->count; i++) + if (lines[tagged->elements[i]].special == special) + return tagged->elements[i]; + } + return -1; +} + +/// Backwards compatibility iteration function for Lua scripts. +INT32 P_FindSpecialLineFromTag(INT16 special, INT16 tag, INT32 start) +{ + if (tag == -1) + { + start++; + + if (start >= (INT32)numlines) + return -1; + + while (start < (INT32)numlines && lines[start].special != special) + start++; + + return start; + } + else + { + size_t p = 0; + INT32 id; + + // For backwards compatibility's sake, simulate the old linked taglist behavior: + // Iterate through the taglist and find the "start" line's position in the list, + // And start checking with the next one (if it exists). + if (start != -1) + { + for (; (id = Tag_Iterate_Lines(tag, p)) >= 0; p++) + if (id == start) + { + p++; + break; + } + } + + for (; (id = Tag_Iterate_Lines(tag, p)) >= 0; p++) + if (lines[id].special == special) + return id; + + return -1; + } +} + + +// Ingame list manipulation. + +/// Changes the first tag for a given sector, and updates the global taggroups. +void Tag_SectorFSet (const size_t id, const mtag_t tag) +{ + sector_t* sec = §ors[id]; + mtag_t curtag = Tag_FGet(&sec->tags); + if (curtag == tag) + return; + + Taggroup_Remove(tags_sectors, curtag, id); + Taggroup_Add(tags_sectors, tag, id); + Tag_FSet(&sec->tags, tag); +} diff --git a/src/taglist.h b/src/taglist.h new file mode 100644 index 000000000..0e6d9f842 --- /dev/null +++ b/src/taglist.h @@ -0,0 +1,127 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 2020 by Nev3r. +// +// 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 taglist.h +/// \brief Tag iteration and reading functions and macros' declarations. + +#ifndef __R_TAGLIST__ +#define __R_TAGLIST__ + +#include "doomtype.h" + +typedef INT16 mtag_t; +#define MAXTAGS UINT16_MAX +#define MTAG_GLOBAL -1 + +/// Multitag list. Each taggable element will have its own taglist. +typedef struct +{ + mtag_t* tags; + UINT16 count; +} taglist_t; + +void Tag_Add (taglist_t* list, const mtag_t tag); +void Tag_FSet (taglist_t* list, const mtag_t tag); +mtag_t Tag_FGet (const taglist_t* list); +boolean Tag_Find (const taglist_t* list, const mtag_t tag); +boolean Tag_Share (const taglist_t* list1, const taglist_t* list2); +boolean Tag_Compare (const taglist_t* list1, const taglist_t* list2); + +void Tag_SectorFSet (const size_t id, const mtag_t tag); + +/// Taggroup list. It is essentially just an element id list. +typedef struct +{ + size_t *elements; + size_t count; +} taggroup_t; + +extern taggroup_t* tags_sectors[]; +extern taggroup_t* tags_lines[]; +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); + +void Taglist_InitGlobalTables(void); + +INT32 Tag_Iterate_Sectors (const mtag_t tag, const size_t p); +INT32 Tag_Iterate_Lines (const mtag_t tag, const size_t p); +INT32 Tag_Iterate_Things (const mtag_t tag, const size_t p); + +INT32 Tag_FindLineSpecial(const INT16 special, const mtag_t tag); +INT32 P_FindSpecialLineFromTag(INT16 special, INT16 tag, INT32 start); + +// Use this macro to declare an iterator position variable. +#define TAG_ITER_DECLARECOUNTER(level) size_t ICNT_##level + +#define TAG_ITER(level, fn, tag, return_varname) for(ICNT_##level = 0; (return_varname = fn(tag, ICNT_##level)) >= 0; ICNT_##level++) + +// Use these macros as wrappers for a taglist iteration. +#define TAG_ITER_SECTORS(level, tag, return_varname) TAG_ITER(level, Tag_Iterate_Sectors, tag, return_varname) +#define TAG_ITER_LINES(level, tag, return_varname) TAG_ITER(level, Tag_Iterate_Lines, tag, return_varname) +#define TAG_ITER_THINGS(level, tag, return_varname) TAG_ITER(level, Tag_Iterate_Things, tag, return_varname) + +/* ITERATION MACROS +TAG_ITER_DECLARECOUNTER must be used before using the iterators. + +'level': +For each nested iteration, an additional TAG_ITER_DECLARECOUNTER +must be used with a different level number to avoid conflict with +the outer iterations. +Most cases don't have nested iterations and thus the level is just 0. + +'tag': +Pretty much the elements' tag to iterate through. + +'return_varname': +Target variable's name to return the iteration results to. + + +EXAMPLE: +{ + TAG_ITER_DECLARECOUNTER(0); + TAG_ITER_DECLARECOUNTER(1); // For the nested iteration. + + size_t li; + size_t sec; + + INT32 tag1 = 4; + + ... + + TAG_ITER_LINES(0, tag1, li) + { + line_t *line = lines + li; + + ... + + if (something) + { + mtag_t tag2 = 8; + + // Nested iteration; just make sure the level is higher + // and that it has its own counter declared in scope. + TAG_ITER_SECTORS(1, tag2, sec) + { + sector_t *sector = sectors + sec; + + ... + } + } + } +} + +Notes: +If no elements are found for a given tag, the loop inside won't be executed. +*/ + +#endif //__R_TAGLIST__