mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-11-15 16:51:31 +00:00
- set editor numbers through MAPINFO. The DECORATE way still works ans will override any definition made in MAPINFO.
- use a standard TMap for finding editor numbers
This commit is contained in:
parent
463d495b80
commit
15dbbc9137
7 changed files with 235 additions and 173 deletions
|
@ -2440,6 +2440,7 @@ void D_DoomMain (void)
|
|||
// Create replacements for dehacked pickups
|
||||
FinishDehPatch();
|
||||
|
||||
InitActorNumsFromMapinfo();
|
||||
FActorInfo::StaticSetActorNums ();
|
||||
|
||||
//Added by MC:
|
||||
|
|
|
@ -34,20 +34,34 @@
|
|||
*/
|
||||
|
||||
#include "info.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "m_fixed.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "d_net.h"
|
||||
#include "v_text.h"
|
||||
|
||||
#include "gi.h"
|
||||
|
||||
#include "actor.h"
|
||||
#include "r_state.h"
|
||||
#include "i_system.h"
|
||||
#include "p_local.h"
|
||||
#include "templates.h"
|
||||
#include "cmdlib.h"
|
||||
#include "g_level.h"
|
||||
#include "v_text.h"
|
||||
#include "i_system.h"
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Stuff that's only valid during definition time
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct MapinfoEdMapItem
|
||||
{
|
||||
FName classname; // DECORATE is read after MAPINFO so we do not have the actual classes available here yet.
|
||||
int special;
|
||||
int args[5];
|
||||
// These are for error reporting. We must store the file information because it's no longer available when these items get resolved.
|
||||
FString filename;
|
||||
int linenum;
|
||||
};
|
||||
|
||||
typedef TMap<int, MapinfoEdMapItem> IdMap;
|
||||
|
||||
static IdMap DoomEdFromMapinfo;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -56,108 +70,20 @@
|
|||
|
||||
FDoomEdMap DoomEdMap;
|
||||
|
||||
FDoomEdMap::FDoomEdEntry *FDoomEdMap::DoomEdHash[DOOMED_HASHSIZE];
|
||||
|
||||
FDoomEdMap::~FDoomEdMap()
|
||||
{
|
||||
Empty();
|
||||
}
|
||||
|
||||
void FDoomEdMap::AddType (int doomednum, const PClass *type, bool temporary)
|
||||
{
|
||||
unsigned int hash = (unsigned int)doomednum % DOOMED_HASHSIZE;
|
||||
FDoomEdEntry *entry = DoomEdHash[hash];
|
||||
while (entry && entry->DoomEdNum != doomednum)
|
||||
{
|
||||
entry = entry->HashNext;
|
||||
}
|
||||
if (entry == NULL)
|
||||
{
|
||||
entry = new FDoomEdEntry;
|
||||
entry->HashNext = DoomEdHash[hash];
|
||||
entry->DoomEdNum = doomednum;
|
||||
DoomEdHash[hash] = entry;
|
||||
}
|
||||
else if (!entry->temp)
|
||||
{
|
||||
Printf (PRINT_BOLD, "Warning: %s and %s both have doomednum %d.\n",
|
||||
type->TypeName.GetChars(), entry->Type->TypeName.GetChars(), doomednum);
|
||||
}
|
||||
entry->temp = temporary;
|
||||
entry->Type = type;
|
||||
}
|
||||
|
||||
void FDoomEdMap::DelType (int doomednum)
|
||||
{
|
||||
unsigned int hash = (unsigned int)doomednum % DOOMED_HASHSIZE;
|
||||
FDoomEdEntry **prev = &DoomEdHash[hash];
|
||||
FDoomEdEntry *entry = *prev;
|
||||
while (entry && entry->DoomEdNum != doomednum)
|
||||
{
|
||||
prev = &entry->HashNext;
|
||||
entry = entry->HashNext;
|
||||
}
|
||||
if (entry != NULL)
|
||||
{
|
||||
*prev = entry->HashNext;
|
||||
delete entry;
|
||||
}
|
||||
}
|
||||
|
||||
void FDoomEdMap::Empty ()
|
||||
{
|
||||
int bucket;
|
||||
|
||||
for (bucket = 0; bucket < DOOMED_HASHSIZE; ++bucket)
|
||||
{
|
||||
FDoomEdEntry *probe = DoomEdHash[bucket];
|
||||
|
||||
while (probe != NULL)
|
||||
{
|
||||
FDoomEdEntry *next = probe->HashNext;
|
||||
delete probe;
|
||||
probe = next;
|
||||
}
|
||||
DoomEdHash[bucket] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const PClass *FDoomEdMap::FindType (int doomednum) const
|
||||
{
|
||||
unsigned int hash = (unsigned int)doomednum % DOOMED_HASHSIZE;
|
||||
FDoomEdEntry *entry = DoomEdHash[hash];
|
||||
while (entry && entry->DoomEdNum != doomednum)
|
||||
entry = entry->HashNext;
|
||||
return entry ? entry->Type : NULL;
|
||||
}
|
||||
|
||||
struct EdSorting
|
||||
{
|
||||
const PClass *Type;
|
||||
int DoomEdNum;
|
||||
};
|
||||
|
||||
static int STACK_ARGS sortnums (const void *a, const void *b)
|
||||
{
|
||||
return ((const EdSorting *)a)->DoomEdNum -
|
||||
((const EdSorting *)b)->DoomEdNum;
|
||||
return (*(const FDoomEdMap::Pair**)a)->Key - (*(const FDoomEdMap::Pair**)b)->Key;
|
||||
}
|
||||
|
||||
void FDoomEdMap::DumpMapThings ()
|
||||
CCMD (dumpmapthings)
|
||||
{
|
||||
TArray<EdSorting> infos (PClass::m_Types.Size());
|
||||
int i;
|
||||
TArray<FDoomEdMap::Pair*> infos(DoomEdMap.CountUsed());
|
||||
FDoomEdMap::Iterator it(DoomEdMap);
|
||||
FDoomEdMap::Pair *pair;
|
||||
|
||||
for (i = 0; i < DOOMED_HASHSIZE; ++i)
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
FDoomEdEntry *probe = DoomEdHash[i];
|
||||
|
||||
while (probe != NULL)
|
||||
{
|
||||
EdSorting sorting = { probe->Type, probe->DoomEdNum };
|
||||
infos.Push (sorting);
|
||||
probe = probe->HashNext;
|
||||
}
|
||||
infos.Push(pair);
|
||||
}
|
||||
|
||||
if (infos.Size () == 0)
|
||||
|
@ -166,17 +92,145 @@ void FDoomEdMap::DumpMapThings ()
|
|||
}
|
||||
else
|
||||
{
|
||||
qsort (&infos[0], infos.Size (), sizeof(EdSorting), sortnums);
|
||||
qsort (&infos[0], infos.Size (), sizeof(FDoomEdMap::Pair*), sortnums);
|
||||
|
||||
for (i = 0; i < (int)infos.Size (); ++i)
|
||||
for (unsigned i = 0; i < infos.Size (); ++i)
|
||||
{
|
||||
Printf ("%6d %s\n",
|
||||
infos[i].DoomEdNum, infos[i].Type->TypeName.GetChars());
|
||||
infos[i]->Key, infos[i]->Value.Type->TypeName.GetChars());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (dumpmapthings)
|
||||
|
||||
void FMapInfoParser::ParseDoomEdNums()
|
||||
{
|
||||
FDoomEdMap::DumpMapThings ();
|
||||
TMap<int, bool> defined;
|
||||
int error = 0;
|
||||
|
||||
MapinfoEdMapItem editem;
|
||||
|
||||
editem.filename = sc.ScriptName;
|
||||
|
||||
sc.MustGetStringName("{");
|
||||
while (true)
|
||||
{
|
||||
if (sc.CheckString("}")) return;
|
||||
else if (sc.CheckNumber())
|
||||
{
|
||||
int ednum = sc.Number;
|
||||
sc.MustGetStringName("=");
|
||||
sc.MustGetString();
|
||||
|
||||
bool *def = defined.CheckKey(ednum);
|
||||
if (def != NULL)
|
||||
{
|
||||
sc.ScriptMessage("Editor Number %d defined more than once", ednum);
|
||||
error++;
|
||||
}
|
||||
defined[ednum] = true;
|
||||
if (sc.String[0] == '$')
|
||||
{
|
||||
// todo: add special stuff like playerstarts and sound sequence overrides here, too.
|
||||
editem.classname = NAME_None;
|
||||
editem.special = 1; // todo: assign proper constants
|
||||
}
|
||||
else
|
||||
{
|
||||
editem.classname = sc.String;
|
||||
editem.special = -1;
|
||||
}
|
||||
memset(editem.args, 0, sizeof(editem.args));
|
||||
|
||||
int minargs = 0;
|
||||
int maxargs = 5;
|
||||
FString specialname;
|
||||
if (sc.CheckString(","))
|
||||
{
|
||||
// todo: parse a special or args
|
||||
editem.special = 0; // mark args as used - if this is done we need to prevent assignment of map args in P_SpawnMapThing.
|
||||
if (!sc.CheckNumber())
|
||||
{
|
||||
sc.MustGetString();
|
||||
specialname = sc.String; // save for later error reporting.
|
||||
editem.special = P_FindLineSpecial(sc.String, &minargs, &maxargs);
|
||||
if (editem.special == 0 || minargs == -1)
|
||||
{
|
||||
sc.ScriptMessage("Invalid special %s for Editor Number %d", sc.String, ednum);
|
||||
error++;
|
||||
minargs = 0;
|
||||
maxargs = 5;
|
||||
}
|
||||
if (!sc.CheckString(","))
|
||||
{
|
||||
// special case: Special without arguments
|
||||
if (minargs != 0)
|
||||
{
|
||||
sc.ScriptMessage("Incorrect number of args for special %s, min = %d, max = %d, found = 0", specialname.GetChars(), minargs, maxargs);
|
||||
error++;
|
||||
}
|
||||
DoomEdFromMapinfo.Insert(ednum, editem);
|
||||
continue;
|
||||
}
|
||||
sc.MustGetStringName(",");
|
||||
sc.MustGetNumber();
|
||||
}
|
||||
int i = 0;
|
||||
while (i < 5)
|
||||
{
|
||||
editem.args[i++] = sc.Number;
|
||||
i++;
|
||||
if (!sc.CheckString(",")) break;
|
||||
sc.MustGetNumber();
|
||||
}
|
||||
if (specialname.IsNotEmpty() && (i < minargs || i > maxargs))
|
||||
{
|
||||
sc.ScriptMessage("Incorrect number of args for special %s, min = %d, max = %d, found = %d", specialname.GetChars(), minargs, maxargs, i);
|
||||
error++;
|
||||
}
|
||||
}
|
||||
DoomEdFromMapinfo.Insert(ednum, editem);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.ScriptError("Number expected");
|
||||
}
|
||||
}
|
||||
if (error > 0)
|
||||
{
|
||||
sc.ScriptError("%d errors encountered in DoomEdNum definition");
|
||||
}
|
||||
}
|
||||
|
||||
void InitActorNumsFromMapinfo()
|
||||
{
|
||||
DoomEdMap.Clear();
|
||||
IdMap::Iterator it(DoomEdFromMapinfo);
|
||||
IdMap::Pair *pair;
|
||||
int error = 0;
|
||||
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
const PClass *cls = NULL;
|
||||
if (pair->Value.classname != NAME_None)
|
||||
{
|
||||
cls = PClass::FindClass(pair->Value.classname);
|
||||
if (cls == NULL)
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "Script error, \"%s\" line %d:\nUnknown actor class %s\n",
|
||||
pair->Value.filename.GetChars(), pair->Value.linenum, pair->Value.classname.GetChars());
|
||||
error++;
|
||||
}
|
||||
}
|
||||
FDoomEdEntry ent;
|
||||
ent.Type = cls;
|
||||
ent.Special = pair->Value.special;
|
||||
memcpy(ent.Args, pair->Value.args, sizeof(ent.Args));
|
||||
DoomEdMap.Insert(pair->Key, ent);
|
||||
}
|
||||
if (error > 0)
|
||||
{
|
||||
I_Error("%d unknown actor classes found", error);
|
||||
}
|
||||
DoomEdFromMapinfo.Clear(); // we do not need this any longer
|
||||
}
|
||||
|
|
|
@ -104,6 +104,7 @@ struct FMapInfoParser
|
|||
|
||||
void ParseIntermissionAction(FIntermissionDescriptor *Desc);
|
||||
void ParseIntermission();
|
||||
void ParseDoomEdNums();
|
||||
void ParseAMColors(bool);
|
||||
FName CheckEndSequence();
|
||||
FName ParseEndGame();
|
||||
|
|
|
@ -1876,6 +1876,18 @@ void FMapInfoParser::ParseMapInfo (int lump, level_info_t &gamedefaults, level_i
|
|||
sc.ScriptError("intermission definitions not supported with old MAPINFO syntax");
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("doomednums"))
|
||||
{
|
||||
if (format_type != FMT_Old)
|
||||
{
|
||||
format_type = FMT_New;
|
||||
ParseDoomEdNums();
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.ScriptError("doomednums definitions not supported with old MAPINFO syntax");
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("automap") || sc.Compare("automap_overlay"))
|
||||
{
|
||||
if (format_type != FMT_Old)
|
||||
|
|
21
src/info.cpp
21
src/info.cpp
|
@ -142,7 +142,6 @@ void FActorInfo::StaticInit ()
|
|||
void FActorInfo::StaticSetActorNums ()
|
||||
{
|
||||
SpawnableThings.Clear();
|
||||
DoomEdMap.Empty ();
|
||||
|
||||
for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i)
|
||||
{
|
||||
|
@ -171,7 +170,16 @@ void FActorInfo::RegisterIDs ()
|
|||
}
|
||||
if (DoomEdNum != -1)
|
||||
{
|
||||
DoomEdMap.AddType (DoomEdNum, cls);
|
||||
FDoomEdEntry *oldent = DoomEdMap.CheckKey(DoomEdNum);
|
||||
if (oldent != NULL && oldent->Special == -2)
|
||||
{
|
||||
Printf(TEXTCOLOR_RED"Editor number %d defined twice for classes '%s' and '%s'\n", DoomEdNum, cls->TypeName.GetChars(), oldent->Type->TypeName.GetChars());
|
||||
}
|
||||
FDoomEdEntry ent;
|
||||
memset(&ent, 0, sizeof(ent));
|
||||
ent.Type = cls;
|
||||
ent.Special = -2; // use -2 instead of -1 so that we can recognize DECORATE defined entries and print a warning message if duplicates occur.
|
||||
DoomEdMap.Insert(DoomEdNum, ent);
|
||||
if (cls != Class)
|
||||
{
|
||||
Printf(TEXTCOLOR_RED"Editor number %d refers to hidden class type '%s'\n", DoomEdNum, cls->TypeName.GetChars());
|
||||
|
@ -179,15 +187,6 @@ void FActorInfo::RegisterIDs ()
|
|||
}
|
||||
}
|
||||
// Fill out the list for Chex Quest with Doom's actors
|
||||
if (gameinfo.gametype == GAME_Chex && DoomEdMap.FindType(DoomEdNum) == NULL &&
|
||||
(GameFilter & GAME_Doom))
|
||||
{
|
||||
DoomEdMap.AddType (DoomEdNum, Class, true);
|
||||
if (cls != Class)
|
||||
{
|
||||
Printf(TEXTCOLOR_RED"Editor number %d refers to hidden class type '%s'\n", DoomEdNum, cls->TypeName.GetChars());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
32
src/info.h
32
src/info.h
|
@ -278,34 +278,20 @@ struct FActorInfo
|
|||
TArray<const PClass *> ForbiddenToPlayerClass;
|
||||
};
|
||||
|
||||
class FDoomEdMap
|
||||
struct FDoomEdEntry
|
||||
{
|
||||
public:
|
||||
~FDoomEdMap();
|
||||
|
||||
const PClass *FindType (int doomednum) const;
|
||||
void AddType (int doomednum, const PClass *type, bool temporary = false);
|
||||
void DelType (int doomednum);
|
||||
void Empty ();
|
||||
|
||||
static void DumpMapThings ();
|
||||
|
||||
private:
|
||||
enum { DOOMED_HASHSIZE = 256 };
|
||||
|
||||
struct FDoomEdEntry
|
||||
{
|
||||
FDoomEdEntry *HashNext;
|
||||
const PClass *Type;
|
||||
int DoomEdNum;
|
||||
bool temp;
|
||||
};
|
||||
|
||||
static FDoomEdEntry *DoomEdHash[DOOMED_HASHSIZE];
|
||||
const PClass *Type;
|
||||
int Special;
|
||||
int Args[5];
|
||||
};
|
||||
|
||||
typedef TMap<int, FDoomEdEntry> FDoomEdMap;
|
||||
|
||||
extern FDoomEdMap DoomEdMap;
|
||||
|
||||
void InitActorNumsFromMapinfo();
|
||||
|
||||
|
||||
int GetSpriteIndex(const char * spritename, bool add = true);
|
||||
TArray<FName> &MakeStateNameList(const char * fname);
|
||||
void AddStateLight(FState *state, const char *lname);
|
||||
|
|
|
@ -4600,6 +4600,28 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
|
|||
if (mthing->type == 0 || mthing->type == -1)
|
||||
return NULL;
|
||||
|
||||
// find which type to spawn
|
||||
FDoomEdEntry *mentry = DoomEdMap.CheckKey(mthing->type);
|
||||
|
||||
if (mentry == NULL)
|
||||
{
|
||||
// [RH] Don't die if the map tries to spawn an unknown thing
|
||||
Printf ("Unknown type %i at (%i, %i)\n",
|
||||
mthing->type,
|
||||
mthing->x>>FRACBITS, mthing->y>>FRACBITS);
|
||||
mentry = DoomEdMap.CheckKey(0);
|
||||
if (mentry == NULL) // we need a valid entry for the rest of this function so if we can't find a default, let's exit right away.
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (mentry->Type == NULL && mentry->Special <= 0)
|
||||
{
|
||||
// has been explicitly set to not spawning anything.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// count deathmatch start positions
|
||||
if (mthing->type == 11)
|
||||
{
|
||||
|
@ -4776,39 +4798,25 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
|
|||
mthing->args[0] = mthing->type - 14100;
|
||||
mthing->type = 14165;
|
||||
}
|
||||
// find which type to spawn
|
||||
i = DoomEdMap.FindType (mthing->type);
|
||||
|
||||
if (i == NULL)
|
||||
{
|
||||
// [RH] Don't die if the map tries to spawn an unknown thing
|
||||
Printf ("Unknown type %i at (%i, %i)\n",
|
||||
mthing->type,
|
||||
mthing->x>>FRACBITS, mthing->y>>FRACBITS);
|
||||
i = PClass::FindClass("Unknown");
|
||||
}
|
||||
// [RH] If the thing's corresponding sprite has no frames, also map
|
||||
// it to the unknown thing.
|
||||
else
|
||||
// Handle decorate replacements explicitly here
|
||||
// to check for missing frames in the replacement object.
|
||||
i = mentry->Type->GetReplacement();
|
||||
|
||||
const AActor *defaults = GetDefaultByType (i);
|
||||
if (defaults->SpawnState == NULL ||
|
||||
sprites[defaults->SpawnState->sprite].numframes == 0)
|
||||
{
|
||||
// Handle decorate replacements explicitly here
|
||||
// to check for missing frames in the replacement object.
|
||||
i = i->GetReplacement();
|
||||
// We don't load mods for shareware games so we'll just ignore
|
||||
// missing actors. Heretic needs this since the shareware includes
|
||||
// the retail weapons in Deathmatch.
|
||||
if (gameinfo.flags & GI_SHAREWARE)
|
||||
return NULL;
|
||||
|
||||
const AActor *defaults = GetDefaultByType (i);
|
||||
if (defaults->SpawnState == NULL ||
|
||||
sprites[defaults->SpawnState->sprite].numframes == 0)
|
||||
{
|
||||
// We don't load mods for shareware games so we'll just ignore
|
||||
// missing actors. Heretic needs this since the shareware includes
|
||||
// the retail weapons in Deathmatch.
|
||||
if (gameinfo.flags & GI_SHAREWARE)
|
||||
return NULL;
|
||||
|
||||
Printf ("%s at (%i, %i) has no frames\n",
|
||||
i->TypeName.GetChars(), mthing->x>>FRACBITS, mthing->y>>FRACBITS);
|
||||
i = PClass::FindClass("Unknown");
|
||||
}
|
||||
Printf ("%s at (%i, %i) has no frames\n",
|
||||
i->TypeName.GetChars(), mthing->x>>FRACBITS, mthing->y>>FRACBITS);
|
||||
i = PClass::FindClass("Unknown");
|
||||
}
|
||||
|
||||
const AActor *info = GetDefaultByType (i);
|
||||
|
@ -4898,7 +4906,8 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
|
|||
P_FindFloorCeiling(mobj, FFCF_SAMESECTOR | FFCF_ONLY3DFLOORS | FFCF_3DRESTRICT);
|
||||
}
|
||||
|
||||
if (!(mobj->flags2 & MF2_ARGSDEFINED))
|
||||
// if the actor got args defined either in DECORATE or MAPINFO we must ignore the map's properties.
|
||||
if (!(mobj->flags2 & MF2_ARGSDEFINED) && (mentry == NULL || mentry->Special < 0))
|
||||
{
|
||||
// [RH] Set the thing's special
|
||||
mobj->special = mthing->special;
|
||||
|
|
Loading…
Reference in a new issue