- uncouple sector tag storage from the sector data to allow multiple tags per sector.

Tags are now handled by a tag manager class which stores sector/tag pairs. This way multiple entries can be added per sector.
Since UDMF does not have any arrays the additional tags are stored as a space separated string as 'MoreIDs'.
This commit is contained in:
Christoph Oelckers 2015-04-19 12:33:27 +02:00
parent 6326cd74b4
commit b921157f57
21 changed files with 274 additions and 96 deletions

View file

@ -49,6 +49,7 @@
#include "gi.h"
#include "g_level.h"
#include "p_lnspec.h"
#include "p_tags.h"
#include "r_state.h"
#include "w_wad.h"
@ -551,8 +552,8 @@ void SetCompatibilityParams()
{
if ((unsigned)CompatParams[i + 1] < (unsigned)numsectors)
{
sectors[CompatParams[i + 1]].ClearTags();
sectors[CompatParams[i + 1]].SetMainTag(CompatParams[i + 2]);
// this assumes that the sector does not have any tags yet!
tagManager.AddSectorTag(CompatParams[i + 1], CompatParams[i + 2]);
}
i += 3;
break;

View file

@ -1165,7 +1165,7 @@ void FParser::SF_ObjSector(void)
}
t_return.type = svt_int;
t_return.value.i = mo ? mo->Sector->GetMainTag() : 0; // nullptr check
t_return.value.i = mo ? tagManager.GetFirstSectorTag(mo->Sector) : 0; // nullptr check
}
//==========================================================================
@ -4312,7 +4312,7 @@ void FParser::SF_KillInSector()
while ((mo=it.Next()))
{
if (mo->flags3&MF3_ISMONSTER && mo->Sector->HasTag(tag)) P_DamageMobj(mo, NULL, NULL, 1000000, NAME_Massacre);
if (mo->flags3&MF3_ISMONSTER && tagManager.SectorHasTag(mo->Sector, tag)) P_DamageMobj(mo, NULL, NULL, 1000000, NAME_Massacre);
}
}
}

View file

@ -636,7 +636,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain)
}
else if ((sec->special & 0xFF) == Scroll_StrifeCurrent)
{
int anglespeed = sec->GetMainTag() - 100;
int anglespeed = tagManager.GetFirstSectorTag(sec) - 100;
fixed_t speed = (anglespeed % 10) << (FRACBITS - 4);
angle_t finean = (anglespeed / 10) << (32-3);
finean >>= ANGLETOFINESHIFT;

View file

@ -326,6 +326,7 @@ xx(Arg4)
xx(Arg0Str)
xx(Arg1Str)
xx(Id)
xx(MoreIds)
xx(V1)
xx(V2)

View file

@ -3211,7 +3211,7 @@ do_count:
if (actor->health > 0 &&
(kind == NULL || actor->IsA (kind)))
{
if (actor->Sector->HasTag(tag) || tag == -1)
if (tag == -1 || tagManager.SectorHasTag(actor->Sector, tag))
{
// Don't count items in somebody's inventory
if (!actor->IsKindOf (RUNTIME_CLASS(AInventory)) ||
@ -3231,7 +3231,7 @@ do_count:
if (actor->health > 0 &&
(kind == NULL || actor->IsA (kind)))
{
if (actor->Sector->HasTag(tag) || tag == -1)
if (tag == -1 || tagManager.SectorHasTag(actor->Sector, tag))
{
// Don't count items in somebody's inventory
if (!actor->IsKindOf (RUNTIME_CLASS(AInventory)) ||

View file

@ -838,7 +838,7 @@ void EV_StopLightEffect (int tag)
while ((effect = iterator.Next()) != NULL)
{
if (effect->GetSector()->HasTag(tag))
if (tagManager.SectorHasTag(effect->GetSector(), tag))
{
effect->Destroy();
}

View file

@ -278,7 +278,7 @@ static void RemoveTaggedSectors(extsector_t::linked::plane &scrollplane, int tag
{
for(int i = scrollplane.Sectors.Size()-1; i>=0; i--)
{
if (scrollplane.Sectors[i].Sector->HasTag(tag))
if (tagManager.SectorHasTag(scrollplane.Sectors[i].Sector, tag))
{
scrollplane.Sectors.Delete(i);
}

View file

@ -1266,7 +1266,7 @@ FUNC(LS_Thing_Destroy)
while (actor)
{
AActor *temp = iterator.Next ();
if (actor->flags & MF_SHOOTABLE && actor->Sector->HasTag(arg2))
if (actor->flags & MF_SHOOTABLE && tagManager.SectorHasTag(actor->Sector, arg2))
P_DamageMobj (actor, NULL, it, arg1 ? TELEFRAG_DAMAGE : actor->health, NAME_None);
actor = temp;
}
@ -1279,7 +1279,7 @@ FUNC(LS_Thing_Destroy)
while (actor)
{
AActor *temp = iterator.Next ();
if (actor->flags & MF_SHOOTABLE && (arg2 == 0 || actor->Sector->HasTag(arg2)))
if (actor->flags & MF_SHOOTABLE && (arg2 == 0 || tagManager.SectorHasTag(actor->Sector, arg2)))
P_DamageMobj (actor, NULL, it, arg1 ? TELEFRAG_DAMAGE : actor->health, NAME_None);
actor = temp;
}
@ -2169,7 +2169,7 @@ static void SetScroller (int tag, DScroller::EScrollType type, fixed_t dx, fixed
{
if (scroller->IsType (type))
{
if (sectors[scroller->GetAffectee ()].HasTag(tag))
if (tagManager.SectorHasTag(scroller->GetAffectee (), tag))
{
i++;
scroller->SetRate (dx, dy);

View file

@ -3437,7 +3437,7 @@ void AActor::Tick ()
}
else if (scrolltype == Scroll_StrifeCurrent)
{ // Strife scroll special
int anglespeed = sec->GetMainTag() - 100;
int anglespeed = tagManager.GetFirstSectorTag(sec) - 100;
fixed_t carryspeed = DivScale32 (anglespeed % 10, 16*CARRYFACTOR);
angle_t fineangle = (anglespeed / 10) << (32-3);
fineangle >>= ANGLETOFINESHIFT;

View file

@ -348,9 +348,13 @@ void P_SerializeWorld (FArchive &arc)
{
arc << sec->lightlevel;
}
arc << sec->special
<< sec->tag
<< sec->soundtraversed
arc << sec->special;
if (SaveVersion < 4523)
{
short tag;
arc << tag;
}
arc << sec->soundtraversed
<< sec->seqType
<< sec->friction
<< sec->movefactor

View file

@ -825,45 +825,6 @@ sector_t *sector_t::GetHeightSec() const
}
bool sector_t::HasTag(int checktag) const
{
return tag == checktag;
}
bool sector_t::HasTags() const
{
return tag != 0;
}
void sector_t::SetMainTag(int tagnum)
{
tag = tagnum;
}
int sector_t::GetMainTag() const
{
return tag;
}
void sector_t::ClearTags()
{
tag = 0;
}
void sector_t::HashTags()
{
int i;
for (i=numsectors; --i>=0; ) // Initially make all slots empty.
sectors[i].firsttag = -1;
for (i=numsectors; --i>=0; ) // Proceed from last to first sector
{ // so that lower sectors appear first
int j = (unsigned) sectors[i].tag % (unsigned) numsectors; // Hash func
sectors[i].nexttag = sectors[j].firsttag; // Prepend sector to chain
sectors[j].firsttag = i;
}
}
void line_t::SetMainId(int newid)
{
id = newid;

View file

@ -1513,7 +1513,7 @@ void P_LoadSectors (MapData *map, FMissingTextureTracker &missingtex)
else // [RH] Translate to new sector special
ss->special = P_TranslateSectorSpecial (LittleShort(ms->special));
ss->secretsector = !!(ss->special&SECRET_MASK);
ss->SetMainTag(LittleShort(ms->tag));
tagManager.AddSectorTag(i, LittleShort(ms->tag));
ss->thinglist = NULL;
ss->touching_thinglist = NULL; // phares 3/14/98
ss->seqType = defSeqType;
@ -2493,7 +2493,7 @@ void P_ProcessSideTextures(bool checktranmap, side_t *sd, sector_t *sec, intmaps
for (s = 0; s < numsectors; s++)
{
if (sectors[s].HasTag(tag))
if (tagManager.SectorHasTag(s, tag))
{
if (!colorgood) color = sectors[s].ColorMap->Color;
if (!foggood) fog = sectors[s].ColorMap->Fade;
@ -3129,9 +3129,9 @@ static void P_GroupLines (bool buildmap)
{
if (sector->linecount == 0)
{
Printf ("Sector %i (tag %i) has no lines\n", i, sector->GetMainTag());
Printf ("Sector %i (tag %i) has no lines\n", i, tagManager.GetFirstSectorTag(sector));
// 0 the sector's tag so that no specials can use it
sector->ClearTags();
tagManager.RemoveSectorTags(i);
}
else
{
@ -3208,7 +3208,7 @@ static void P_GroupLines (bool buildmap)
// [RH] Moved this here
times[4].Clock();
// killough 1/30/98: Create xref tables for tags
sector_t::HashTags();
tagManager.HashTags();
line_t::HashIds();
times[4].Unclock();
@ -3340,6 +3340,7 @@ void P_FreeLevelData ()
FPolyObj::ClearAllSubsectorLinks(); // can't be done as part of the polyobj deletion process.
SN_StopAllSequences ();
DThinker::DestroyAllThinkers ();
tagManager.Clear();
level.total_monsters = level.total_items = level.total_secrets =
level.killed_monsters = level.found_items = level.found_secrets =
wminfo.maxfrags = 0;

View file

@ -1741,7 +1741,7 @@ static void P_SpawnScrollers(void)
if (lines[i].special == Sector_CopyScroller)
{
// don't allow copying the scroller if the sector has the same tag as it would just duplicate it.
if (lines[i].frontsector->HasTag(lines[i].args[0]))
if (tagManager.SectorHasTag(lines[i].frontsector, lines[i].args[0]))
{
copyscrollers.Push(i);
}
@ -2149,7 +2149,7 @@ DPusher::DPusher (DPusher::EPusher type, line_t *l, int magnitude, int angle,
int DPusher::CheckForSectorMatch (EPusher type, int tag)
{
if (m_Type == type && sectors[m_Affectee].HasTag(tag))
if (m_Type == type && tagManager.SectorHasTag(m_Affectee, tag))
return m_Affectee;
else
return -1;

View file

@ -35,13 +35,163 @@
#include "p_tags.h"
#include "c_dispatch.h"
FTagManager tagManager;
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
static inline int sectindex(const sector_t *sector)
{
return (int)(intptr_t)(sector - sectors);
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FTagManager::AddSectorTag(int sector, int tag)
{
// This function assumes that all tags for a single sector get added sequentially.
// Should there ever be some need for compatibility.txt to add tags to sectors which already have a tag this function needs to be changed to adjust the startForSector indices.
while (startForSector.Size() <= (unsigned int)sector)
{
startForSector.Push(-1);
}
if (startForSector[sector] == -1)
{
startForSector[sector] = allTags.Size();
}
else
{
// check if the key was already defined
for (unsigned i = startForSector[sector]; i < allTags.Size(); i++)
{
if (allTags[i].tag == tag)
{
return;
}
}
}
FTagItem it = { sector, tag, -1 };
allTags.Push(it);
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FTagManager::RemoveSectorTags(int sect)
{
int start = startForSector[sect];
if (start >= 0)
{
while (allTags[start].target == sect)
{
allTags[start].tag = allTags[start].target = -1;
start++;
}
}
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void FTagManager::HashTags()
{
// add an end marker so we do not need to check for the array's size in the other functions.
static FTagItem it = { -1, -1, -1 };
allTags.Push(it);
// Initially make all slots empty.
memset(TagHashFirst, -1, sizeof(TagHashFirst));
// Proceed from last to first so that lower targets appear first
for (int i = allTags.Size() - 1; i >= 0; i--)
{
if (allTags[i].target > 0) // only link valid entries
{
int hash = ((unsigned int)allTags[i].tag) % FTagManager::TAG_HASH_SIZE;
allTags[i].nexttag = TagHashFirst[hash];
TagHashFirst[hash] = i;
}
}
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
bool FTagManager::SectorHasTags(const sector_t *sector) const
{
int i = sectindex(sector);
return SectorHasTags(i);
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
int FTagManager::GetFirstSectorTag(const sector_t *sect) const
{
int i = sectindex(sect);
return SectorHasTags(i) ? allTags[startForSector[i]].tag : 0;
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
bool FTagManager::SectorHasTag(int i, int tag) const
{
if (SectorHasTags(i))
{
int ndx = startForSector[i];
while (allTags[ndx].target == i)
{
if (allTags[ndx].tag == tag) return true;
ndx++;
}
}
return false;
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
bool FTagManager::SectorHasTag(const sector_t *sector, int tag) const
{
return SectorHasTag(sectindex(sector), tag);
}
//-----------------------------------------------------------------------------
//
// RETURN NEXT SECTOR # THAT LINE TAG REFERS TO
//
// Find the next sector with a specified tag.
// Rewritten by Lee Killough to use chained hashing to improve speed
//
//-----------------------------------------------------------------------------
int FSectorTagIterator::Next()
{
@ -53,27 +203,37 @@ int FSectorTagIterator::Next()
}
else
{
while (start != -1 && sectors[start].tag != searchtag) start = sectors[start].nexttag;
while (start >= 0 && tagManager.allTags[start].tag != searchtag) start = tagManager.allTags[start].nexttag;
if (start == -1) return -1;
ret = start;
start = sectors[start].nexttag;
start = start = tagManager.allTags[start].nexttag;
}
return ret;
}
//-----------------------------------------------------------------------------
//
// linear search for compatible stair building
//
//-----------------------------------------------------------------------------
int FSectorTagIterator::NextCompat(bool compat, int start)
{
if (!compat) return Next();
for (int i = start + 1; i < numsectors; i++)
{
if (sectors[i].HasTag(searchtag)) return i;
if (tagManager.SectorHasTag(i, searchtag)) return i;
}
return -1;
}
//-----------------------------------------------------------------------------
//
// killough 4/16/98: Same thing, only for linedefs
//
//-----------------------------------------------------------------------------
int FLineIdIterator::Next()
{

View file

@ -4,6 +4,59 @@
#include "r_defs.h"
#include "r_state.h"
struct FTagItem
{
int target; // either sector or line
int tag;
int nexttag; // for hashing
};
class FSectorTagIterator;
class FTagManager
{
enum
{
TAG_HASH_SIZE = 256
};
friend class FSectorTagIterator;
TArray<FTagItem> allTags;
TArray<FTagItem> allIDs;
TArray<int> startForSector;
TArray<int> startForLine;
int TagHashFirst[TAG_HASH_SIZE];
bool SectorHasTags(int sect) const
{
return sect >= 0 && sect < (int)startForSector.Size() && startForSector[sect] >= 0;
}
public:
void Clear()
{
allTags.Clear();
allIDs.Clear();
startForSector.Clear();
startForLine.Clear();
memset(TagHashFirst, -1, sizeof(TagHashFirst));
}
bool SectorHasTags(const sector_t *sector) const;
int GetFirstSectorTag(const sector_t *sect) const;
bool SectorHasTag(int sector, int tag) const;
bool SectorHasTag(const sector_t *sector, int tag) const;
bool LineHasID(int line, int id);
void HashTags();
void AddSectorTag(int sector, int tag);
void RemoveSectorTags(int sect);
};
extern FTagManager tagManager;
class FSectorTagIterator
{
protected:
@ -14,7 +67,7 @@ public:
FSectorTagIterator(int tag)
{
searchtag = tag;
start = sectors[(unsigned)tag % (unsigned)numsectors].firsttag;
start = tagManager.TagHashFirst[((unsigned int)tag) % FTagManager::TAG_HASH_SIZE];
}
// Special constructor for actions that treat tag 0 as 'back of activation line'
@ -28,7 +81,7 @@ public:
else
{
searchtag = tag;
start = sectors[(unsigned)tag % (unsigned)numsectors].firsttag;
start = tagManager.TagHashFirst[((unsigned int)tag) % FTagManager::TAG_HASH_SIZE];
}
}

View file

@ -250,7 +250,7 @@ static AActor *SelectTeleDest (int tid, int tag, bool norandom)
int count = 0;
while ( (searcher = iterator.Next ()) )
{
if (tag == 0 || searcher->Sector->HasTag(tag))
if (tag == 0 || tagManager.SectorHasTag(searcher->Sector, tag))
{
count++;
}
@ -289,7 +289,7 @@ static AActor *SelectTeleDest (int tid, int tag, bool norandom)
while (count > 0)
{
searcher = iterator.Next ();
if (tag == 0 || searcher->Sector->HasTag(tag))
if (tag == 0 || tagManager.SectorHasTag(searcher->Sector, tag))
{
count--;
}

View file

@ -46,6 +46,7 @@
#include "r_state.h"
#include "r_data/colormaps.h"
#include "w_wad.h"
#include "p_tags.h"
//===========================================================================
//
@ -1269,6 +1270,7 @@ public:
int desaturation = -1;
int fplaneflags = 0, cplaneflags = 0;
double fp[4] = { 0 }, cp[4] = { 0 };
FString tagstring;
memset(sec, 0, sizeof(*sec));
sec->lightlevel = 160;
@ -1332,7 +1334,7 @@ public:
continue;
case NAME_Id:
sec->SetMainTag((short)CheckInt(key));
tagManager.AddSectorTag(index, CheckInt(key));
continue;
default:
@ -1510,28 +1512,32 @@ public:
cp[3] = CheckFloat(key);
break;
case NAME_MoreIds:
// delay parsing of the tag string until parsing of the sector is complete
// This ensures that the ID is always the first tag in the list.
tagstring = CheckString(key);
break;
default:
break;
}
#if 0 // for later
if (namespace_bits & (Zd)) && !strnicmp(key.GetChars(), "Id", 2))
{
char *endp;
int num = strtol(key.GetChars(), &endp, 10);
if (num > 0 && *endp == NULL)
{
// only allow ID## with ## as a proper number
sec->SetTag((short)CheckInt(key), false);
}
}
#endif
if ((namespace_bits & (Zd | Zdt)) && !strnicmp("user_", key.GetChars(), 5))
{
AddUserKey(key, UDMF_Sector, index);
}
}
if (tagstring.IsNotEmpty())
{
FScanner sc;
sc.OpenMem("tagstring", tagstring.GetChars(), tagstring.Len());
// scan the string as long as valid numbers can be found
while (sc.CheckNumber())
{
if (sc.Number != 0) tagManager.AddSectorTag(index, sc.Number);
}
}
sec->secretsector = !!(sec->special&SECRET_MASK);
// Reset the planes to their defaults if not all of the plane equation's parameters were found.

View file

@ -262,7 +262,7 @@ static int WriteSECTORS (FILE *file)
uppercopy (ms.ceilingpic, GetTextureName (sectors[i].GetTexture(sector_t::ceiling)));
ms.lightlevel = LittleShort((short)sectors[i].lightlevel);
ms.special = LittleShort(sectors[i].special);
ms.tag = LittleShort(sectors[i].GetMainTag());
ms.tag = LittleShort(tagManager.GetFirstSectorTag(&sectors[i]));
fwrite (&ms, sizeof(ms), 1, file);
}
return numsectors * sizeof(ms);

View file

@ -307,7 +307,7 @@ void P_TranslateTeleportThings ()
while ( (dest = iterator.Next()) )
{
if (!dest->Sector->HasTags())
if (!tagManager.SectorHasTags(dest->Sector))
{
dest->tid = 1;
dest->AddToHash ();

View file

@ -633,12 +633,6 @@ struct sector_t
return pos == floor? floorplane:ceilingplane;
}
bool HasTag(int checktag) const;
bool HasTags() const;
void SetMainTag(int tagnum);
int GetMainTag() const;
void ClearTags();
static void HashTags();
bool PlaneMoving(int pos);
@ -657,12 +651,9 @@ struct sector_t
TObjPtr<AActor> SoundTarget;
short special;
short tag;
short lightlevel;
short seqType; // this sector's sound sequence
int nexttag,firsttag; // killough 1/30/98: improves searches for tags.
int sky;
FNameNoInit SeqName; // Sound sequence name. Setting seqType non-negative will override this.

View file

@ -76,7 +76,7 @@ const char *GetVersionString();
// Use 4500 as the base git save version, since it's higher than the
// SVN revision ever got.
#define SAVEVER 4522
#define SAVEVER 4523
#define SAVEVERSTRINGIFY2(x) #x
#define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)